diff options
Diffstat (limited to 'drivers/gpu')
144 files changed, 5724 insertions, 3080 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 96eddd1..305c590 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -66,6 +66,8 @@ config DRM_RADEON If M is selected, the module will be called radeon. +source "drivers/gpu/drm/radeon/Kconfig" + config DRM_I810 tristate "Intel I810" depends on DRM && AGP && AGP_INTEL diff --git a/drivers/gpu/drm/ati_pcigart.c b/drivers/gpu/drm/ati_pcigart.c index 628eae3..17be051 100644 --- a/drivers/gpu/drm/ati_pcigart.c +++ b/drivers/gpu/drm/ati_pcigart.c @@ -39,8 +39,7 @@ static 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, - gart_info->table_mask); + PAGE_SIZE); if (gart_info->table_handle == NULL) return -ENOMEM; @@ -112,6 +111,13 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); + if (pci_set_dma_mask(dev->pdev, gart_info->table_mask)) { + DRM_ERROR("fail to set dma mask to 0x%Lx\n", + (unsigned long long)gart_info->table_mask); + ret = 1; + goto done; + } + ret = drm_ati_alloc_pcigart_table(dev, gart_info); if (ret) { DRM_ERROR("cannot allocate PCI GART page!\n"); diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 3d09e30..8417cc4 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -326,7 +326,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, * As we're limiting the address to 2^32-1 (or less), * casting it down to 32 bits is no problem, but we * need to point to a 64bit variable first. */ - dmah = drm_pci_alloc(dev, map->size, map->size, 0xffffffffUL); + dmah = drm_pci_alloc(dev, map->size, map->size); if (!dmah) { kfree(map); return -ENOMEM; @@ -885,7 +885,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) while (entry->buf_count < count) { - dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000, 0xfffffffful); + dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000); if (!dmah) { /* Set count correctly so we free the proper amount. */ diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5124401..d91fb8c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -158,6 +158,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A", 0 }, { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B", 0 }, { DRM_MODE_CONNECTOR_TV, "TV", 0 }, + { DRM_MODE_CONNECTOR_eDP, "Embedded DisplayPort", 0 }, }; static struct drm_prop_enum_list drm_encoder_enum_list[] = diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 4231d6d..7d0f00a 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -216,7 +216,7 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc) EXPORT_SYMBOL(drm_helper_crtc_in_use); /** - * drm_disable_unused_functions - disable unused objects + * drm_helper_disable_unused_functions - disable unused objects * @dev: DRM device * * LOCKING: @@ -702,7 +702,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, if (encoder->crtc != crtc) continue; - DRM_INFO("%s: set mode %s %x\n", drm_get_encoder_name(encoder), + DRM_DEBUG("%s: set mode %s %x\n", drm_get_encoder_name(encoder), mode->name, mode->base.id); encoder_funcs = encoder->helper_private; encoder_funcs->mode_set(encoder, mode, adjusted_mode); @@ -1032,7 +1032,8 @@ bool drm_helper_initial_config(struct drm_device *dev) /* * we shouldn't end up with no modes here. */ - WARN(!count, "No connectors reported connected with modes\n"); + if (count == 0) + printk(KERN_INFO "No connectors reported connected with modes\n"); drm_setup_crtcs(dev); @@ -1162,6 +1163,9 @@ EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); int drm_helper_resume_force_mode(struct drm_device *dev) { struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_crtc_helper_funcs *crtc_funcs; int ret; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -1174,6 +1178,25 @@ int drm_helper_resume_force_mode(struct drm_device *dev) if (ret == false) DRM_ERROR("failed to set mode on crtc %p\n", crtc); + + /* Turn off outputs that were already powered off */ + if (drm_helper_choose_crtc_dpms(crtc)) { + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + + if(encoder->crtc != crtc) + continue; + + encoder_funcs = encoder->helper_private; + if (encoder_funcs->dpms) + (*encoder_funcs->dpms) (encoder, + drm_helper_choose_encoder_dpms(encoder)); + + crtc_funcs = crtc->helper_private; + if (crtc_funcs->dpms) + (*crtc_funcs->dpms) (crtc, + drm_helper_choose_crtc_dpms(crtc)); + } + } } /* disable the unused connectors while restoring the modesetting */ drm_helper_disable_unused_functions(dev); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5c9f798..ab6c973 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -598,6 +598,50 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev, return mode; } +/* + * EDID is delightfully ambiguous about how interlaced modes are to be + * encoded. Our internal representation is of frame height, but some + * HDTV detailed timings are encoded as field height. + * + * The format list here is from CEA, in frame size. Technically we + * should be checking refresh rate too. Whatever. + */ +static void +drm_mode_do_interlace_quirk(struct drm_display_mode *mode, + struct detailed_pixel_timing *pt) +{ + int i; + static const struct { + int w, h; + } cea_interlaced[] = { + { 1920, 1080 }, + { 720, 480 }, + { 1440, 480 }, + { 2880, 480 }, + { 720, 576 }, + { 1440, 576 }, + { 2880, 576 }, + }; + static const int n_sizes = + sizeof(cea_interlaced)/sizeof(cea_interlaced[0]); + + if (!(pt->misc & DRM_EDID_PT_INTERLACED)) + return; + + for (i = 0; i < n_sizes; i++) { + if ((mode->hdisplay == cea_interlaced[i].w) && + (mode->vdisplay == cea_interlaced[i].h / 2)) { + mode->vdisplay *= 2; + mode->vsync_start *= 2; + mode->vsync_end *= 2; + mode->vtotal *= 2; + mode->vtotal |= 1; + } + } + + mode->flags |= DRM_MODE_FLAG_INTERLACE; +} + /** * drm_mode_detailed - create a new mode from an EDID detailed timing section * @dev: DRM device (needed to create new mode) @@ -633,8 +677,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, return NULL; } if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) { - printk(KERN_WARNING "integrated sync not supported\n"); - return NULL; + printk(KERN_WARNING "composite sync not supported\n"); } /* it is incorrect if hsync/vsync width is zero */ @@ -681,8 +724,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, drm_mode_set_name(mode); - if (pt->misc & DRM_EDID_PT_INTERLACED) - mode->flags |= DRM_MODE_FLAG_INTERLACE; + drm_mode_do_interlace_quirk(mode, pt); if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE; @@ -911,23 +953,27 @@ static int drm_cvt_modes(struct drm_connector *connector, struct drm_device *dev = connector->dev; struct cvt_timing *cvt; const int rates[] = { 60, 85, 75, 60, 50 }; + const u8 empty[3] = { 0, 0, 0 }; for (i = 0; i < 4; i++) { int uninitialized_var(width), height; cvt = &(timing->data.other_data.data.cvt[i]); - height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 8) + 1) * 2; - switch (cvt->code[1] & 0xc0) { + if (!memcmp(cvt->code, empty, 3)) + continue; + + height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 4) + 1) * 2; + switch (cvt->code[1] & 0x0c) { case 0x00: width = height * 4 / 3; break; - case 0x40: + case 0x04: width = height * 16 / 9; break; - case 0x80: + case 0x08: width = height * 16 / 10; break; - case 0xc0: + case 0x0c: width = height * 15 / 9; break; } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 1b49fa0..0f9e9055 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -156,7 +156,7 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *con force = DRM_FORCE_ON; break; case 'D': - if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) || + if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) && (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB)) force = DRM_FORCE_ON; else @@ -389,7 +389,7 @@ int drm_fb_helper_blank(int blank, struct fb_info *info) break; /* Display: Off; HSync: On, VSync: On */ case FB_BLANK_NORMAL: - drm_fb_helper_off(info, DRM_MODE_DPMS_ON); + drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY); break; /* Display: Off; HSync: Off, VSync: On */ case FB_BLANK_HSYNC_SUSPEND: @@ -606,11 +606,10 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, 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"); + if (var->bits_per_pixel > fb->bits_per_pixel || var->xres > fb->width || var->yres > fb->height) { + DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb " + "object %dx%d-%d > %dx%d-%d\n", var->xres, var->yres, var->bits_per_pixel, + fb->width, fb->height, fb->bits_per_pixel); return -EINVAL; } diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index e9dbb48..8bf3770 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -142,19 +142,6 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) if (IS_ERR(obj->filp)) goto free; - /* Basically we want to disable the OOM killer and handle ENOMEM - * ourselves by sacrificing pages from cached buffers. - * XXX shmem_file_[gs]et_gfp_mask() - */ - mapping_set_gfp_mask(obj->filp->f_path.dentry->d_inode->i_mapping, - GFP_HIGHUSER | - __GFP_COLD | - __GFP_FS | - __GFP_RECLAIMABLE | - __GFP_NORETRY | - __GFP_NOWARN | - __GFP_NOMEMALLOC); - kref_init(&obj->refcount); kref_init(&obj->handlecount); obj->size = size; diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 7998ee6..b98384d 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -115,6 +115,7 @@ void drm_vblank_cleanup(struct drm_device *dev) dev->num_crtcs = 0; } +EXPORT_SYMBOL(drm_vblank_cleanup); int drm_vblank_init(struct drm_device *dev, int num_crtcs) { @@ -163,7 +164,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) } dev->vblank_disable_allowed = 0; - return 0; err: @@ -493,6 +493,9 @@ EXPORT_SYMBOL(drm_vblank_off); */ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) { + /* vblank is not initialized (IRQ not installed ?) */ + if (!dev->num_crtcs) + return; /* * To avoid all the problems that might happen if interrupts * were enabled/disabled around or between these calls, we just diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index cdec329..2ac074c8 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -405,7 +405,8 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm, wasted += alignment - tmp; } - if (entry->size >= size + wasted) { + if (entry->size >= size + wasted && + (entry->start + wasted + size) <= end) { if (!best_match) return entry; if (entry->size < best_size) { diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 6d81a02..76d6339 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1,9 +1,4 @@ /* - * The list_sort function is (presumably) licensed under the GPL (see the - * top level "COPYING" file for details). - * - * The remainder of this file is: - * * Copyright © 1997-2003 by The XFree86 Project, Inc. * Copyright © 2007 Dave Airlie * Copyright © 2007-2008 Intel Corporation @@ -36,6 +31,7 @@ */ #include <linux/list.h> +#include <linux/list_sort.h> #include "drmP.h" #include "drm.h" #include "drm_crtc.h" @@ -855,6 +851,7 @@ EXPORT_SYMBOL(drm_mode_prune_invalid); /** * drm_mode_compare - compare modes for favorability + * @priv: unused * @lh_a: list_head for first mode * @lh_b: list_head for second mode * @@ -868,7 +865,7 @@ EXPORT_SYMBOL(drm_mode_prune_invalid); * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or * positive if @lh_b is better than @lh_a. */ -static int drm_mode_compare(struct list_head *lh_a, struct list_head *lh_b) +static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head *lh_b) { struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head); struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head); @@ -885,85 +882,6 @@ static int drm_mode_compare(struct list_head *lh_a, struct list_head *lh_b) return diff; } -/* FIXME: what we don't have a list sort function? */ -/* list sort from Mark J Roberts (mjr@znex.org) */ -void list_sort(struct list_head *head, - int (*cmp)(struct list_head *a, struct list_head *b)) -{ - struct list_head *p, *q, *e, *list, *tail, *oldhead; - int insize, nmerges, psize, qsize, i; - - list = head->next; - list_del(head); - insize = 1; - for (;;) { - p = oldhead = list; - list = tail = NULL; - nmerges = 0; - - while (p) { - nmerges++; - q = p; - psize = 0; - for (i = 0; i < insize; i++) { - psize++; - q = q->next == oldhead ? NULL : q->next; - if (!q) - break; - } - - qsize = insize; - while (psize > 0 || (qsize > 0 && q)) { - if (!psize) { - e = q; - q = q->next; - qsize--; - if (q == oldhead) - q = NULL; - } else if (!qsize || !q) { - e = p; - p = p->next; - psize--; - if (p == oldhead) - p = NULL; - } else if (cmp(p, q) <= 0) { - e = p; - p = p->next; - psize--; - if (p == oldhead) - p = NULL; - } else { - e = q; - q = q->next; - qsize--; - if (q == oldhead) - q = NULL; - } - if (tail) - tail->next = e; - else - list = e; - e->prev = tail; - tail = e; - } - p = q; - } - - tail->next = list; - list->prev = tail; - - if (nmerges <= 1) - break; - - insize *= 2; - } - - head->next = list; - head->prev = list->prev; - list->prev->next = head; - list->prev = head; -} - /** * drm_mode_sort - sort mode list * @mode_list: list to sort @@ -975,7 +893,7 @@ void list_sort(struct list_head *head, */ void drm_mode_sort(struct list_head *mode_list) { - list_sort(mode_list, drm_mode_compare); + list_sort(NULL, mode_list, drm_mode_compare); } EXPORT_SYMBOL(drm_mode_sort); diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 577094f..e68ebf9 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -47,8 +47,7 @@ /** * \brief Allocate a PCI consistent memory block, for DMA. */ -drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align, - dma_addr_t maxaddr) +drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align) { drm_dma_handle_t *dmah; #if 1 @@ -63,11 +62,6 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali if (align > size) return NULL; - if (pci_set_dma_mask(dev->pdev, maxaddr) != 0) { - DRM_ERROR("Setting pci dma mask failed\n"); - return NULL; - } - dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL); if (!dmah) return NULL; diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 18476bf..a894ade 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -272,7 +272,7 @@ static void i915_dump_pages(struct seq_file *m, struct page **pages, int page_co mem = kmap_atomic(pages[page], KM_USER0); for (i = 0; i < PAGE_SIZE; i += 4) seq_printf(m, "%08x : %08x\n", i, mem[i / 4]); - kunmap_atomic(pages[page], KM_USER0); + kunmap_atomic(mem, KM_USER0); } } @@ -290,7 +290,7 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data) list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) { obj = obj_priv->obj; if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) { - ret = i915_gem_object_get_pages(obj); + ret = i915_gem_object_get_pages(obj, 0); if (ret) { DRM_ERROR("Failed to get pages: %d\n", ret); spin_unlock(&dev_priv->mm.active_list_lock); @@ -386,34 +386,6 @@ out: return 0; } -static int i915_registers_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_i915_private_t *dev_priv = dev->dev_private; - uint32_t reg; - -#define DUMP_RANGE(start, end) \ - for (reg=start; reg < end; reg += 4) \ - seq_printf(m, "%08x\t%08x\n", reg, I915_READ(reg)); - - DUMP_RANGE(0x00000, 0x00fff); /* VGA registers */ - DUMP_RANGE(0x02000, 0x02fff); /* instruction, memory, interrupt control registers */ - DUMP_RANGE(0x03000, 0x031ff); /* FENCE and PPGTT control registers */ - DUMP_RANGE(0x03200, 0x03fff); /* frame buffer compression registers */ - DUMP_RANGE(0x05000, 0x05fff); /* I/O control registers */ - DUMP_RANGE(0x06000, 0x06fff); /* clock control registers */ - DUMP_RANGE(0x07000, 0x07fff); /* 3D internal debug registers */ - DUMP_RANGE(0x07400, 0x088ff); /* GPE debug registers */ - DUMP_RANGE(0x0a000, 0x0afff); /* display palette registers */ - DUMP_RANGE(0x10000, 0x13fff); /* MMIO MCHBAR */ - DUMP_RANGE(0x30000, 0x3ffff); /* overlay registers */ - DUMP_RANGE(0x60000, 0x6ffff); /* display engine pipeline registers */ - DUMP_RANGE(0x70000, 0x72fff); /* display and cursor registers */ - DUMP_RANGE(0x73000, 0x73fff); /* performance counters */ - - return 0; -} - static int i915_wedged_open(struct inode *inode, struct file *filp) @@ -519,7 +491,6 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor) } static struct drm_info_list i915_debugfs_list[] = { - {"i915_regs", i915_registers_info, 0}, {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST}, {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST}, {"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST}, diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 701bfea..2307f98 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -123,7 +123,7 @@ static int i915_init_phys_hws(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; /* Program Hardware Status Page */ dev_priv->status_page_dmah = - drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); + drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE); if (!dev_priv->status_page_dmah) { DRM_ERROR("Can not allocate hardware status page\n"); @@ -134,6 +134,10 @@ static int i915_init_phys_hws(struct drm_device *dev) memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + if (IS_I965G(dev)) + dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) & + 0xf0; + I915_WRITE(HWS_PGA, dev_priv->dma_status_page); DRM_DEBUG_DRIVER("Enabled hardware status page\n"); return 0; @@ -731,8 +735,10 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, if (cmdbuf->num_cliprects) { cliprects = kcalloc(cmdbuf->num_cliprects, sizeof(struct drm_clip_rect), GFP_KERNEL); - if (cliprects == NULL) + if (cliprects == NULL) { + ret = -ENOMEM; goto fail_batch_free; + } ret = copy_from_user(cliprects, cmdbuf->cliprects, cmdbuf->num_cliprects * @@ -813,9 +819,13 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_PAGEFLIPPING: value = 1; break; + case I915_PARAM_HAS_EXECBUF2: + /* depends on GEM */ + value = dev_priv->has_gem; + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", - param->param); + param->param); return -EINVAL; } @@ -1117,7 +1127,8 @@ static void i915_setup_compression(struct drm_device *dev, int size) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_mm_node *compressed_fb, *compressed_llb; - unsigned long cfb_base, ll_base; + unsigned long cfb_base; + unsigned long ll_base = 0; /* Leave 1M for line length buffer & misc. */ compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0); @@ -1200,14 +1211,6 @@ static int i915_load_modeset_init(struct drm_device *dev, dev->mode_config.fb_base = drm_get_resource_start(dev, fb_bar) & 0xff000000; - if (IS_MOBILE(dev) || IS_I9XX(dev)) - dev_priv->cursor_needs_physical = true; - else - dev_priv->cursor_needs_physical = false; - - if (IS_I965G(dev) || IS_G33(dev)) - dev_priv->cursor_needs_physical = false; - /* Basic memrange allocator for stolen space (aka vram) */ drm_mm_init(&dev_priv->vram, 0, prealloc_size); DRM_INFO("set up %ldM of stolen space\n", prealloc_size / (1024*1024)); @@ -1257,6 +1260,8 @@ static int i915_load_modeset_init(struct drm_device *dev, if (ret) goto destroy_ringbuffer; + intel_modeset_init(dev); + ret = drm_irq_install(dev); if (ret) goto destroy_ringbuffer; @@ -1271,8 +1276,6 @@ static int i915_load_modeset_init(struct drm_device *dev, I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); - intel_modeset_init(dev); - drm_helper_initial_config(dev); return 0; @@ -1360,7 +1363,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) { struct drm_i915_private *dev_priv = dev->dev_private; resource_size_t base, size; - int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1; + int ret = 0, mmio_bar; uint32_t agp_size, prealloc_size, prealloc_start; /* i915 has 4 more counters */ @@ -1376,8 +1379,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev->dev_private = (void *)dev_priv; dev_priv->dev = dev; + dev_priv->info = (struct intel_device_info *) flags; /* Add register map (needed for suspend/resume) */ + mmio_bar = IS_I9XX(dev) ? 0 : 1; base = drm_get_resource_start(dev, mmio_bar); size = drm_get_resource_len(dev, mmio_bar); @@ -1652,6 +1657,7 @@ struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH), diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 24286ca..79beffc 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -33,7 +33,6 @@ #include "i915_drm.h" #include "i915_drv.h" -#include "drm_pciids.h" #include <linux/console.h> #include "drm_crtc_helper.h" @@ -46,88 +45,229 @@ module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); unsigned int i915_powersave = 1; module_param_named(powersave, i915_powersave, int, 0400); +unsigned int i915_lvds_downclock = 0; +module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); + static struct drm_driver driver; -static struct pci_device_id pciidlist[] = { - i915_PCI_IDS +#define INTEL_VGA_DEVICE(id, info) { \ + .class = PCI_CLASS_DISPLAY_VGA << 8, \ + .class_mask = 0xffff00, \ + .vendor = 0x8086, \ + .device = id, \ + .subvendor = PCI_ANY_ID, \ + .subdevice = PCI_ANY_ID, \ + .driver_data = (unsigned long) info } + +const static struct intel_device_info intel_i830_info = { + .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, +}; + +const static struct intel_device_info intel_845g_info = { + .is_i8xx = 1, +}; + +const static struct intel_device_info intel_i85x_info = { + .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, +}; + +const static struct intel_device_info intel_i865g_info = { + .is_i8xx = 1, +}; + +const static struct intel_device_info intel_i915g_info = { + .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1, +}; +const static struct intel_device_info intel_i915gm_info = { + .is_i9xx = 1, .is_mobile = 1, .has_fbc = 1, + .cursor_needs_physical = 1, +}; +const static struct intel_device_info intel_i945g_info = { + .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1, +}; +const static struct intel_device_info intel_i945gm_info = { + .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1, .has_fbc = 1, + .has_hotplug = 1, .cursor_needs_physical = 1, +}; + +const static struct intel_device_info intel_i965g_info = { + .is_i965g = 1, .is_i9xx = 1, .has_hotplug = 1, +}; + +const static struct intel_device_info intel_i965gm_info = { + .is_i965g = 1, .is_mobile = 1, .is_i965gm = 1, .is_i9xx = 1, + .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, + .has_hotplug = 1, +}; + +const static struct intel_device_info intel_g33_info = { + .is_g33 = 1, .is_i9xx = 1, .need_gfx_hws = 1, + .has_hotplug = 1, +}; + +const static struct intel_device_info intel_g45_info = { + .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .need_gfx_hws = 1, + .has_pipe_cxsr = 1, + .has_hotplug = 1, +}; + +const static struct intel_device_info intel_gm45_info = { + .is_i965g = 1, .is_mobile = 1, .is_g4x = 1, .is_i9xx = 1, + .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, + .has_pipe_cxsr = 1, + .has_hotplug = 1, +}; + +const static struct intel_device_info intel_pineview_info = { + .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1, + .need_gfx_hws = 1, + .has_hotplug = 1, +}; + +const static struct intel_device_info intel_ironlake_d_info = { + .is_ironlake = 1, .is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1, + .has_pipe_cxsr = 1, + .has_hotplug = 1, +}; + +const static struct intel_device_info intel_ironlake_m_info = { + .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1, + .need_gfx_hws = 1, .has_rc6 = 1, + .has_hotplug = 1, +}; + +const static struct pci_device_id pciidlist[] = { + INTEL_VGA_DEVICE(0x3577, &intel_i830_info), + INTEL_VGA_DEVICE(0x2562, &intel_845g_info), + INTEL_VGA_DEVICE(0x3582, &intel_i85x_info), + INTEL_VGA_DEVICE(0x35e8, &intel_i85x_info), + INTEL_VGA_DEVICE(0x2572, &intel_i865g_info), + INTEL_VGA_DEVICE(0x2582, &intel_i915g_info), + INTEL_VGA_DEVICE(0x258a, &intel_i915g_info), + INTEL_VGA_DEVICE(0x2592, &intel_i915gm_info), + INTEL_VGA_DEVICE(0x2772, &intel_i945g_info), + INTEL_VGA_DEVICE(0x27a2, &intel_i945gm_info), + INTEL_VGA_DEVICE(0x27ae, &intel_i945gm_info), + INTEL_VGA_DEVICE(0x2972, &intel_i965g_info), + INTEL_VGA_DEVICE(0x2982, &intel_i965g_info), + INTEL_VGA_DEVICE(0x2992, &intel_i965g_info), + INTEL_VGA_DEVICE(0x29a2, &intel_i965g_info), + INTEL_VGA_DEVICE(0x29b2, &intel_g33_info), + INTEL_VGA_DEVICE(0x29c2, &intel_g33_info), + INTEL_VGA_DEVICE(0x29d2, &intel_g33_info), + INTEL_VGA_DEVICE(0x2a02, &intel_i965gm_info), + INTEL_VGA_DEVICE(0x2a12, &intel_i965gm_info), + INTEL_VGA_DEVICE(0x2a42, &intel_gm45_info), + INTEL_VGA_DEVICE(0x2e02, &intel_g45_info), + INTEL_VGA_DEVICE(0x2e12, &intel_g45_info), + INTEL_VGA_DEVICE(0x2e22, &intel_g45_info), + INTEL_VGA_DEVICE(0x2e32, &intel_g45_info), + INTEL_VGA_DEVICE(0x2e42, &intel_g45_info), + INTEL_VGA_DEVICE(0xa001, &intel_pineview_info), + INTEL_VGA_DEVICE(0xa011, &intel_pineview_info), + INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info), + INTEL_VGA_DEVICE(0x0046, &intel_ironlake_m_info), + {0, 0, 0} }; #if defined(CONFIG_DRM_I915_KMS) MODULE_DEVICE_TABLE(pci, pciidlist); #endif -static int i915_suspend(struct drm_device *dev, pm_message_t state) +static int i915_drm_freeze(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!dev || !dev_priv) { - DRM_ERROR("dev: %p, dev_priv: %p\n", dev, dev_priv); - DRM_ERROR("DRM not initialized, aborting suspend.\n"); - return -ENODEV; - } - - if (state.event == PM_EVENT_PRETHAW) - return 0; - pci_save_state(dev->pdev); /* If KMS is active, we do the leavevt stuff here */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { - if (i915_gem_idle(dev)) + int error = i915_gem_idle(dev); + if (error) { dev_err(&dev->pdev->dev, - "GEM idle failed, resume may fail\n"); + "GEM idle failed, resume might fail\n"); + return error; + } drm_irq_uninstall(dev); } i915_save_state(dev); + return 0; +} + +static void i915_drm_suspend(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + intel_opregion_free(dev, 1); + /* Modeset on resume, not lid events */ + dev_priv->modeset_on_lid = 0; +} + +static int i915_suspend(struct drm_device *dev, pm_message_t state) +{ + int error; + + if (!dev || !dev->dev_private) { + DRM_ERROR("dev: %p\n", dev); + DRM_ERROR("DRM not initialized, aborting suspend.\n"); + return -ENODEV; + } + + if (state.event == PM_EVENT_PRETHAW) + return 0; + + error = i915_drm_freeze(dev); + if (error) + return error; + + i915_drm_suspend(dev); + if (state.event == PM_EVENT_SUSPEND) { /* Shut down the device */ pci_disable_device(dev->pdev); pci_set_power_state(dev->pdev, PCI_D3hot); } - /* Modeset on resume, not lid events */ - dev_priv->modeset_on_lid = 0; - return 0; } -static int i915_resume(struct drm_device *dev) +static int i915_drm_thaw(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int ret = 0; - - if (pci_enable_device(dev->pdev)) - return -1; - pci_set_master(dev->pdev); - - i915_restore_state(dev); - - intel_opregion_init(dev, 1); + int error = 0; /* KMS EnterVT equivalent */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { mutex_lock(&dev->struct_mutex); dev_priv->mm.suspended = 0; - ret = i915_gem_init_ringbuffer(dev); - if (ret != 0) - ret = -1; + error = i915_gem_init_ringbuffer(dev); mutex_unlock(&dev->struct_mutex); drm_irq_install(dev); - } - if (drm_core_check_feature(dev, DRIVER_MODESET)) { + /* Resume the modeset for every activated CRTC */ drm_helper_resume_force_mode(dev); } dev_priv->modeset_on_lid = 0; - return ret; + return error; +} + +static int i915_resume(struct drm_device *dev) +{ + if (pci_enable_device(dev->pdev)) + return -EIO; + + pci_set_master(dev->pdev); + + i915_restore_state(dev); + + intel_opregion_init(dev, 1); + + return i915_drm_thaw(dev); } /** @@ -268,22 +408,80 @@ i915_pci_remove(struct pci_dev *pdev) drm_put_dev(dev); } -static int -i915_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int i915_pm_suspend(struct device *dev) { - struct drm_device *dev = pci_get_drvdata(pdev); + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + int error; - return i915_suspend(dev, state); + if (!drm_dev || !drm_dev->dev_private) { + dev_err(dev, "DRM not initialized, aborting suspend.\n"); + return -ENODEV; + } + + error = i915_drm_freeze(drm_dev); + if (error) + return error; + + i915_drm_suspend(drm_dev); + + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; } -static int -i915_pci_resume(struct pci_dev *pdev) +static int i915_pm_resume(struct device *dev) { - struct drm_device *dev = pci_get_drvdata(pdev); + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + return i915_resume(drm_dev); +} + +static int i915_pm_freeze(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + if (!drm_dev || !drm_dev->dev_private) { + dev_err(dev, "DRM not initialized, aborting suspend.\n"); + return -ENODEV; + } - return i915_resume(dev); + return i915_drm_freeze(drm_dev); } +static int i915_pm_thaw(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + return i915_drm_thaw(drm_dev); +} + +static int i915_pm_poweroff(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + int error; + + error = i915_drm_freeze(drm_dev); + if (!error) + i915_drm_suspend(drm_dev); + + return error; +} + +const struct dev_pm_ops i915_pm_ops = { + .suspend = i915_pm_suspend, + .resume = i915_pm_resume, + .freeze = i915_pm_freeze, + .thaw = i915_pm_thaw, + .poweroff = i915_pm_poweroff, + .restore = i915_pm_resume, +}; + static struct vm_operations_struct i915_gem_vm_ops = { .fault = i915_gem_fault, .open = drm_gem_vm_open, @@ -303,8 +501,11 @@ static struct drm_driver driver = { .lastclose = i915_driver_lastclose, .preclose = i915_driver_preclose, .postclose = i915_driver_postclose, + + /* Used in place of i915_pm_ops for non-DRIVER_MODESET */ .suspend = i915_suspend, .resume = i915_resume, + .device_is_agp = i915_driver_device_is_agp, .enable_vblank = i915_enable_vblank, .disable_vblank = i915_disable_vblank, @@ -344,10 +545,7 @@ static struct drm_driver driver = { .id_table = pciidlist, .probe = i915_pci_probe, .remove = i915_pci_remove, -#ifdef CONFIG_PM - .resume = i915_pci_resume, - .suspend = i915_pci_suspend, -#endif + .driver.pm = &i915_pm_ops, }, .name = DRIVER_NAME, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fbecac7..b99b6a8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -172,9 +172,31 @@ struct drm_i915_display_funcs { struct intel_overlay; +struct intel_device_info { + u8 is_mobile : 1; + u8 is_i8xx : 1; + u8 is_i915g : 1; + u8 is_i9xx : 1; + u8 is_i945gm : 1; + u8 is_i965g : 1; + u8 is_i965gm : 1; + u8 is_g33 : 1; + u8 need_gfx_hws : 1; + u8 is_g4x : 1; + u8 is_pineview : 1; + u8 is_ironlake : 1; + u8 has_fbc : 1; + u8 has_rc6 : 1; + u8 has_pipe_cxsr : 1; + u8 has_hotplug : 1; + u8 cursor_needs_physical : 1; +}; + typedef struct drm_i915_private { struct drm_device *dev; + const struct intel_device_info *info; + int has_gem; void __iomem *regs; @@ -232,8 +254,6 @@ typedef struct drm_i915_private { int hangcheck_count; uint32_t last_acthd; - bool cursor_needs_physical; - struct drm_mm vram; unsigned long cfb_size; @@ -263,6 +283,7 @@ typedef struct drm_i915_private { unsigned int lvds_use_ssc:1; unsigned int edp_support:1; int lvds_ssc_freq; + int edp_bpp; struct notifier_block lid_notifier; @@ -287,8 +308,6 @@ typedef struct drm_i915_private { u32 saveDSPACNTR; u32 saveDSPBCNTR; u32 saveDSPARB; - u32 saveRENDERSTANDBY; - u32 savePWRCTXA; u32 saveHWS; u32 savePIPEACONF; u32 savePIPEBCONF; @@ -474,6 +493,15 @@ typedef struct drm_i915_private { struct list_head flushing_list; /** + * List of objects currently pending a GPU write flush. + * + * All elements on this list will belong to either the + * active_list or flushing_list, last_rendering_seqno can + * be used to differentiate between the two elements. + */ + struct list_head gpu_write_list; + + /** * LRU list of objects which are not in the ringbuffer and * are ready to unbind, but are still in the GTT. * @@ -561,6 +589,7 @@ typedef struct drm_i915_private { u16 orig_clock; int child_dev_num; struct child_device_config *child_dev; + struct drm_connector *int_lvds_connector; } drm_i915_private_t; /** driver private structure attached to each drm_gem_object */ @@ -572,6 +601,8 @@ struct drm_i915_gem_object { /** This object's place on the active/flushing/inactive lists */ struct list_head list; + /** This object's place on GPU write list */ + struct list_head gpu_write_list; /** This object's place on the fenced object LRU */ struct list_head fence_list; @@ -703,6 +734,7 @@ extern struct drm_ioctl_desc i915_ioctls[]; extern int i915_max_ioctl; extern unsigned int i915_fbpercrtc; extern unsigned int i915_powersave; +extern unsigned int i915_lvds_downclock; extern void i915_save_display(struct drm_device *dev); extern void i915_restore_display(struct drm_device *dev); @@ -794,6 +826,8 @@ int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv); +int i915_gem_execbuffer2(struct drm_device *dev, void *data, + struct drm_file *file_priv); int i915_gem_pin_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_unpin_ioctl(struct drm_device *dev, void *data, @@ -843,12 +877,13 @@ int i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptib int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write); +int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj); int i915_gem_attach_phys_object(struct drm_device *dev, struct drm_gem_object *obj, int id); void i915_gem_detach_phys_object(struct drm_device *dev, struct drm_gem_object *obj); void i915_gem_free_all_phys_object(struct drm_device *dev); -int i915_gem_object_get_pages(struct drm_gem_object *obj); +int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); void i915_gem_object_put_pages(struct drm_gem_object *obj); void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); void i915_gem_object_flush_write_domain(struct drm_gem_object *obj); @@ -860,6 +895,9 @@ void i915_gem_shrinker_exit(void); void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj); void i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj); +bool i915_tiling_ok(struct drm_device *dev, int stride, int size, + int tiling_mode); +bool i915_obj_fenceable(struct drm_device *dev, struct drm_gem_object *obj); /* i915_gem_debug.c */ void i915_gem_dump_object(struct drm_gem_object *obj, int len, @@ -982,67 +1020,33 @@ extern void g4x_disable_fbc(struct drm_device *dev); extern int i915_wrap_ring(struct drm_device * dev); extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); -#define IS_I830(dev) ((dev)->pci_device == 0x3577) -#define IS_845G(dev) ((dev)->pci_device == 0x2562) -#define IS_I85X(dev) ((dev)->pci_device == 0x3582) -#define IS_I865G(dev) ((dev)->pci_device == 0x2572) -#define IS_I8XX(dev) (IS_I830(dev) || IS_845G(dev) || IS_I85X(dev) || IS_I865G(dev)) - -#define IS_I915G(dev) ((dev)->pci_device == 0x2582 || (dev)->pci_device == 0x258a) -#define IS_I915GM(dev) ((dev)->pci_device == 0x2592) -#define IS_I945G(dev) ((dev)->pci_device == 0x2772) -#define IS_I945GM(dev) ((dev)->pci_device == 0x27A2 ||\ - (dev)->pci_device == 0x27AE) -#define IS_I965G(dev) ((dev)->pci_device == 0x2972 || \ - (dev)->pci_device == 0x2982 || \ - (dev)->pci_device == 0x2992 || \ - (dev)->pci_device == 0x29A2 || \ - (dev)->pci_device == 0x2A02 || \ - (dev)->pci_device == 0x2A12 || \ - (dev)->pci_device == 0x2A42 || \ - (dev)->pci_device == 0x2E02 || \ - (dev)->pci_device == 0x2E12 || \ - (dev)->pci_device == 0x2E22 || \ - (dev)->pci_device == 0x2E32 || \ - (dev)->pci_device == 0x2E42 || \ - (dev)->pci_device == 0x0042 || \ - (dev)->pci_device == 0x0046) - -#define IS_I965GM(dev) ((dev)->pci_device == 0x2A02 || \ - (dev)->pci_device == 0x2A12) - -#define IS_GM45(dev) ((dev)->pci_device == 0x2A42) - -#define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \ - (dev)->pci_device == 0x2E12 || \ - (dev)->pci_device == 0x2E22 || \ - (dev)->pci_device == 0x2E32 || \ - (dev)->pci_device == 0x2E42 || \ - IS_GM45(dev)) - -#define IS_PINEVIEW_G(dev) ((dev)->pci_device == 0xa001) -#define IS_PINEVIEW_M(dev) ((dev)->pci_device == 0xa011) -#define IS_PINEVIEW(dev) (IS_PINEVIEW_G(dev) || IS_PINEVIEW_M(dev)) - -#define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \ - (dev)->pci_device == 0x29B2 || \ - (dev)->pci_device == 0x29D2 || \ - (IS_PINEVIEW(dev))) - +#define INTEL_INFO(dev) (((struct drm_i915_private *) (dev)->dev_private)->info) + +#define IS_I830(dev) ((dev)->pci_device == 0x3577) +#define IS_845G(dev) ((dev)->pci_device == 0x2562) +#define IS_I85X(dev) ((dev)->pci_device == 0x3582) +#define IS_I865G(dev) ((dev)->pci_device == 0x2572) +#define IS_I8XX(dev) (INTEL_INFO(dev)->is_i8xx) +#define IS_I915G(dev) (INTEL_INFO(dev)->is_i915g) +#define IS_I915GM(dev) ((dev)->pci_device == 0x2592) +#define IS_I945G(dev) ((dev)->pci_device == 0x2772) +#define IS_I945GM(dev) (INTEL_INFO(dev)->is_i945gm) +#define IS_I965G(dev) (INTEL_INFO(dev)->is_i965g) +#define IS_I965GM(dev) (INTEL_INFO(dev)->is_i965gm) +#define IS_GM45(dev) ((dev)->pci_device == 0x2A42) +#define IS_G4X(dev) (INTEL_INFO(dev)->is_g4x) +#define IS_PINEVIEW_G(dev) ((dev)->pci_device == 0xa001) +#define IS_PINEVIEW_M(dev) ((dev)->pci_device == 0xa011) +#define IS_PINEVIEW(dev) (INTEL_INFO(dev)->is_pineview) +#define IS_G33(dev) (INTEL_INFO(dev)->is_g33) #define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042) #define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046) -#define IS_IRONLAKE(dev) (IS_IRONLAKE_D(dev) || IS_IRONLAKE_M(dev)) - -#define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \ - IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev) || \ - IS_IRONLAKE(dev)) +#define IS_IRONLAKE(dev) (INTEL_INFO(dev)->is_ironlake) +#define IS_I9XX(dev) (INTEL_INFO(dev)->is_i9xx) +#define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) -#define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \ - IS_I945GM(dev) || IS_I965GM(dev) || IS_GM45(dev) || \ - IS_PINEVIEW(dev) || IS_IRONLAKE_M(dev)) +#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) -#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev) || \ - IS_IRONLAKE(dev)) /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte * rows, which changed the alignment requirements and fence programming. */ @@ -1054,17 +1058,14 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define SUPPORTS_EDP(dev) (IS_IRONLAKE_M(dev)) #define SUPPORTS_TV(dev) (IS_I9XX(dev) && IS_MOBILE(dev) && \ !IS_IRONLAKE(dev) && !IS_PINEVIEW(dev)) -#define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev) || IS_I965G(dev)) +#define I915_HAS_HOTPLUG(dev) (INTEL_INFO(dev)->has_hotplug) /* dsparb controlled by hw only */ #define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev)) #define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IRONLAKE(dev)) -#define HAS_PIPE_CXSR(dev) (IS_G4X(dev) || IS_IRONLAKE(dev)) -#define I915_HAS_FBC(dev) (IS_MOBILE(dev) && \ - (IS_I9XX(dev) || IS_GM45(dev)) && \ - !IS_PINEVIEW(dev) && \ - !IS_IRONLAKE(dev)) -#define I915_HAS_RC6(dev) (IS_I965GM(dev) || IS_GM45(dev) || IS_IRONLAKE_M(dev)) +#define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr) +#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) +#define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6) #define PRIMARY_RINGBUFFER_SIZE (128*1024) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8c463cf..ec8a0d7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -277,7 +277,7 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj, mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_get_pages(obj); + ret = i915_gem_object_get_pages(obj, 0); if (ret != 0) goto fail_unlock; @@ -321,40 +321,24 @@ fail_unlock: return ret; } -static inline gfp_t -i915_gem_object_get_page_gfp_mask (struct drm_gem_object *obj) -{ - return mapping_gfp_mask(obj->filp->f_path.dentry->d_inode->i_mapping); -} - -static inline void -i915_gem_object_set_page_gfp_mask (struct drm_gem_object *obj, gfp_t gfp) -{ - mapping_set_gfp_mask(obj->filp->f_path.dentry->d_inode->i_mapping, gfp); -} - static int i915_gem_object_get_pages_or_evict(struct drm_gem_object *obj) { int ret; - ret = i915_gem_object_get_pages(obj); + ret = i915_gem_object_get_pages(obj, __GFP_NORETRY | __GFP_NOWARN); /* If we've insufficient memory to map in the pages, attempt * to make some space by throwing out some old buffers. */ if (ret == -ENOMEM) { struct drm_device *dev = obj->dev; - gfp_t gfp; ret = i915_gem_evict_something(dev, obj->size); if (ret) return ret; - gfp = i915_gem_object_get_page_gfp_mask(obj); - i915_gem_object_set_page_gfp_mask(obj, gfp & ~__GFP_NORETRY); - ret = i915_gem_object_get_pages(obj); - i915_gem_object_set_page_gfp_mask (obj, gfp); + ret = i915_gem_object_get_pages(obj, 0); } return ret; @@ -790,7 +774,7 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_get_pages(obj); + ret = i915_gem_object_get_pages(obj, 0); if (ret != 0) goto fail_unlock; @@ -1568,6 +1552,8 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) else list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); + BUG_ON(!list_empty(&obj_priv->gpu_write_list)); + obj_priv->last_rendering_seqno = 0; if (obj_priv->active) { obj_priv->active = 0; @@ -1638,7 +1624,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, struct drm_i915_gem_object *obj_priv, *next; list_for_each_entry_safe(obj_priv, next, - &dev_priv->mm.flushing_list, list) { + &dev_priv->mm.gpu_write_list, + gpu_write_list) { struct drm_gem_object *obj = obj_priv->obj; if ((obj->write_domain & flush_domains) == @@ -1646,6 +1633,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, uint32_t old_write_domain = obj->write_domain; obj->write_domain = 0; + list_del_init(&obj_priv->gpu_write_list); i915_gem_object_move_to_active(obj, seqno); trace_i915_gem_object_change_domain(obj, @@ -2021,9 +2009,6 @@ i915_gem_object_unbind(struct drm_gem_object *obj) /* blow away mappings if mapped through GTT */ i915_gem_release_mmap(obj); - if (obj_priv->fence_reg != I915_FENCE_REG_NONE) - i915_gem_clear_fence_reg(obj); - /* Move the object to the CPU domain to ensure that * any possible CPU writes while it's not in the GTT * are flushed when we go to remap it. This will @@ -2039,6 +2024,10 @@ i915_gem_object_unbind(struct drm_gem_object *obj) BUG_ON(obj_priv->active); + /* release the fence reg _after_ flushing */ + if (obj_priv->fence_reg != I915_FENCE_REG_NONE) + i915_gem_clear_fence_reg(obj); + if (obj_priv->agp_mem != NULL) { drm_unbind_agp(obj_priv->agp_mem); drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE); @@ -2099,8 +2088,8 @@ static int i915_gem_evict_everything(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t seqno; int ret; + uint32_t seqno; bool lists_empty; spin_lock(&dev_priv->mm.active_list_lock); @@ -2122,6 +2111,8 @@ i915_gem_evict_everything(struct drm_device *dev) if (ret) return ret; + BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); + ret = i915_gem_evict_from_inactive_list(dev); if (ret) return ret; @@ -2229,7 +2220,8 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) } int -i915_gem_object_get_pages(struct drm_gem_object *obj) +i915_gem_object_get_pages(struct drm_gem_object *obj, + gfp_t gfpmask) { struct drm_i915_gem_object *obj_priv = obj->driver_private; int page_count, i; @@ -2255,7 +2247,10 @@ i915_gem_object_get_pages(struct drm_gem_object *obj) inode = obj->filp->f_path.dentry->d_inode; mapping = inode->i_mapping; for (i = 0; i < page_count; i++) { - page = read_mapping_page(mapping, i, NULL); + page = read_cache_page_gfp(mapping, i, + mapping_gfp_mask (mapping) | + __GFP_COLD | + gfpmask); if (IS_ERR(page)) { ret = PTR_ERR(page); i915_gem_object_put_pages(obj); @@ -2578,12 +2573,9 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = obj->driver_private; struct drm_mm_node *free_space; - bool retry_alloc = false; + gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN; int ret; - if (dev_priv->mm.suspended) - return -EBUSY; - if (obj_priv->madv != I915_MADV_WILLNEED) { DRM_ERROR("Attempting to bind a purgeable object\n"); return -EINVAL; @@ -2625,15 +2617,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) DRM_INFO("Binding object of size %zd at 0x%08x\n", obj->size, obj_priv->gtt_offset); #endif - if (retry_alloc) { - i915_gem_object_set_page_gfp_mask (obj, - i915_gem_object_get_page_gfp_mask (obj) & ~__GFP_NORETRY); - } - ret = i915_gem_object_get_pages(obj); - if (retry_alloc) { - i915_gem_object_set_page_gfp_mask (obj, - i915_gem_object_get_page_gfp_mask (obj) | __GFP_NORETRY); - } + ret = i915_gem_object_get_pages(obj, gfpmask); if (ret) { drm_mm_put_block(obj_priv->gtt_space); obj_priv->gtt_space = NULL; @@ -2643,9 +2627,9 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) ret = i915_gem_evict_something(dev, obj->size); if (ret) { /* now try to shrink everyone else */ - if (! retry_alloc) { - retry_alloc = true; - goto search_free; + if (gfpmask) { + gfpmask = 0; + goto search_free; } return ret; @@ -2723,7 +2707,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) old_write_domain = obj->write_domain; i915_gem_flush(dev, 0, obj->write_domain); seqno = i915_add_request(dev, NULL, obj->write_domain); - obj->write_domain = 0; + BUG_ON(obj->write_domain); i915_gem_object_move_to_active(obj, seqno); trace_i915_gem_object_change_domain(obj, @@ -2839,6 +2823,57 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) return 0; } +/* + * Prepare buffer for display plane. Use uninterruptible for possible flush + * wait, as in modesetting process we're not supposed to be interrupted. + */ +int +i915_gem_object_set_to_display_plane(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct drm_i915_gem_object *obj_priv = obj->driver_private; + uint32_t old_write_domain, old_read_domains; + int ret; + + /* Not valid to be called on unbound objects. */ + if (obj_priv->gtt_space == NULL) + return -EINVAL; + + i915_gem_object_flush_gpu_write_domain(obj); + + /* Wait on any GPU rendering and flushing to occur. */ + if (obj_priv->active) { +#if WATCH_BUF + DRM_INFO("%s: object %p wait for seqno %08x\n", + __func__, obj, obj_priv->last_rendering_seqno); +#endif + ret = i915_do_wait_request(dev, obj_priv->last_rendering_seqno, 0); + if (ret != 0) + return ret; + } + + old_write_domain = obj->write_domain; + old_read_domains = obj->read_domains; + + obj->read_domains &= I915_GEM_DOMAIN_GTT; + + i915_gem_object_flush_cpu_write_domain(obj); + + /* It should now be out of any other write domains, and we can update + * the domain values for our changes. + */ + BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0); + obj->read_domains |= I915_GEM_DOMAIN_GTT; + obj->write_domain = I915_GEM_DOMAIN_GTT; + obj_priv->dirty = 1; + + trace_i915_gem_object_change_domain(obj, + old_read_domains, + old_write_domain); + + return 0; +} + /** * Moves a single object to the CPU read, and possibly write domain. * @@ -3198,7 +3233,7 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, static int i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, struct drm_file *file_priv, - struct drm_i915_gem_exec_object *entry, + struct drm_i915_gem_exec_object2 *entry, struct drm_i915_gem_relocation_entry *relocs) { struct drm_device *dev = obj->dev; @@ -3206,12 +3241,35 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, struct drm_i915_gem_object *obj_priv = obj->driver_private; int i, ret; void __iomem *reloc_page; + bool need_fence; + + need_fence = entry->flags & EXEC_OBJECT_NEEDS_FENCE && + obj_priv->tiling_mode != I915_TILING_NONE; + + /* Check fence reg constraints and rebind if necessary */ + if (need_fence && !i915_obj_fenceable(dev, obj)) + i915_gem_object_unbind(obj); /* Choose the GTT offset for our buffer and put it there. */ ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment); if (ret) return ret; + /* + * Pre-965 chips need a fence register set up in order to + * properly handle blits to/from tiled surfaces. + */ + if (need_fence) { + ret = i915_gem_object_get_fence_reg(obj); + if (ret != 0) { + if (ret != -EBUSY && ret != -ERESTARTSYS) + DRM_ERROR("Failure to install fence: %d\n", + ret); + i915_gem_object_unpin(obj); + return ret; + } + } + entry->offset = obj_priv->gtt_offset; /* Apply the relocations, using the GTT aperture to avoid cache @@ -3373,7 +3431,7 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, */ static int i915_dispatch_gem_execbuffer(struct drm_device *dev, - struct drm_i915_gem_execbuffer *exec, + struct drm_i915_gem_execbuffer2 *exec, struct drm_clip_rect *cliprects, uint64_t exec_offset) { @@ -3463,7 +3521,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv) } static int -i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object *exec_list, +i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object2 *exec_list, uint32_t buffer_count, struct drm_i915_gem_relocation_entry **relocs) { @@ -3478,8 +3536,10 @@ i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object *exec_list, } *relocs = drm_calloc_large(reloc_count, sizeof(**relocs)); - if (*relocs == NULL) + if (*relocs == NULL) { + DRM_ERROR("failed to alloc relocs, count %d\n", reloc_count); return -ENOMEM; + } for (i = 0; i < buffer_count; i++) { struct drm_i915_gem_relocation_entry __user *user_relocs; @@ -3503,13 +3563,16 @@ i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object *exec_list, } static int -i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object *exec_list, +i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object2 *exec_list, uint32_t buffer_count, struct drm_i915_gem_relocation_entry *relocs) { uint32_t reloc_count = 0, i; int ret = 0; + if (relocs == NULL) + return 0; + for (i = 0; i < buffer_count; i++) { struct drm_i915_gem_relocation_entry __user *user_relocs; int unwritten; @@ -3536,7 +3599,7 @@ err: } static int -i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer *exec, +i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer2 *exec, uint64_t exec_offset) { uint32_t exec_start, exec_len; @@ -3589,18 +3652,18 @@ i915_gem_wait_for_pending_flip(struct drm_device *dev, } int -i915_gem_execbuffer(struct drm_device *dev, void *data, - struct drm_file *file_priv) +i915_gem_do_execbuffer(struct drm_device *dev, void *data, + struct drm_file *file_priv, + struct drm_i915_gem_execbuffer2 *args, + struct drm_i915_gem_exec_object2 *exec_list) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_execbuffer *args = data; - struct drm_i915_gem_exec_object *exec_list = NULL; struct drm_gem_object **object_list = NULL; struct drm_gem_object *batch_obj; struct drm_i915_gem_object *obj_priv; struct drm_clip_rect *cliprects = NULL; - struct drm_i915_gem_relocation_entry *relocs; - int ret, ret2, i, pinned = 0; + struct drm_i915_gem_relocation_entry *relocs = NULL; + int ret = 0, ret2, i, pinned = 0; uint64_t exec_offset; uint32_t seqno, flush_domains, reloc_index; int pin_tries, flips; @@ -3614,31 +3677,21 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); return -EINVAL; } - /* Copy in the exec list from userland */ - exec_list = drm_malloc_ab(sizeof(*exec_list), args->buffer_count); object_list = drm_malloc_ab(sizeof(*object_list), args->buffer_count); - if (exec_list == NULL || object_list == NULL) { - DRM_ERROR("Failed to allocate exec or object list " - "for %d buffers\n", + if (object_list == NULL) { + DRM_ERROR("Failed to allocate object list for %d buffers\n", args->buffer_count); ret = -ENOMEM; goto pre_mutex_err; } - ret = copy_from_user(exec_list, - (struct drm_i915_relocation_entry __user *) - (uintptr_t) args->buffers_ptr, - sizeof(*exec_list) * args->buffer_count); - if (ret != 0) { - DRM_ERROR("copy %d exec entries failed %d\n", - args->buffer_count, ret); - goto pre_mutex_err; - } if (args->num_cliprects != 0) { cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects), GFP_KERNEL); - if (cliprects == NULL) + if (cliprects == NULL) { + ret = -ENOMEM; goto pre_mutex_err; + } ret = copy_from_user(cliprects, (struct drm_clip_rect __user *) @@ -3680,6 +3733,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, if (object_list[i] == NULL) { DRM_ERROR("Invalid object handle %d at index %d\n", exec_list[i].handle, i); + /* prevent error path from reading uninitialized data */ + args->buffer_count = i + 1; ret = -EBADF; goto err; } @@ -3688,6 +3743,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, if (obj_priv->in_execbuffer) { DRM_ERROR("Object %p appears more than once in object list\n", object_list[i]); + /* prevent error path from reading uninitialized data */ + args->buffer_count = i + 1; ret = -EBADF; goto err; } @@ -3801,16 +3858,23 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, i915_gem_flush(dev, dev->invalidate_domains, dev->flush_domains); - if (dev->flush_domains) + if (dev->flush_domains & I915_GEM_GPU_DOMAINS) (void)i915_add_request(dev, file_priv, dev->flush_domains); } for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; + struct drm_i915_gem_object *obj_priv = obj->driver_private; uint32_t old_write_domain = obj->write_domain; obj->write_domain = obj->pending_write_domain; + if (obj->write_domain) + list_move_tail(&obj_priv->gpu_write_list, + &dev_priv->mm.gpu_write_list); + else + list_del_init(&obj_priv->gpu_write_list); + trace_i915_gem_object_change_domain(obj, obj->read_domains, old_write_domain); @@ -3884,8 +3948,101 @@ err: mutex_unlock(&dev->struct_mutex); +pre_mutex_err: + /* Copy the updated relocations out regardless of current error + * state. Failure to update the relocs would mean that the next + * time userland calls execbuf, it would do so with presumed offset + * state that didn't match the actual object state. + */ + ret2 = i915_gem_put_relocs_to_user(exec_list, args->buffer_count, + relocs); + if (ret2 != 0) { + DRM_ERROR("Failed to copy relocations back out: %d\n", ret2); + + if (ret == 0) + ret = ret2; + } + + drm_free_large(object_list); + kfree(cliprects); + + return ret; +} + +/* + * Legacy execbuffer just creates an exec2 list from the original exec object + * list array and passes it to the real function. + */ +int +i915_gem_execbuffer(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_i915_gem_execbuffer *args = data; + struct drm_i915_gem_execbuffer2 exec2; + struct drm_i915_gem_exec_object *exec_list = NULL; + struct drm_i915_gem_exec_object2 *exec2_list = NULL; + int ret, i; + +#if WATCH_EXEC + DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", + (int) args->buffers_ptr, args->buffer_count, args->batch_len); +#endif + + if (args->buffer_count < 1) { + DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); + return -EINVAL; + } + + /* Copy in the exec list from userland */ + exec_list = drm_malloc_ab(sizeof(*exec_list), args->buffer_count); + exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count); + if (exec_list == NULL || exec2_list == NULL) { + DRM_ERROR("Failed to allocate exec list for %d buffers\n", + args->buffer_count); + drm_free_large(exec_list); + drm_free_large(exec2_list); + return -ENOMEM; + } + ret = copy_from_user(exec_list, + (struct drm_i915_relocation_entry __user *) + (uintptr_t) args->buffers_ptr, + sizeof(*exec_list) * args->buffer_count); + if (ret != 0) { + DRM_ERROR("copy %d exec entries failed %d\n", + args->buffer_count, ret); + drm_free_large(exec_list); + drm_free_large(exec2_list); + return -EFAULT; + } + + for (i = 0; i < args->buffer_count; i++) { + exec2_list[i].handle = exec_list[i].handle; + exec2_list[i].relocation_count = exec_list[i].relocation_count; + exec2_list[i].relocs_ptr = exec_list[i].relocs_ptr; + exec2_list[i].alignment = exec_list[i].alignment; + exec2_list[i].offset = exec_list[i].offset; + if (!IS_I965G(dev)) + exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE; + else + exec2_list[i].flags = 0; + } + + exec2.buffers_ptr = args->buffers_ptr; + exec2.buffer_count = args->buffer_count; + exec2.batch_start_offset = args->batch_start_offset; + exec2.batch_len = args->batch_len; + exec2.DR1 = args->DR1; + exec2.DR4 = args->DR4; + exec2.num_cliprects = args->num_cliprects; + exec2.cliprects_ptr = args->cliprects_ptr; + exec2.flags = 0; + + ret = i915_gem_do_execbuffer(dev, data, file_priv, &exec2, exec2_list); if (!ret) { /* Copy the new buffer offsets back to the user's exec list. */ + for (i = 0; i < args->buffer_count; i++) + exec_list[i].offset = exec2_list[i].offset; + /* ... and back out to userspace */ ret = copy_to_user((struct drm_i915_relocation_entry __user *) (uintptr_t) args->buffers_ptr, exec_list, @@ -3898,25 +4055,62 @@ err: } } - /* Copy the updated relocations out regardless of current error - * state. Failure to update the relocs would mean that the next - * time userland calls execbuf, it would do so with presumed offset - * state that didn't match the actual object state. - */ - ret2 = i915_gem_put_relocs_to_user(exec_list, args->buffer_count, - relocs); - if (ret2 != 0) { - DRM_ERROR("Failed to copy relocations back out: %d\n", ret2); + drm_free_large(exec_list); + drm_free_large(exec2_list); + return ret; +} - if (ret == 0) - ret = ret2; +int +i915_gem_execbuffer2(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_i915_gem_execbuffer2 *args = data; + struct drm_i915_gem_exec_object2 *exec2_list = NULL; + int ret; + +#if WATCH_EXEC + DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", + (int) args->buffers_ptr, args->buffer_count, args->batch_len); +#endif + + if (args->buffer_count < 1) { + DRM_ERROR("execbuf2 with %d buffers\n", args->buffer_count); + return -EINVAL; } -pre_mutex_err: - drm_free_large(object_list); - drm_free_large(exec_list); - kfree(cliprects); + exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count); + if (exec2_list == NULL) { + DRM_ERROR("Failed to allocate exec list for %d buffers\n", + args->buffer_count); + return -ENOMEM; + } + ret = copy_from_user(exec2_list, + (struct drm_i915_relocation_entry __user *) + (uintptr_t) args->buffers_ptr, + sizeof(*exec2_list) * args->buffer_count); + if (ret != 0) { + DRM_ERROR("copy %d exec entries failed %d\n", + args->buffer_count, ret); + drm_free_large(exec2_list); + return -EFAULT; + } + + ret = i915_gem_do_execbuffer(dev, data, file_priv, args, exec2_list); + if (!ret) { + /* Copy the new buffer offsets back to the user's exec list. */ + ret = copy_to_user((struct drm_i915_relocation_entry __user *) + (uintptr_t) args->buffers_ptr, + exec2_list, + sizeof(*exec2_list) * args->buffer_count); + if (ret) { + ret = -EFAULT; + DRM_ERROR("failed to copy %d exec entries " + "back to user (%d)\n", + args->buffer_count, ret); + } + } + drm_free_large(exec2_list); return ret; } @@ -3933,19 +4127,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) if (ret) return ret; } - /* - * Pre-965 chips need a fence register set up in order to - * properly handle tiled surfaces. - */ - if (!IS_I965G(dev) && obj_priv->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence_reg(obj); - if (ret != 0) { - if (ret != -EBUSY && ret != -ERESTARTSYS) - DRM_ERROR("Failure to install fence: %d\n", - ret); - return ret; - } - } + obj_priv->pin_count++; /* If the object is not active and not pending a flush, @@ -4203,6 +4385,7 @@ int i915_gem_init_object(struct drm_gem_object *obj) obj_priv->obj = obj; obj_priv->fence_reg = I915_FENCE_REG_NONE; INIT_LIST_HEAD(&obj_priv->list); + INIT_LIST_HEAD(&obj_priv->gpu_write_list); INIT_LIST_HEAD(&obj_priv->fence_list); obj_priv->madv = I915_MADV_WILLNEED; @@ -4654,6 +4837,7 @@ i915_gem_load(struct drm_device *dev) spin_lock_init(&dev_priv->mm.active_list_lock); INIT_LIST_HEAD(&dev_priv->mm.active_list); INIT_LIST_HEAD(&dev_priv->mm.flushing_list); + INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list); INIT_LIST_HEAD(&dev_priv->mm.request_list); INIT_LIST_HEAD(&dev_priv->mm.fence_list); @@ -4708,7 +4892,7 @@ int i915_gem_init_phys_object(struct drm_device *dev, phys_obj->id = id; - phys_obj->handle = drm_pci_alloc(dev, size, 0, 0xffffffff); + phys_obj->handle = drm_pci_alloc(dev, size, 0); if (!phys_obj->handle) { ret = -ENOMEM; goto kfree_obj; @@ -4766,7 +4950,7 @@ void i915_gem_detach_phys_object(struct drm_device *dev, if (!obj_priv->phys_obj) return; - ret = i915_gem_object_get_pages(obj); + ret = i915_gem_object_get_pages(obj, 0); if (ret) goto out; @@ -4824,7 +5008,7 @@ i915_gem_attach_phys_object(struct drm_device *dev, obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1]; obj_priv->phys_obj->cur_obj = obj; - ret = i915_gem_object_get_pages(obj); + ret = i915_gem_object_get_pages(obj, 0); if (ret) { DRM_ERROR("failed to get page list\n"); goto out; diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 30d6af6c..df278b2 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -304,35 +304,39 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) /** - * Returns the size of the fence for a tiled object of the given size. + * Returns whether an object is currently fenceable. If not, it may need + * to be unbound and have its pitch adjusted. */ -static int -i915_get_fence_size(struct drm_device *dev, int size) +bool +i915_obj_fenceable(struct drm_device *dev, struct drm_gem_object *obj) { - int i; - int start; + struct drm_i915_gem_object *obj_priv = obj->driver_private; if (IS_I965G(dev)) { /* The 965 can have fences at any page boundary. */ - return ALIGN(size, 4096); + if (obj->size & 4095) + return false; + return true; + } else if (IS_I9XX(dev)) { + if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK) + return false; } else { - /* Align the size to a power of two greater than the smallest - * fence size. - */ - if (IS_I9XX(dev)) - start = 1024 * 1024; - else - start = 512 * 1024; + if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK) + return false; + } - for (i = start; i < size; i <<= 1) - ; + /* Power of two sized... */ + if (obj->size & (obj->size - 1)) + return false; - return i; - } + /* Objects must be size aligned as well */ + if (obj_priv->gtt_offset & (obj->size - 1)) + return false; + return true; } /* Check pitch constriants for all chips & tiling formats */ -static bool +bool i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) { int tile_width; @@ -384,12 +388,6 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) if (stride & (stride - 1)) return false; - /* We don't 0handle the aperture area covered by the fence being bigger - * than the object size. - */ - if (i915_get_fence_size(dev, size) != size) - return false; - return true; } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 85f4c5d..a17d6bdf 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -274,7 +274,6 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int ret = IRQ_NONE; u32 de_iir, gt_iir, de_ier, pch_iir; - u32 new_de_iir, new_gt_iir, new_pch_iir; struct drm_i915_master_private *master_priv; /* disable master interrupt before clearing iir */ @@ -286,49 +285,58 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) gt_iir = I915_READ(GTIIR); pch_iir = I915_READ(SDEIIR); - for (;;) { - if (de_iir == 0 && gt_iir == 0 && pch_iir == 0) - break; + if (de_iir == 0 && gt_iir == 0 && pch_iir == 0) + goto done; - ret = IRQ_HANDLED; + ret = IRQ_HANDLED; - /* should clear PCH hotplug event before clear CPU irq */ - I915_WRITE(SDEIIR, pch_iir); - new_pch_iir = I915_READ(SDEIIR); + if (dev->primary->master) { + master_priv = dev->primary->master->driver_priv; + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_dispatch = + READ_BREADCRUMB(dev_priv); + } - I915_WRITE(DEIIR, de_iir); - new_de_iir = I915_READ(DEIIR); - I915_WRITE(GTIIR, gt_iir); - new_gt_iir = I915_READ(GTIIR); + if (gt_iir & GT_USER_INTERRUPT) { + u32 seqno = i915_get_gem_seqno(dev); + dev_priv->mm.irq_gem_seqno = seqno; + trace_i915_gem_request_complete(dev, seqno); + DRM_WAKEUP(&dev_priv->irq_queue); + dev_priv->hangcheck_count = 0; + mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); + } - if (dev->primary->master) { - master_priv = dev->primary->master->driver_priv; - if (master_priv->sarea_priv) - master_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); - } + if (de_iir & DE_GSE) + ironlake_opregion_gse_intr(dev); - if (gt_iir & GT_USER_INTERRUPT) { - u32 seqno = i915_get_gem_seqno(dev); - dev_priv->mm.irq_gem_seqno = seqno; - trace_i915_gem_request_complete(dev, seqno); - DRM_WAKEUP(&dev_priv->irq_queue); - } + if (de_iir & DE_PLANEA_FLIP_DONE) { + intel_prepare_page_flip(dev, 0); + intel_finish_page_flip(dev, 0); + } - if (de_iir & DE_GSE) - ironlake_opregion_gse_intr(dev); + if (de_iir & DE_PLANEB_FLIP_DONE) { + intel_prepare_page_flip(dev, 1); + intel_finish_page_flip(dev, 1); + } - /* check event from PCH */ - if ((de_iir & DE_PCH_EVENT) && - (pch_iir & SDE_HOTPLUG_MASK)) { - queue_work(dev_priv->wq, &dev_priv->hotplug_work); - } + if (de_iir & DE_PIPEA_VBLANK) + drm_handle_vblank(dev, 0); - de_iir = new_de_iir; - gt_iir = new_gt_iir; - pch_iir = new_pch_iir; + if (de_iir & DE_PIPEB_VBLANK) + drm_handle_vblank(dev, 1); + + /* check event from PCH */ + if ((de_iir & DE_PCH_EVENT) && + (pch_iir & SDE_HOTPLUG_MASK)) { + queue_work(dev_priv->wq, &dev_priv->hotplug_work); } + /* should clear PCH hotplug event before clear CPU irq */ + I915_WRITE(SDEIIR, pch_iir); + I915_WRITE(GTIIR, gt_iir); + I915_WRITE(DEIIR, de_iir); + +done: I915_WRITE(DEIER, de_ier); (void)I915_READ(DEIER); @@ -852,11 +860,11 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) if (!(pipeconf & PIPEACONF_ENABLE)) return -EINVAL; - if (IS_IRONLAKE(dev)) - return 0; - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - if (IS_I965G(dev)) + if (IS_IRONLAKE(dev)) + ironlake_enable_display_irq(dev_priv, (pipe == 0) ? + DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); + else if (IS_I965G(dev)) i915_enable_pipestat(dev_priv, pipe, PIPE_START_VBLANK_INTERRUPT_ENABLE); else @@ -874,13 +882,14 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; - if (IS_IRONLAKE(dev)) - return; - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - i915_disable_pipestat(dev_priv, pipe, - PIPE_VBLANK_INTERRUPT_ENABLE | - PIPE_START_VBLANK_INTERRUPT_ENABLE); + if (IS_IRONLAKE(dev)) + ironlake_disable_display_irq(dev_priv, (pipe == 0) ? + DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); + else + i915_disable_pipestat(dev_priv, pipe, + PIPE_VBLANK_INTERRUPT_ENABLE | + PIPE_START_VBLANK_INTERRUPT_ENABLE); spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } @@ -1023,13 +1032,14 @@ static int ironlake_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* enable kind of interrupts always enabled */ - u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT; + u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | + DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE; u32 render_mask = GT_USER_INTERRUPT; u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG | SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; dev_priv->irq_mask_reg = ~display_mask; - dev_priv->de_irq_enable_reg = display_mask; + dev_priv->de_irq_enable_reg = display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK; /* should always can generate irq */ I915_WRITE(DEIIR, I915_READ(DEIIR)); @@ -1084,6 +1094,10 @@ void i915_driver_irq_preinstall(struct drm_device * dev) (void) I915_READ(IER); } +/* + * Must be called after intel_modeset_init or hotplug interrupts won't be + * enabled correctly. + */ int i915_driver_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -1106,19 +1120,23 @@ int i915_driver_irq_postinstall(struct drm_device *dev) if (I915_HAS_HOTPLUG(dev)) { u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); - /* Leave other bits alone */ - hotplug_en |= HOTPLUG_EN_MASK; + /* Note HDMI and DP share bits */ + if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) + hotplug_en |= HDMIB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) + hotplug_en |= HDMIC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) + hotplug_en |= HDMID_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS) + hotplug_en |= SDVOC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS) + hotplug_en |= SDVOB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) + hotplug_en |= CRT_HOTPLUG_INT_EN; + /* Ignore TV since it's buggy */ + I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); - dev_priv->hotplug_supported_mask = CRT_HOTPLUG_INT_STATUS | - TV_HOTPLUG_INT_STATUS | SDVOC_HOTPLUG_INT_STATUS | - SDVOB_HOTPLUG_INT_STATUS; - if (IS_G4X(dev)) { - dev_priv->hotplug_supported_mask |= - HDMIB_HOTPLUG_INT_STATUS | - HDMIC_HOTPLUG_INT_STATUS | - HDMID_HOTPLUG_INT_STATUS; - } /* Enable in IER... */ enable_mask |= I915_DISPLAY_PORT_INTERRUPT; /* and unmask in IMR */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 974b3cf..ab1bd2d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -338,6 +338,7 @@ #define FBC_CTL_PERIODIC (1<<30) #define FBC_CTL_INTERVAL_SHIFT (16) #define FBC_CTL_UNCOMPRESSIBLE (1<<14) +#define FBC_C3_IDLE (1<<13) #define FBC_CTL_STRIDE_SHIFT (5) #define FBC_CTL_FENCENO (1<<0) #define FBC_COMMAND 0x0320c @@ -879,13 +880,6 @@ #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) #define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */ #define CRT_FORCE_HOTPLUG_MASK 0xfffffe1f -#define HOTPLUG_EN_MASK (HDMIB_HOTPLUG_INT_EN | \ - HDMIC_HOTPLUG_INT_EN | \ - HDMID_HOTPLUG_INT_EN | \ - SDVOB_HOTPLUG_INT_EN | \ - SDVOC_HOTPLUG_INT_EN | \ - CRT_HOTPLUG_INT_EN) - #define PORT_HOTPLUG_STAT 0x61114 #define HDMIB_HOTPLUG_INT_STATUS (1 << 29) @@ -982,6 +976,8 @@ #define LVDS_PORT_EN (1 << 31) /* Selects pipe B for LVDS data. Must be set on pre-965. */ #define LVDS_PIPEB_SELECT (1 << 30) +/* LVDS dithering flag on 965/g4x platform */ +#define LVDS_ENABLE_DITHER (1 << 25) /* Enable border for unscaled (or aspect-scaled) display */ #define LVDS_BORDER_ENABLE (1 << 15) /* @@ -1751,6 +1747,8 @@ /* Display & cursor control */ +/* dithering flag on Ironlake */ +#define PIPE_ENABLE_DITHER (1 << 4) /* Pipe A */ #define PIPEADSL 0x70000 #define PIPEACONF 0x70008 @@ -1818,7 +1816,7 @@ #define DSPFW_PLANEB_SHIFT 8 #define DSPFW2 0x70038 #define DSPFW_CURSORA_MASK 0x00003f00 -#define DSPFW_CURSORA_SHIFT 16 +#define DSPFW_CURSORA_SHIFT 8 #define DSPFW3 0x7003c #define DSPFW_HPLL_SR_EN (1<<31) #define DSPFW_CURSOR_SR_SHIFT 24 diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index d5ebb00..a3b90c9 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -732,12 +732,6 @@ int i915_save_state(struct drm_device *dev) pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); - /* Render Standby */ - if (I915_HAS_RC6(dev)) { - dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY); - dev_priv->savePWRCTXA = I915_READ(PWRCTXA); - } - /* Hardware status page */ dev_priv->saveHWS = I915_READ(HWS_PGA); @@ -793,12 +787,6 @@ int i915_restore_state(struct drm_device *dev) pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); - /* Render Standby */ - if (I915_HAS_RC6(dev)) { - I915_WRITE(MCHBAR_RENDER_STANDBY, dev_priv->saveRENDERSTANDBY); - I915_WRITE(PWRCTXA, dev_priv->savePWRCTXA); - } - /* Hardware status page */ I915_WRITE(HWS_PGA, dev_priv->saveHWS); diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index f275677..15fbc1b 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -33,6 +33,8 @@ #define SLAVE_ADDR1 0x70 #define SLAVE_ADDR2 0x72 +static int panel_type; + static void * find_section(struct bdb_header *bdb, int section_id) { @@ -128,6 +130,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, dev_priv->lvds_dither = lvds_options->pixel_dither; if (lvds_options->panel_type == 0xff) return; + panel_type = lvds_options->panel_type; lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); if (!lvds_lfp_data) @@ -197,7 +200,8 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, memset(temp_mode, 0, sizeof(*temp_mode)); } kfree(temp_mode); - if (temp_downclock < panel_fixed_mode->clock) { + if (temp_downclock < panel_fixed_mode->clock && + i915_lvds_downclock) { dev_priv->lvds_downclock_avail = 1; dev_priv->lvds_downclock = temp_downclock; DRM_DEBUG_KMS("LVDS downclock is found in VBT. ", @@ -405,6 +409,34 @@ parse_driver_features(struct drm_i915_private *dev_priv, } static void +parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) +{ + struct bdb_edp *edp; + + edp = find_section(bdb, BDB_EDP); + if (!edp) { + if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp_support) { + DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported,\ + assume 18bpp panel color depth.\n"); + dev_priv->edp_bpp = 18; + } + return; + } + + switch ((edp->color_depth >> (panel_type * 2)) & 3) { + case EDP_18BPP: + dev_priv->edp_bpp = 18; + break; + case EDP_24BPP: + dev_priv->edp_bpp = 24; + break; + case EDP_30BPP: + dev_priv->edp_bpp = 30; + break; + } +} + +static void parse_device_mapping(struct drm_i915_private *dev_priv, struct bdb_header *bdb) { @@ -521,6 +553,7 @@ intel_init_bios(struct drm_device *dev) parse_sdvo_device_mapping(dev_priv, bdb); parse_device_mapping(dev_priv, bdb); parse_driver_features(dev_priv, bdb); + parse_edp(dev_priv, bdb); pci_unmap_rom(pdev, bios); diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 425ac9d..4c18514 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -98,6 +98,7 @@ struct vbios_data { #define BDB_SDVO_LVDS_PNP_IDS 24 #define BDB_SDVO_LVDS_POWER_SEQ 25 #define BDB_TV_OPTIONS 26 +#define BDB_EDP 27 #define BDB_LVDS_OPTIONS 40 #define BDB_LVDS_LFP_DATA_PTRS 41 #define BDB_LVDS_LFP_DATA 42 @@ -426,6 +427,45 @@ struct bdb_driver_features { u8 custom_vbt_version; } __attribute__((packed)); +#define EDP_18BPP 0 +#define EDP_24BPP 1 +#define EDP_30BPP 2 +#define EDP_RATE_1_62 0 +#define EDP_RATE_2_7 1 +#define EDP_LANE_1 0 +#define EDP_LANE_2 1 +#define EDP_LANE_4 3 +#define EDP_PREEMPHASIS_NONE 0 +#define EDP_PREEMPHASIS_3_5dB 1 +#define EDP_PREEMPHASIS_6dB 2 +#define EDP_PREEMPHASIS_9_5dB 3 +#define EDP_VSWING_0_4V 0 +#define EDP_VSWING_0_6V 1 +#define EDP_VSWING_0_8V 2 +#define EDP_VSWING_1_2V 3 + +struct edp_power_seq { + u16 t3; + u16 t7; + u16 t9; + u16 t10; + u16 t12; +} __attribute__ ((packed)); + +struct edp_link_params { + u8 rate:4; + u8 lanes:4; + u8 preemphasis:4; + u8 vswing:4; +} __attribute__ ((packed)); + +struct bdb_edp { + struct edp_power_seq power_seqs[16]; + u32 color_depth; + u32 sdrrs_msa_timing_delay; + struct edp_link_params link_params[16]; +} __attribute__ ((packed)); + bool intel_init_bios(struct drm_device *dev); /* diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 9f3d3e5..79dd402 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -157,6 +157,9 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) adpa = I915_READ(PCH_ADPA); adpa &= ~ADPA_CRT_HOTPLUG_MASK; + /* disable HPD first */ + I915_WRITE(PCH_ADPA, adpa); + (void)I915_READ(PCH_ADPA); adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 | ADPA_CRT_HOTPLUG_WARMUP_10MS | @@ -548,4 +551,6 @@ void intel_crt_init(struct drm_device *dev) drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); drm_sysfs_connector_add(connector); + + dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 52cd9b0..b27202d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -70,8 +70,6 @@ struct intel_limit { intel_p2_t p2; bool (* find_pll)(const intel_limit_t *, struct drm_crtc *, int, int, intel_clock_t *); - bool (* find_reduced_pll)(const intel_limit_t *, struct drm_crtc *, - int, int, intel_clock_t *); }; #define I8XX_DOT_MIN 25000 @@ -242,38 +240,93 @@ struct intel_limit { #define IRONLAKE_DOT_MAX 350000 #define IRONLAKE_VCO_MIN 1760000 #define IRONLAKE_VCO_MAX 3510000 -#define IRONLAKE_N_MIN 1 -#define IRONLAKE_N_MAX 5 -#define IRONLAKE_M_MIN 79 -#define IRONLAKE_M_MAX 118 #define IRONLAKE_M1_MIN 12 -#define IRONLAKE_M1_MAX 23 +#define IRONLAKE_M1_MAX 22 #define IRONLAKE_M2_MIN 5 #define IRONLAKE_M2_MAX 9 -#define IRONLAKE_P_SDVO_DAC_MIN 5 -#define IRONLAKE_P_SDVO_DAC_MAX 80 -#define IRONLAKE_P_LVDS_MIN 28 -#define IRONLAKE_P_LVDS_MAX 112 -#define IRONLAKE_P1_MIN 1 -#define IRONLAKE_P1_MAX 8 -#define IRONLAKE_P2_SDVO_DAC_SLOW 10 -#define IRONLAKE_P2_SDVO_DAC_FAST 5 -#define IRONLAKE_P2_LVDS_SLOW 14 /* single channel */ -#define IRONLAKE_P2_LVDS_FAST 7 /* double channel */ #define IRONLAKE_P2_DOT_LIMIT 225000 /* 225Mhz */ +/* We have parameter ranges for different type of outputs. */ + +/* DAC & HDMI Refclk 120Mhz */ +#define IRONLAKE_DAC_N_MIN 1 +#define IRONLAKE_DAC_N_MAX 5 +#define IRONLAKE_DAC_M_MIN 79 +#define IRONLAKE_DAC_M_MAX 127 +#define IRONLAKE_DAC_P_MIN 5 +#define IRONLAKE_DAC_P_MAX 80 +#define IRONLAKE_DAC_P1_MIN 1 +#define IRONLAKE_DAC_P1_MAX 8 +#define IRONLAKE_DAC_P2_SLOW 10 +#define IRONLAKE_DAC_P2_FAST 5 + +/* LVDS single-channel 120Mhz refclk */ +#define IRONLAKE_LVDS_S_N_MIN 1 +#define IRONLAKE_LVDS_S_N_MAX 3 +#define IRONLAKE_LVDS_S_M_MIN 79 +#define IRONLAKE_LVDS_S_M_MAX 118 +#define IRONLAKE_LVDS_S_P_MIN 28 +#define IRONLAKE_LVDS_S_P_MAX 112 +#define IRONLAKE_LVDS_S_P1_MIN 2 +#define IRONLAKE_LVDS_S_P1_MAX 8 +#define IRONLAKE_LVDS_S_P2_SLOW 14 +#define IRONLAKE_LVDS_S_P2_FAST 14 + +/* LVDS dual-channel 120Mhz refclk */ +#define IRONLAKE_LVDS_D_N_MIN 1 +#define IRONLAKE_LVDS_D_N_MAX 3 +#define IRONLAKE_LVDS_D_M_MIN 79 +#define IRONLAKE_LVDS_D_M_MAX 127 +#define IRONLAKE_LVDS_D_P_MIN 14 +#define IRONLAKE_LVDS_D_P_MAX 56 +#define IRONLAKE_LVDS_D_P1_MIN 2 +#define IRONLAKE_LVDS_D_P1_MAX 8 +#define IRONLAKE_LVDS_D_P2_SLOW 7 +#define IRONLAKE_LVDS_D_P2_FAST 7 + +/* LVDS single-channel 100Mhz refclk */ +#define IRONLAKE_LVDS_S_SSC_N_MIN 1 +#define IRONLAKE_LVDS_S_SSC_N_MAX 2 +#define IRONLAKE_LVDS_S_SSC_M_MIN 79 +#define IRONLAKE_LVDS_S_SSC_M_MAX 126 +#define IRONLAKE_LVDS_S_SSC_P_MIN 28 +#define IRONLAKE_LVDS_S_SSC_P_MAX 112 +#define IRONLAKE_LVDS_S_SSC_P1_MIN 2 +#define IRONLAKE_LVDS_S_SSC_P1_MAX 8 +#define IRONLAKE_LVDS_S_SSC_P2_SLOW 14 +#define IRONLAKE_LVDS_S_SSC_P2_FAST 14 + +/* LVDS dual-channel 100Mhz refclk */ +#define IRONLAKE_LVDS_D_SSC_N_MIN 1 +#define IRONLAKE_LVDS_D_SSC_N_MAX 3 +#define IRONLAKE_LVDS_D_SSC_M_MIN 79 +#define IRONLAKE_LVDS_D_SSC_M_MAX 126 +#define IRONLAKE_LVDS_D_SSC_P_MIN 14 +#define IRONLAKE_LVDS_D_SSC_P_MAX 42 +#define IRONLAKE_LVDS_D_SSC_P1_MIN 2 +#define IRONLAKE_LVDS_D_SSC_P1_MAX 6 +#define IRONLAKE_LVDS_D_SSC_P2_SLOW 7 +#define IRONLAKE_LVDS_D_SSC_P2_FAST 7 + +/* DisplayPort */ +#define IRONLAKE_DP_N_MIN 1 +#define IRONLAKE_DP_N_MAX 2 +#define IRONLAKE_DP_M_MIN 81 +#define IRONLAKE_DP_M_MAX 90 +#define IRONLAKE_DP_P_MIN 10 +#define IRONLAKE_DP_P_MAX 20 +#define IRONLAKE_DP_P2_FAST 10 +#define IRONLAKE_DP_P2_SLOW 10 +#define IRONLAKE_DP_P2_LIMIT 0 +#define IRONLAKE_DP_P1_MIN 1 +#define IRONLAKE_DP_P1_MAX 2 + static bool intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *best_clock); static bool -intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *best_clock); -static bool intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *best_clock); -static bool -intel_ironlake_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *best_clock); static bool intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc, @@ -294,7 +347,6 @@ static const intel_limit_t intel_limits_i8xx_dvo = { .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, .p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST }, .find_pll = intel_find_best_PLL, - .find_reduced_pll = intel_find_best_reduced_PLL, }; static const intel_limit_t intel_limits_i8xx_lvds = { @@ -309,7 +361,6 @@ static const intel_limit_t intel_limits_i8xx_lvds = { .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, .p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST }, .find_pll = intel_find_best_PLL, - .find_reduced_pll = intel_find_best_reduced_PLL, }; static const intel_limit_t intel_limits_i9xx_sdvo = { @@ -324,7 +375,6 @@ static const intel_limit_t intel_limits_i9xx_sdvo = { .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, .find_pll = intel_find_best_PLL, - .find_reduced_pll = intel_find_best_reduced_PLL, }; static const intel_limit_t intel_limits_i9xx_lvds = { @@ -342,7 +392,6 @@ static const intel_limit_t intel_limits_i9xx_lvds = { .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST }, .find_pll = intel_find_best_PLL, - .find_reduced_pll = intel_find_best_reduced_PLL, }; /* below parameter and function is for G4X Chipset Family*/ @@ -360,7 +409,6 @@ static const intel_limit_t intel_limits_g4x_sdvo = { .p2_fast = G4X_P2_SDVO_FAST }, .find_pll = intel_g4x_find_best_PLL, - .find_reduced_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_g4x_hdmi = { @@ -377,7 +425,6 @@ static const intel_limit_t intel_limits_g4x_hdmi = { .p2_fast = G4X_P2_HDMI_DAC_FAST }, .find_pll = intel_g4x_find_best_PLL, - .find_reduced_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_g4x_single_channel_lvds = { @@ -402,7 +449,6 @@ static const intel_limit_t intel_limits_g4x_single_channel_lvds = { .p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST }, .find_pll = intel_g4x_find_best_PLL, - .find_reduced_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_g4x_dual_channel_lvds = { @@ -427,7 +473,6 @@ static const intel_limit_t intel_limits_g4x_dual_channel_lvds = { .p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST }, .find_pll = intel_g4x_find_best_PLL, - .find_reduced_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_g4x_display_port = { @@ -465,7 +510,6 @@ static const intel_limit_t intel_limits_pineview_sdvo = { .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, .find_pll = intel_find_best_PLL, - .find_reduced_pll = intel_find_best_reduced_PLL, }; static const intel_limit_t intel_limits_pineview_lvds = { @@ -481,46 +525,135 @@ static const intel_limit_t intel_limits_pineview_lvds = { .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW }, .find_pll = intel_find_best_PLL, - .find_reduced_pll = intel_find_best_reduced_PLL, }; -static const intel_limit_t intel_limits_ironlake_sdvo = { +static const intel_limit_t intel_limits_ironlake_dac = { + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, + .n = { .min = IRONLAKE_DAC_N_MIN, .max = IRONLAKE_DAC_N_MAX }, + .m = { .min = IRONLAKE_DAC_M_MIN, .max = IRONLAKE_DAC_M_MAX }, + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, + .p = { .min = IRONLAKE_DAC_P_MIN, .max = IRONLAKE_DAC_P_MAX }, + .p1 = { .min = IRONLAKE_DAC_P1_MIN, .max = IRONLAKE_DAC_P1_MAX }, + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, + .p2_slow = IRONLAKE_DAC_P2_SLOW, + .p2_fast = IRONLAKE_DAC_P2_FAST }, + .find_pll = intel_g4x_find_best_PLL, +}; + +static const intel_limit_t intel_limits_ironlake_single_lvds = { + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, + .n = { .min = IRONLAKE_LVDS_S_N_MIN, .max = IRONLAKE_LVDS_S_N_MAX }, + .m = { .min = IRONLAKE_LVDS_S_M_MIN, .max = IRONLAKE_LVDS_S_M_MAX }, + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, + .p = { .min = IRONLAKE_LVDS_S_P_MIN, .max = IRONLAKE_LVDS_S_P_MAX }, + .p1 = { .min = IRONLAKE_LVDS_S_P1_MIN, .max = IRONLAKE_LVDS_S_P1_MAX }, + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, + .p2_slow = IRONLAKE_LVDS_S_P2_SLOW, + .p2_fast = IRONLAKE_LVDS_S_P2_FAST }, + .find_pll = intel_g4x_find_best_PLL, +}; + +static const intel_limit_t intel_limits_ironlake_dual_lvds = { .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, - .n = { .min = IRONLAKE_N_MIN, .max = IRONLAKE_N_MAX }, - .m = { .min = IRONLAKE_M_MIN, .max = IRONLAKE_M_MAX }, + .n = { .min = IRONLAKE_LVDS_D_N_MIN, .max = IRONLAKE_LVDS_D_N_MAX }, + .m = { .min = IRONLAKE_LVDS_D_M_MIN, .max = IRONLAKE_LVDS_D_M_MAX }, .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, - .p = { .min = IRONLAKE_P_SDVO_DAC_MIN, .max = IRONLAKE_P_SDVO_DAC_MAX }, - .p1 = { .min = IRONLAKE_P1_MIN, .max = IRONLAKE_P1_MAX }, + .p = { .min = IRONLAKE_LVDS_D_P_MIN, .max = IRONLAKE_LVDS_D_P_MAX }, + .p1 = { .min = IRONLAKE_LVDS_D_P1_MIN, .max = IRONLAKE_LVDS_D_P1_MAX }, .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, - .p2_slow = IRONLAKE_P2_SDVO_DAC_SLOW, - .p2_fast = IRONLAKE_P2_SDVO_DAC_FAST }, - .find_pll = intel_ironlake_find_best_PLL, + .p2_slow = IRONLAKE_LVDS_D_P2_SLOW, + .p2_fast = IRONLAKE_LVDS_D_P2_FAST }, + .find_pll = intel_g4x_find_best_PLL, }; -static const intel_limit_t intel_limits_ironlake_lvds = { +static const intel_limit_t intel_limits_ironlake_single_lvds_100m = { .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, - .n = { .min = IRONLAKE_N_MIN, .max = IRONLAKE_N_MAX }, - .m = { .min = IRONLAKE_M_MIN, .max = IRONLAKE_M_MAX }, + .n = { .min = IRONLAKE_LVDS_S_SSC_N_MIN, .max = IRONLAKE_LVDS_S_SSC_N_MAX }, + .m = { .min = IRONLAKE_LVDS_S_SSC_M_MIN, .max = IRONLAKE_LVDS_S_SSC_M_MAX }, .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, - .p = { .min = IRONLAKE_P_LVDS_MIN, .max = IRONLAKE_P_LVDS_MAX }, - .p1 = { .min = IRONLAKE_P1_MIN, .max = IRONLAKE_P1_MAX }, + .p = { .min = IRONLAKE_LVDS_S_SSC_P_MIN, .max = IRONLAKE_LVDS_S_SSC_P_MAX }, + .p1 = { .min = IRONLAKE_LVDS_S_SSC_P1_MIN,.max = IRONLAKE_LVDS_S_SSC_P1_MAX }, .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, - .p2_slow = IRONLAKE_P2_LVDS_SLOW, - .p2_fast = IRONLAKE_P2_LVDS_FAST }, - .find_pll = intel_ironlake_find_best_PLL, + .p2_slow = IRONLAKE_LVDS_S_SSC_P2_SLOW, + .p2_fast = IRONLAKE_LVDS_S_SSC_P2_FAST }, + .find_pll = intel_g4x_find_best_PLL, +}; + +static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = { + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, + .n = { .min = IRONLAKE_LVDS_D_SSC_N_MIN, .max = IRONLAKE_LVDS_D_SSC_N_MAX }, + .m = { .min = IRONLAKE_LVDS_D_SSC_M_MIN, .max = IRONLAKE_LVDS_D_SSC_M_MAX }, + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, + .p = { .min = IRONLAKE_LVDS_D_SSC_P_MIN, .max = IRONLAKE_LVDS_D_SSC_P_MAX }, + .p1 = { .min = IRONLAKE_LVDS_D_SSC_P1_MIN,.max = IRONLAKE_LVDS_D_SSC_P1_MAX }, + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, + .p2_slow = IRONLAKE_LVDS_D_SSC_P2_SLOW, + .p2_fast = IRONLAKE_LVDS_D_SSC_P2_FAST }, + .find_pll = intel_g4x_find_best_PLL, +}; + +static const intel_limit_t intel_limits_ironlake_display_port = { + .dot = { .min = IRONLAKE_DOT_MIN, + .max = IRONLAKE_DOT_MAX }, + .vco = { .min = IRONLAKE_VCO_MIN, + .max = IRONLAKE_VCO_MAX}, + .n = { .min = IRONLAKE_DP_N_MIN, + .max = IRONLAKE_DP_N_MAX }, + .m = { .min = IRONLAKE_DP_M_MIN, + .max = IRONLAKE_DP_M_MAX }, + .m1 = { .min = IRONLAKE_M1_MIN, + .max = IRONLAKE_M1_MAX }, + .m2 = { .min = IRONLAKE_M2_MIN, + .max = IRONLAKE_M2_MAX }, + .p = { .min = IRONLAKE_DP_P_MIN, + .max = IRONLAKE_DP_P_MAX }, + .p1 = { .min = IRONLAKE_DP_P1_MIN, + .max = IRONLAKE_DP_P1_MAX}, + .p2 = { .dot_limit = IRONLAKE_DP_P2_LIMIT, + .p2_slow = IRONLAKE_DP_P2_SLOW, + .p2_fast = IRONLAKE_DP_P2_FAST }, + .find_pll = intel_find_pll_ironlake_dp, }; static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc) { + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; const intel_limit_t *limit; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) - limit = &intel_limits_ironlake_lvds; + int refclk = 120; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if (dev_priv->lvds_use_ssc && dev_priv->lvds_ssc_freq == 100) + refclk = 100; + + if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == + LVDS_CLKB_POWER_UP) { + /* LVDS dual channel */ + if (refclk == 100) + limit = &intel_limits_ironlake_dual_lvds_100m; + else + limit = &intel_limits_ironlake_dual_lvds; + } else { + if (refclk == 100) + limit = &intel_limits_ironlake_single_lvds_100m; + else + limit = &intel_limits_ironlake_single_lvds; + } + } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) || + HAS_eDP) + limit = &intel_limits_ironlake_display_port; else - limit = &intel_limits_ironlake_sdvo; + limit = &intel_limits_ironlake_dac; return limit; } @@ -737,46 +870,6 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, return (err != target); } - -static bool -intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *best_clock) - -{ - struct drm_device *dev = crtc->dev; - intel_clock_t clock; - int err = target; - bool found = false; - - memcpy(&clock, best_clock, sizeof(intel_clock_t)); - - for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { - for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++) { - /* m1 is always 0 in Pineview */ - if (clock.m2 >= clock.m1 && !IS_PINEVIEW(dev)) - break; - for (clock.n = limit->n.min; clock.n <= limit->n.max; - clock.n++) { - int this_err; - - intel_clock(dev, refclk, &clock); - - if (!intel_PLL_is_valid(crtc, &clock)) - continue; - - this_err = abs(clock.dot - target); - if (this_err < err) { - *best_clock = clock; - err = this_err; - found = true; - } - } - } - } - - return found; -} - static bool intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *best_clock) @@ -791,7 +884,13 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, found = false; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == + int lvds_reg; + + if (IS_IRONLAKE(dev)) + lvds_reg = PCH_LVDS; + else + lvds_reg = LVDS; + if ((I915_READ(lvds_reg) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) clock.p2 = limit->p2.p2_fast; else @@ -839,6 +938,11 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; intel_clock_t clock; + + /* return directly when it is eDP */ + if (HAS_eDP) + return true; + if (target < 200000) { clock.n = 1; clock.p1 = 2; @@ -857,68 +961,6 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc, return true; } -static bool -intel_ironlake_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *best_clock) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - intel_clock_t clock; - int err_most = 47; - int err_min = 10000; - - /* eDP has only 2 clock choice, no n/m/p setting */ - if (HAS_eDP) - return true; - - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) - return intel_find_pll_ironlake_dp(limit, crtc, target, - refclk, best_clock); - - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) - clock.p2 = limit->p2.p2_fast; - else - clock.p2 = limit->p2.p2_slow; - } else { - if (target < limit->p2.dot_limit) - clock.p2 = limit->p2.p2_slow; - else - clock.p2 = limit->p2.p2_fast; - } - - memset(best_clock, 0, sizeof(*best_clock)); - for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) { - /* based on hardware requriment prefer smaller n to precision */ - for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) { - /* based on hardware requirment prefere larger m1,m2 */ - for (clock.m1 = limit->m1.max; - clock.m1 >= limit->m1.min; clock.m1--) { - for (clock.m2 = limit->m2.max; - clock.m2 >= limit->m2.min; clock.m2--) { - int this_err; - - intel_clock(dev, refclk, &clock); - if (!intel_PLL_is_valid(crtc, &clock)) - continue; - this_err = abs((10000 - (target*10000/clock.dot))); - if (this_err < err_most) { - *best_clock = clock; - /* found on first matching */ - goto out; - } else if (this_err < err_min) { - *best_clock = clock; - err_min = this_err; - } - } - } - } - } -out: - return true; -} - /* DisplayPort has only two frequencies, 162MHz and 270MHz */ static bool intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc, @@ -989,6 +1031,8 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) /* enable it... */ fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC; + if (IS_I945GM(dev)) + fbc_ctl |= FBC_C3_IDLE; /* 945 needs special SR handling */ fbc_ctl |= (dev_priv->cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; if (obj_priv->tiling_mode != I915_TILING_NONE) @@ -1282,7 +1326,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return ret; } - ret = i915_gem_object_set_to_gtt_domain(obj, 1); + ret = i915_gem_object_set_to_display_plane(obj); if (ret != 0) { i915_gem_object_unpin(obj); mutex_unlock(&dev->struct_mutex); @@ -1493,6 +1537,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; u32 temp; int tries = 5, j, n; + u32 pipe_bpc; + + temp = I915_READ(pipeconf_reg); + pipe_bpc = temp & PIPE_BPC_MASK; /* XXX: When our outputs are all unaware of DPMS modes other than off * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. @@ -1524,6 +1572,12 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ temp = I915_READ(fdi_rx_reg); + /* + * make the BPC in FDI Rx be consistent with that in + * pipeconf reg. + */ + temp &= ~(0x7 << 16); + temp |= (pipe_bpc << 11); I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE | FDI_SEL_PCDCLK | FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */ @@ -1666,6 +1720,12 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) /* enable PCH transcoder */ temp = I915_READ(transconf_reg); + /* + * make the BPC in transcoder be consistent with + * that in pipeconf reg. + */ + temp &= ~PIPE_BPC_MASK; + temp |= pipe_bpc; I915_WRITE(transconf_reg, temp | TRANS_ENABLE); I915_READ(transconf_reg); @@ -1697,6 +1757,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) case DRM_MODE_DPMS_OFF: DRM_DEBUG_KMS("crtc %d dpms off\n", pipe); + drm_vblank_off(dev, pipe); /* Disable display plane */ temp = I915_READ(dspcntr_reg); if ((temp & DISPLAY_PLANE_ENABLE) != 0) { @@ -1745,6 +1806,9 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) I915_READ(fdi_tx_reg); temp = I915_READ(fdi_rx_reg); + /* BPC in FDI rx is consistent with that in pipeconf */ + temp &= ~(0x07 << 16); + temp |= (pipe_bpc << 11); I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE); I915_READ(fdi_rx_reg); @@ -1789,7 +1853,12 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) } } } - + temp = I915_READ(transconf_reg); + /* BPC in transcoder is consistent with that in pipeconf */ + temp &= ~PIPE_BPC_MASK; + temp |= pipe_bpc; + I915_WRITE(transconf_reg, temp); + I915_READ(transconf_reg); udelay(100); /* disable PCH DPLL */ @@ -2448,7 +2517,7 @@ static void pineview_enable_cxsr(struct drm_device *dev, unsigned long clock, * A value of 5us seems to be a good balance; safe for very low end * platforms but not overly aggressive on lower latency configs. */ -const static int latency_ns = 5000; +static const int latency_ns = 5000; static int i9xx_get_fifo_size(struct drm_device *dev, int plane) { @@ -2559,7 +2628,7 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock, /* Calc sr entries for one plane configs */ if (sr_hdisplay && (!planea_clock || !planeb_clock)) { /* self-refresh has much higher latency */ - const static int sr_latency_ns = 12000; + static const int sr_latency_ns = 12000; sr_clock = planea_clock ? planea_clock : planeb_clock; line_time_us = ((sr_hdisplay * 1000) / sr_clock); @@ -2570,6 +2639,10 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock, sr_entries = roundup(sr_entries / cacheline_size, 1); DRM_DEBUG("self-refresh entries: %d\n", sr_entries); I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); + } else { + /* Turn off self refresh if both pipes are enabled */ + I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) + & ~FW_BLC_SELF_EN); } DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n", @@ -2598,7 +2671,7 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock, /* Calc sr entries for one plane configs */ if (sr_hdisplay && (!planea_clock || !planeb_clock)) { /* self-refresh has much higher latency */ - const static int sr_latency_ns = 12000; + static const int sr_latency_ns = 12000; sr_clock = planea_clock ? planea_clock : planeb_clock; line_time_us = ((sr_hdisplay * 1000) / sr_clock); @@ -2613,6 +2686,10 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock, srwm = 1; srwm &= 0x3f; I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); + } else { + /* Turn off self refresh if both pipes are enabled */ + I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) + & ~FW_BLC_SELF_EN); } DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n", @@ -2667,7 +2744,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, if (HAS_FW_BLC(dev) && sr_hdisplay && (!planea_clock || !planeb_clock)) { /* self-refresh has much higher latency */ - const static int sr_latency_ns = 6000; + static const int sr_latency_ns = 6000; sr_clock = planea_clock ? planea_clock : planeb_clock; line_time_us = ((sr_hdisplay * 1000) / sr_clock); @@ -2681,6 +2758,10 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, if (srwm < 0) srwm = 1; I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f)); + } else { + /* Turn off self refresh if both pipes are enabled */ + I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) + & ~FW_BLC_SELF_EN); } DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", @@ -2906,10 +2987,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, return -EINVAL; } - if (is_lvds && limit->find_reduced_pll && - dev_priv->lvds_downclock_avail) { - memcpy(&reduced_clock, &clock, sizeof(intel_clock_t)); - has_reduced_clock = limit->find_reduced_pll(limit, crtc, + if (is_lvds && dev_priv->lvds_downclock_avail) { + has_reduced_clock = limit->find_pll(limit, crtc, dev_priv->lvds_downclock, refclk, &reduced_clock); @@ -2969,6 +3048,33 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* determine panel color depth */ temp = I915_READ(pipeconf_reg); + temp &= ~PIPE_BPC_MASK; + if (is_lvds) { + int lvds_reg = I915_READ(PCH_LVDS); + /* the BPC will be 6 if it is 18-bit LVDS panel */ + if ((lvds_reg & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) + temp |= PIPE_8BPC; + else + temp |= PIPE_6BPC; + } else if (is_edp) { + switch (dev_priv->edp_bpp/3) { + case 8: + temp |= PIPE_8BPC; + break; + case 10: + temp |= PIPE_10BPC; + break; + case 6: + temp |= PIPE_6BPC; + break; + case 12: + temp |= PIPE_12BPC; + break; + } + } else + temp |= PIPE_8BPC; + I915_WRITE(pipeconf_reg, temp); + I915_READ(pipeconf_reg); switch (temp & PIPE_BPC_MASK) { case PIPE_8BPC: @@ -3195,7 +3301,20 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, * appropriately here, but we need to look more thoroughly into how * panels behave in the two modes. */ - + /* set the dithering flag */ + if (IS_I965G(dev)) { + if (dev_priv->lvds_dither) { + if (IS_IRONLAKE(dev)) + pipeconf |= PIPE_ENABLE_DITHER; + else + lvds |= LVDS_ENABLE_DITHER; + } else { + if (IS_IRONLAKE(dev)) + pipeconf &= ~PIPE_ENABLE_DITHER; + else + lvds &= ~LVDS_ENABLE_DITHER; + } + } I915_WRITE(lvds_reg, lvds); I915_READ(lvds_reg); } @@ -3385,7 +3504,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, /* we only need to pin inside GTT if cursor is non-phy */ mutex_lock(&dev->struct_mutex); - if (!dev_priv->cursor_needs_physical) { + if (!dev_priv->info->cursor_needs_physical) { ret = i915_gem_object_pin(bo, PAGE_SIZE); if (ret) { DRM_ERROR("failed to pin cursor bo\n"); @@ -3420,7 +3539,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, I915_WRITE(base, addr); if (intel_crtc->cursor_bo) { - if (dev_priv->cursor_needs_physical) { + if (dev_priv->info->cursor_needs_physical) { if (intel_crtc->cursor_bo != bo) i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo); } else @@ -3779,125 +3898,6 @@ static void intel_gpu_idle_timer(unsigned long arg) queue_work(dev_priv->wq, &dev_priv->idle_work); } -void intel_increase_renderclock(struct drm_device *dev, bool schedule) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - if (IS_IRONLAKE(dev)) - return; - - if (!dev_priv->render_reclock_avail) { - DRM_DEBUG_DRIVER("not reclocking render clock\n"); - return; - } - - /* Restore render clock frequency to original value */ - if (IS_G4X(dev) || IS_I9XX(dev)) - pci_write_config_word(dev->pdev, GCFGC, dev_priv->orig_clock); - else if (IS_I85X(dev)) - pci_write_config_word(dev->pdev, HPLLCC, dev_priv->orig_clock); - DRM_DEBUG_DRIVER("increasing render clock frequency\n"); - - /* Schedule downclock */ - if (schedule) - mod_timer(&dev_priv->idle_timer, jiffies + - msecs_to_jiffies(GPU_IDLE_TIMEOUT)); -} - -void intel_decrease_renderclock(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - if (IS_IRONLAKE(dev)) - return; - - if (!dev_priv->render_reclock_avail) { - DRM_DEBUG_DRIVER("not reclocking render clock\n"); - return; - } - - if (IS_G4X(dev)) { - u16 gcfgc; - - /* Adjust render clock... */ - pci_read_config_word(dev->pdev, GCFGC, &gcfgc); - - /* Down to minimum... */ - gcfgc &= ~GM45_GC_RENDER_CLOCK_MASK; - gcfgc |= GM45_GC_RENDER_CLOCK_266_MHZ; - - pci_write_config_word(dev->pdev, GCFGC, gcfgc); - } else if (IS_I965G(dev)) { - u16 gcfgc; - - /* Adjust render clock... */ - pci_read_config_word(dev->pdev, GCFGC, &gcfgc); - - /* Down to minimum... */ - gcfgc &= ~I965_GC_RENDER_CLOCK_MASK; - gcfgc |= I965_GC_RENDER_CLOCK_267_MHZ; - - pci_write_config_word(dev->pdev, GCFGC, gcfgc); - } else if (IS_I945G(dev) || IS_I945GM(dev)) { - u16 gcfgc; - - /* Adjust render clock... */ - pci_read_config_word(dev->pdev, GCFGC, &gcfgc); - - /* Down to minimum... */ - gcfgc &= ~I945_GC_RENDER_CLOCK_MASK; - gcfgc |= I945_GC_RENDER_CLOCK_166_MHZ; - - pci_write_config_word(dev->pdev, GCFGC, gcfgc); - } else if (IS_I915G(dev)) { - u16 gcfgc; - - /* Adjust render clock... */ - pci_read_config_word(dev->pdev, GCFGC, &gcfgc); - - /* Down to minimum... */ - gcfgc &= ~I915_GC_RENDER_CLOCK_MASK; - gcfgc |= I915_GC_RENDER_CLOCK_166_MHZ; - - pci_write_config_word(dev->pdev, GCFGC, gcfgc); - } else if (IS_I85X(dev)) { - u16 hpllcc; - - /* Adjust render clock... */ - pci_read_config_word(dev->pdev, HPLLCC, &hpllcc); - - /* Up to maximum... */ - hpllcc &= ~GC_CLOCK_CONTROL_MASK; - hpllcc |= GC_CLOCK_133_200; - - pci_write_config_word(dev->pdev, HPLLCC, hpllcc); - } - DRM_DEBUG_DRIVER("decreasing render clock frequency\n"); -} - -/* Note that no increase function is needed for this - increase_renderclock() - * will also rewrite these bits - */ -void intel_decrease_displayclock(struct drm_device *dev) -{ - if (IS_IRONLAKE(dev)) - return; - - if (IS_I945G(dev) || IS_I945GM(dev) || IS_I915G(dev) || - IS_I915GM(dev)) { - u16 gcfgc; - - /* Adjust render clock... */ - pci_read_config_word(dev->pdev, GCFGC, &gcfgc); - - /* Down to minimum... */ - gcfgc &= ~0xf0; - gcfgc |= 0x80; - - pci_write_config_word(dev->pdev, GCFGC, gcfgc); - } -} - #define CRTC_IDLE_TIMEOUT 1000 /* ms */ static void intel_crtc_idle_timer(unsigned long arg) @@ -4011,12 +4011,6 @@ static void intel_idle_update(struct work_struct *work) mutex_lock(&dev->struct_mutex); - /* GPU isn't processing, downclock it. */ - if (!dev_priv->busy) { - intel_decrease_renderclock(dev); - intel_decrease_displayclock(dev); - } - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { /* Skip inactive CRTCs */ if (!crtc->fb) @@ -4050,13 +4044,11 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj) if (!drm_core_check_feature(dev, DRIVER_MODESET)) return; - if (!dev_priv->busy) { + if (!dev_priv->busy) dev_priv->busy = true; - intel_increase_renderclock(dev, true); - } else { + else mod_timer(&dev_priv->idle_timer, jiffies + msecs_to_jiffies(GPU_IDLE_TIMEOUT)); - } list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (!crtc->fb) @@ -4089,7 +4081,8 @@ static void intel_crtc_destroy(struct drm_crtc *crtc) struct intel_unpin_work { struct work_struct work; struct drm_device *dev; - struct drm_gem_object *obj; + struct drm_gem_object *old_fb_obj; + struct drm_gem_object *pending_flip_obj; struct drm_pending_vblank_event *event; int pending; }; @@ -4100,8 +4093,9 @@ static void intel_unpin_work_fn(struct work_struct *__work) container_of(__work, struct intel_unpin_work, work); mutex_lock(&work->dev->struct_mutex); - i915_gem_object_unpin(work->obj); - drm_gem_object_unreference(work->obj); + i915_gem_object_unpin(work->old_fb_obj); + drm_gem_object_unreference(work->pending_flip_obj); + drm_gem_object_unreference(work->old_fb_obj); mutex_unlock(&work->dev->struct_mutex); kfree(work); } @@ -4124,6 +4118,12 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe) spin_lock_irqsave(&dev->event_lock, flags); work = intel_crtc->unpin_work; if (work == NULL || !work->pending) { + if (work && !work->pending) { + obj_priv = work->pending_flip_obj->driver_private; + DRM_DEBUG_DRIVER("flip finish: %p (%d) not pending?\n", + obj_priv, + atomic_read(&obj_priv->pending_flip)); + } spin_unlock_irqrestore(&dev->event_lock, flags); return; } @@ -4144,8 +4144,11 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe) spin_unlock_irqrestore(&dev->event_lock, flags); - obj_priv = work->obj->driver_private; - if (atomic_dec_and_test(&obj_priv->pending_flip)) + obj_priv = work->pending_flip_obj->driver_private; + + /* Initial scanout buffer will have a 0 pending flip count */ + if ((atomic_read(&obj_priv->pending_flip) == 0) || + atomic_dec_and_test(&obj_priv->pending_flip)) DRM_WAKEUP(&dev_priv->pending_flip_queue); schedule_work(&work->work); } @@ -4158,8 +4161,11 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane) unsigned long flags; spin_lock_irqsave(&dev->event_lock, flags); - if (intel_crtc->unpin_work) + if (intel_crtc->unpin_work) { intel_crtc->unpin_work->pending = 1; + } else { + DRM_DEBUG_DRIVER("preparing flip with no unpin work?\n"); + } spin_unlock_irqrestore(&dev->event_lock, flags); } @@ -4175,7 +4181,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; unsigned long flags; - int ret; + int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC; + int ret, pipesrc; RING_LOCALS; work = kzalloc(sizeof *work, GFP_KERNEL); @@ -4187,12 +4194,13 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, work->event = event; work->dev = crtc->dev; intel_fb = to_intel_framebuffer(crtc->fb); - work->obj = intel_fb->obj; + work->old_fb_obj = intel_fb->obj; INIT_WORK(&work->work, intel_unpin_work_fn); /* We borrow the event spin lock for protecting unpin_work */ spin_lock_irqsave(&dev->event_lock, flags); if (intel_crtc->unpin_work) { + DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); spin_unlock_irqrestore(&dev->event_lock, flags); kfree(work); mutex_unlock(&dev->struct_mutex); @@ -4206,19 +4214,24 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, ret = intel_pin_and_fence_fb_obj(dev, obj); if (ret != 0) { + DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n", + obj->driver_private); kfree(work); + intel_crtc->unpin_work = NULL; mutex_unlock(&dev->struct_mutex); return ret; } - /* Reference the old fb object for the scheduled work. */ - drm_gem_object_reference(work->obj); + /* Reference the objects for the scheduled work. */ + drm_gem_object_reference(work->old_fb_obj); + drm_gem_object_reference(obj); crtc->fb = fb; i915_gem_object_flush_write_domain(obj); drm_vblank_get(dev, intel_crtc->pipe); obj_priv = obj->driver_private; atomic_inc(&obj_priv->pending_flip); + work->pending_flip_obj = obj; BEGIN_LP_RING(4); OUT_RING(MI_DISPLAY_FLIP | @@ -4226,7 +4239,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, OUT_RING(fb->pitch); if (IS_I965G(dev)) { OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode); - OUT_RING((fb->width << 16) | fb->height); + pipesrc = I915_READ(pipesrc_reg); + OUT_RING(pipesrc & 0x0fff0fff); } else { OUT_RING(obj_priv->gtt_offset); OUT_RING(MI_NOOP); @@ -4400,29 +4414,43 @@ static void intel_setup_outputs(struct drm_device *dev) bool found = false; if (I915_READ(SDVOB) & SDVO_DETECTED) { + DRM_DEBUG_KMS("probing SDVOB\n"); found = intel_sdvo_init(dev, SDVOB); - if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) + if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) { + DRM_DEBUG_KMS("probing HDMI on SDVOB\n"); intel_hdmi_init(dev, SDVOB); + } - if (!found && SUPPORTS_INTEGRATED_DP(dev)) + if (!found && SUPPORTS_INTEGRATED_DP(dev)) { + DRM_DEBUG_KMS("probing DP_B\n"); intel_dp_init(dev, DP_B); + } } /* Before G4X SDVOC doesn't have its own detect register */ - if (I915_READ(SDVOB) & SDVO_DETECTED) + if (I915_READ(SDVOB) & SDVO_DETECTED) { + DRM_DEBUG_KMS("probing SDVOC\n"); found = intel_sdvo_init(dev, SDVOC); + } if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) { - if (SUPPORTS_INTEGRATED_HDMI(dev)) + if (SUPPORTS_INTEGRATED_HDMI(dev)) { + DRM_DEBUG_KMS("probing HDMI on SDVOC\n"); intel_hdmi_init(dev, SDVOC); - if (SUPPORTS_INTEGRATED_DP(dev)) + } + if (SUPPORTS_INTEGRATED_DP(dev)) { + DRM_DEBUG_KMS("probing DP_C\n"); intel_dp_init(dev, DP_C); + } } - if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED)) + if (SUPPORTS_INTEGRATED_DP(dev) && + (I915_READ(DP_D) & DP_DETECTED)) { + DRM_DEBUG_KMS("probing DP_D\n"); intel_dp_init(dev, DP_D); + } } else if (IS_I8XX(dev)) intel_dvo_init(dev); @@ -4527,6 +4555,42 @@ static const struct drm_mode_config_funcs intel_mode_funcs = { .fb_changed = intelfb_probe, }; +static struct drm_gem_object * +intel_alloc_power_context(struct drm_device *dev) +{ + struct drm_gem_object *pwrctx; + int ret; + + pwrctx = drm_gem_object_alloc(dev, 4096); + if (!pwrctx) { + DRM_DEBUG("failed to alloc power context, RC6 disabled\n"); + return NULL; + } + + mutex_lock(&dev->struct_mutex); + ret = i915_gem_object_pin(pwrctx, 4096); + if (ret) { + DRM_ERROR("failed to pin power context: %d\n", ret); + goto err_unref; + } + + ret = i915_gem_object_set_to_gtt_domain(pwrctx, 1); + if (ret) { + DRM_ERROR("failed to set-domain on power context: %d\n", ret); + goto err_unpin; + } + mutex_unlock(&dev->struct_mutex); + + return pwrctx; + +err_unpin: + i915_gem_object_unpin(pwrctx); +err_unref: + drm_gem_object_unreference(pwrctx); + mutex_unlock(&dev->struct_mutex); + return NULL; +} + void intel_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -4579,42 +4643,27 @@ void intel_init_clock_gating(struct drm_device *dev) * GPU can automatically power down the render unit if given a page * to save state. */ - if (I915_HAS_RC6(dev)) { - struct drm_gem_object *pwrctx; - struct drm_i915_gem_object *obj_priv; - int ret; + if (I915_HAS_RC6(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) { + struct drm_i915_gem_object *obj_priv = NULL; if (dev_priv->pwrctx) { obj_priv = dev_priv->pwrctx->driver_private; } else { - pwrctx = drm_gem_object_alloc(dev, 4096); - if (!pwrctx) { - DRM_DEBUG("failed to alloc power context, " - "RC6 disabled\n"); - goto out; - } + struct drm_gem_object *pwrctx; - ret = i915_gem_object_pin(pwrctx, 4096); - if (ret) { - DRM_ERROR("failed to pin power context: %d\n", - ret); - drm_gem_object_unreference(pwrctx); - goto out; + pwrctx = intel_alloc_power_context(dev); + if (pwrctx) { + dev_priv->pwrctx = pwrctx; + obj_priv = pwrctx->driver_private; } - - i915_gem_object_set_to_gtt_domain(pwrctx, 1); - - dev_priv->pwrctx = pwrctx; - obj_priv = pwrctx->driver_private; } - I915_WRITE(PWRCTXA, obj_priv->gtt_offset | PWRCTX_EN); - I915_WRITE(MCHBAR_RENDER_STANDBY, - I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT); + if (obj_priv) { + I915_WRITE(PWRCTXA, obj_priv->gtt_offset | PWRCTX_EN); + I915_WRITE(MCHBAR_RENDER_STANDBY, + I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT); + } } - -out: - return; } /* Set up chip specific display functions */ @@ -4770,7 +4819,6 @@ void intel_modeset_cleanup(struct drm_device *dev) del_timer_sync(&intel_crtc->idle_timer); } - intel_increase_renderclock(dev, false); del_timer_sync(&dev_priv->idle_timer); if (dev_priv->display.disable_fbc) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 4e7aa8b..439506c 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -125,9 +125,15 @@ intel_dp_link_clock(uint8_t link_bw) /* I think this is a fiction */ static int -intel_dp_link_required(int pixel_clock) +intel_dp_link_required(struct drm_device *dev, + struct intel_output *intel_output, int pixel_clock) { - return pixel_clock * 3; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_eDP(intel_output)) + return (pixel_clock * dev_priv->edp_bpp) / 8; + else + return pixel_clock * 3; } static int @@ -138,7 +144,8 @@ intel_dp_mode_valid(struct drm_connector *connector, int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_output)); int max_lanes = intel_dp_max_lane_count(intel_output); - if (intel_dp_link_required(mode->clock) > max_link_clock * max_lanes) + if (intel_dp_link_required(connector->dev, intel_output, mode->clock) + > max_link_clock * max_lanes) return MODE_CLOCK_HIGH; if (mode->clock < 10000) @@ -492,7 +499,8 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, for (clock = 0; clock <= max_clock; clock++) { int link_avail = intel_dp_link_clock(bws[clock]) * lane_count; - if (intel_dp_link_required(mode->clock) <= link_avail) { + if (intel_dp_link_required(encoder->dev, intel_output, mode->clock) + <= link_avail) { dp_priv->link_bw = bws[clock]; dp_priv->lane_count = lane_count; adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw); @@ -1289,53 +1297,7 @@ intel_dp_hot_plug(struct intel_output *intel_output) if (dp_priv->dpms_mode == DRM_MODE_DPMS_ON) intel_dp_check_link_status(intel_output); } -/* - * Enumerate the child dev array parsed from VBT to check whether - * the given DP is present. - * If it is present, return 1. - * If it is not present, return false. - * If no child dev is parsed from VBT, it is assumed that the given - * DP is present. - */ -static int dp_is_present_in_vbt(struct drm_device *dev, int dp_reg) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct child_device_config *p_child; - int i, dp_port, ret; - - if (!dev_priv->child_dev_num) - return 1; - - dp_port = 0; - if (dp_reg == DP_B || dp_reg == PCH_DP_B) - dp_port = PORT_IDPB; - else if (dp_reg == DP_C || dp_reg == PCH_DP_C) - dp_port = PORT_IDPC; - else if (dp_reg == DP_D || dp_reg == PCH_DP_D) - dp_port = PORT_IDPD; - - ret = 0; - for (i = 0; i < dev_priv->child_dev_num; i++) { - p_child = dev_priv->child_dev + i; - /* - * If the device type is not DP, continue. - */ - if (p_child->device_type != DEVICE_TYPE_DP && - p_child->device_type != DEVICE_TYPE_eDP) - continue; - /* Find the eDP port */ - if (dp_reg == DP_A && p_child->device_type == DEVICE_TYPE_eDP) { - ret = 1; - break; - } - /* Find the DP port */ - if (p_child->dvo_port == dp_port) { - ret = 1; - break; - } - } - return ret; -} + void intel_dp_init(struct drm_device *dev, int output_reg) { @@ -1345,10 +1307,6 @@ intel_dp_init(struct drm_device *dev, int output_reg) struct intel_dp_priv *dp_priv; const char *name = NULL; - if (!dp_is_present_in_vbt(dev, output_reg)) { - DRM_DEBUG_KMS("DP is not present. Ignore it\n"); - return; - } intel_output = kcalloc(sizeof(struct intel_output) + sizeof(struct intel_dp_priv), 1, GFP_KERNEL); if (!intel_output) @@ -1373,11 +1331,10 @@ intel_dp_init(struct drm_device *dev, int output_reg) else if (output_reg == DP_D || output_reg == PCH_DP_D) intel_output->clone_mask = (1 << INTEL_DP_D_CLONE_BIT); - if (IS_eDP(intel_output)) { - intel_output->crtc_mask = (1 << 1); + if (IS_eDP(intel_output)) intel_output->clone_mask = (1 << INTEL_EDP_CLONE_BIT); - } else - intel_output->crtc_mask = (1 << 0) | (1 << 1); + + intel_output->crtc_mask = (1 << 0) | (1 << 1); connector->interlace_allowed = true; connector->doublescan_allowed = 0; @@ -1402,14 +1359,20 @@ intel_dp_init(struct drm_device *dev, int output_reg) break; case DP_B: case PCH_DP_B: + dev_priv->hotplug_supported_mask |= + HDMIB_HOTPLUG_INT_STATUS; name = "DPDDC-B"; break; case DP_C: case PCH_DP_C: + dev_priv->hotplug_supported_mask |= + HDMIC_HOTPLUG_INT_STATUS; name = "DPDDC-C"; break; case DP_D: case PCH_DP_D: + dev_priv->hotplug_supported_mask |= + HDMID_HOTPLUG_INT_STATUS; name = "DPDDC-D"; break; } diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 371d753..aaabbcb 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -148,7 +148,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_pin(fbo, PAGE_SIZE); + ret = i915_gem_object_pin(fbo, 64*1024); if (ret) { DRM_ERROR("failed to pin fb: %d\n", ret); goto out_unref; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index f04dbbe..0e268de 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -225,52 +225,6 @@ static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { .destroy = intel_hdmi_enc_destroy, }; -/* - * Enumerate the child dev array parsed from VBT to check whether - * the given HDMI is present. - * If it is present, return 1. - * If it is not present, return false. - * If no child dev is parsed from VBT, it assumes that the given - * HDMI is present. - */ -static int hdmi_is_present_in_vbt(struct drm_device *dev, int hdmi_reg) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct child_device_config *p_child; - int i, hdmi_port, ret; - - if (!dev_priv->child_dev_num) - return 1; - - if (hdmi_reg == SDVOB) - hdmi_port = DVO_B; - else if (hdmi_reg == SDVOC) - hdmi_port = DVO_C; - else if (hdmi_reg == HDMIB) - hdmi_port = DVO_B; - else if (hdmi_reg == HDMIC) - hdmi_port = DVO_C; - else if (hdmi_reg == HDMID) - hdmi_port = DVO_D; - else - return 0; - - ret = 0; - for (i = 0; i < dev_priv->child_dev_num; i++) { - p_child = dev_priv->child_dev + i; - /* - * If the device type is not HDMI, continue. - */ - if (p_child->device_type != DEVICE_TYPE_HDMI) - continue; - /* Find the HDMI port */ - if (p_child->dvo_port == hdmi_port) { - ret = 1; - break; - } - } - return ret; -} void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -278,10 +232,6 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) struct intel_output *intel_output; struct intel_hdmi_priv *hdmi_priv; - if (!hdmi_is_present_in_vbt(dev, sdvox_reg)) { - DRM_DEBUG_KMS("HDMI is not present. Ignored it \n"); - return; - } intel_output = kcalloc(sizeof(struct intel_output) + sizeof(struct intel_hdmi_priv), 1, GFP_KERNEL); if (!intel_output) @@ -303,21 +253,26 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) if (sdvox_reg == SDVOB) { intel_output->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT); intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB"); + dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; } else if (sdvox_reg == SDVOC) { intel_output->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT); intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC"); + dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMIB) { intel_output->clone_mask = (1 << INTEL_HDMID_CLONE_BIT); intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE, "HDMIB"); + dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMIC) { intel_output->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT); intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD, "HDMIC"); + dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMID) { intel_output->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT); intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF, "HDMID"); + dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; } if (!intel_output->ddc_bus) goto err_connector; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 3118ce2..c2e8a45 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -602,12 +602,47 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, /* Some lid devices report incorrect lid status, assume they're connected */ static const struct dmi_system_id bad_lid_status[] = { { + .ident = "Compaq nx9020", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_BOARD_NAME, "3084"), + }, + }, + { + .ident = "Samsung SX20S", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"), + DMI_MATCH(DMI_BOARD_NAME, "SX20S"), + }, + }, + { .ident = "Aspire One", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire one"), }, }, + { + .ident = "Aspire 1810T", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1810T"), + }, + }, + { + .ident = "PC-81005", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MALATA"), + DMI_MATCH(DMI_PRODUCT_NAME, "PC-81005"), + }, + }, + { + .ident = "Clevo M5x0N", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."), + DMI_MATCH(DMI_BOARD_NAME, "M5x0N"), + }, + }, { } }; @@ -622,7 +657,7 @@ static enum drm_connector_status intel_lvds_detect(struct drm_connector *connect { enum drm_connector_status status = connector_status_connected; - if (!acpi_lid_open() && !dmi_check_system(bad_lid_status)) + if (!dmi_check_system(bad_lid_status) && !acpi_lid_open()) status = connector_status_disconnected; return status; @@ -679,7 +714,14 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, struct drm_i915_private *dev_priv = container_of(nb, struct drm_i915_private, lid_notifier); struct drm_device *dev = dev_priv->dev; + struct drm_connector *connector = dev_priv->int_lvds_connector; + /* + * check and update the status of LVDS connector after receiving + * the LID nofication event. + */ + if (connector) + connector->status = connector->funcs->detect(connector); if (!acpi_lid_open()) { dev_priv->modeset_on_lid = 1; return NOTIFY_OK; @@ -854,65 +896,6 @@ static const struct dmi_system_id intel_no_lvds[] = { { } /* terminating entry */ }; -#ifdef CONFIG_ACPI -/* - * check_lid_device -- check whether @handle is an ACPI LID device. - * @handle: ACPI device handle - * @level : depth in the ACPI namespace tree - * @context: the number of LID device when we find the device - * @rv: a return value to fill if desired (Not use) - */ -static acpi_status -check_lid_device(acpi_handle handle, u32 level, void *context, - void **return_value) -{ - struct acpi_device *acpi_dev; - int *lid_present = context; - - acpi_dev = NULL; - /* Get the acpi device for device handle */ - if (acpi_bus_get_device(handle, &acpi_dev) || !acpi_dev) { - /* If there is no ACPI device for handle, return */ - return AE_OK; - } - - if (!strncmp(acpi_device_hid(acpi_dev), "PNP0C0D", 7)) - *lid_present = 1; - - return AE_OK; -} - -/** - * check whether there exists the ACPI LID device by enumerating the ACPI - * device tree. - */ -static int intel_lid_present(void) -{ - int lid_present = 0; - - if (acpi_disabled) { - /* If ACPI is disabled, there is no ACPI device tree to - * check, so assume the LID device would have been present. - */ - return 1; - } - - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, - check_lid_device, NULL, &lid_present, NULL); - - return lid_present; -} -#else -static int intel_lid_present(void) -{ - /* In the absence of ACPI built in, assume that the LID device would - * have been present. - */ - return 1; -} -#endif - /** * intel_find_lvds_downclock - find the reduced downclock for LVDS in EDID * @dev: drm device @@ -957,7 +940,8 @@ static void intel_find_lvds_downclock(struct drm_device *dev, } } mutex_unlock(&dev->mode_config.mutex); - if (temp_downclock < panel_fixed_mode->clock) { + if (temp_downclock < panel_fixed_mode->clock && + i915_lvds_downclock) { /* We found the downclock for LVDS. */ dev_priv->lvds_downclock_avail = 1; dev_priv->lvds_downclock = temp_downclock; @@ -1031,12 +1015,8 @@ void intel_lvds_init(struct drm_device *dev) if (dmi_check_system(intel_no_lvds)) return; - /* - * Assume LVDS is present if there's an ACPI lid device or if the - * device is present in the VBT. - */ - if (!lvds_is_present_in_vbt(dev) && !intel_lid_present()) { - DRM_DEBUG_KMS("LVDS is not present in VBT and no lid detected\n"); + if (!lvds_is_present_in_vbt(dev)) { + DRM_DEBUG_KMS("LVDS is not present in VBT\n"); return; } @@ -1180,6 +1160,8 @@ out: DRM_DEBUG_KMS("lid notifier registration failed\n"); dev_priv->lid_notifier.notifier_call = NULL; } + /* keep the LVDS connector */ + dev_priv->int_lvds_connector = connector; drm_sysfs_connector_add(connector); return; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 24a3dc9..82678d3 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -462,14 +462,63 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) } /** - * Don't check status code from this as it switches the bus back to the - * SDVO chips which defeats the purpose of doing a bus switch in the first - * place. + * Try to read the response after issuie the DDC switch command. But it + * is noted that we must do the action of reading response and issuing DDC + * switch command in one I2C transaction. Otherwise when we try to start + * another I2C transaction after issuing the DDC bus switch, it will be + * switched to the internal SDVO register. */ static void intel_sdvo_set_control_bus_switch(struct intel_output *intel_output, u8 target) { - intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + u8 out_buf[2], cmd_buf[2], ret_value[2], ret; + struct i2c_msg msgs[] = { + { + .addr = sdvo_priv->slave_addr >> 1, + .flags = 0, + .len = 2, + .buf = out_buf, + }, + /* the following two are to read the response */ + { + .addr = sdvo_priv->slave_addr >> 1, + .flags = 0, + .len = 1, + .buf = cmd_buf, + }, + { + .addr = sdvo_priv->slave_addr >> 1, + .flags = I2C_M_RD, + .len = 1, + .buf = ret_value, + }, + }; + + intel_sdvo_debug_write(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, + &target, 1); + /* write the DDC switch command argument */ + intel_sdvo_write_byte(intel_output, SDVO_I2C_ARG_0, target); + + out_buf[0] = SDVO_I2C_OPCODE; + out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH; + cmd_buf[0] = SDVO_I2C_CMD_STATUS; + cmd_buf[1] = 0; + ret_value[0] = 0; + ret_value[1] = 0; + + ret = i2c_transfer(intel_output->i2c_bus, msgs, 3); + if (ret != 3) { + /* failure in I2C transfer */ + DRM_DEBUG_KMS("I2c transfer returned %d\n", ret); + return; + } + if (ret_value[0] != SDVO_CMD_STATUS_SUCCESS) { + DRM_DEBUG_KMS("DDC switch command returns response %d\n", + ret_value[0]); + return; + } + return; } static bool intel_sdvo_set_target_input(struct intel_output *intel_output, bool target_0, bool target_1) @@ -1579,6 +1628,32 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response) edid = drm_get_edid(&intel_output->base, intel_output->ddc_bus); + /* This is only applied to SDVO cards with multiple outputs */ + if (edid == NULL && intel_sdvo_multifunc_encoder(intel_output)) { + uint8_t saved_ddc, temp_ddc; + saved_ddc = sdvo_priv->ddc_bus; + temp_ddc = sdvo_priv->ddc_bus >> 1; + /* + * Don't use the 1 as the argument of DDC bus switch to get + * the EDID. It is used for SDVO SPD ROM. + */ + while(temp_ddc > 1) { + sdvo_priv->ddc_bus = temp_ddc; + edid = drm_get_edid(&intel_output->base, + intel_output->ddc_bus); + if (edid) { + /* + * When we can get the EDID, maybe it is the + * correct DDC bus. Update it. + */ + sdvo_priv->ddc_bus = temp_ddc; + break; + } + temp_ddc >>= 1; + } + if (edid == NULL) + sdvo_priv->ddc_bus = saved_ddc; + } /* when there is no edid and no monitor is connected with VGA * port, try to use the CRT ddc to read the EDID for DVI-connector */ @@ -2270,6 +2345,14 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags) connector->connector_type = DRM_MODE_CONNECTOR_VGA; intel_output->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | (1 << INTEL_ANALOG_CLONE_BIT); + } else if (flags & SDVO_OUTPUT_CVBS0) { + + sdvo_priv->controlled_output = SDVO_OUTPUT_CVBS0; + encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; + connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; + sdvo_priv->is_tv = true; + intel_output->needs_tv_clock = true; + intel_output->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; } else if (flags & SDVO_OUTPUT_LVDS0) { sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0; @@ -2662,6 +2745,7 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) bool intel_sdvo_init(struct drm_device *dev, int output_device) { + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_connector *connector; struct intel_output *intel_output; struct intel_sdvo_priv *sdvo_priv; @@ -2708,10 +2792,12 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS"); sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA, "SDVOB/VGA DDC BUS"); + dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS; } else { intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS"); sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA, "SDVOC/VGA DDC BUS"); + dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; } if (intel_output->ddc_bus == NULL) diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index b1bc1ea..1175429 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -30,12 +30,11 @@ config DRM_NOUVEAU_DEBUG via debugfs. menu "I2C encoder or helper chips" - depends on DRM && I2C + depends on DRM && DRM_KMS_HELPER && I2C config DRM_I2C_CH7006 tristate "Chrontel ch7006 TV encoder" - depends on DRM_NOUVEAU - default m + default m if DRM_NOUVEAU help Support for Chrontel ch7006 and similar TV encoders, found on some nVidia video cards. diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 1cf4882..48227e7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -90,21 +90,21 @@ int nouveau_hybrid_setup(struct drm_device *dev) { int result; - if (nouveau_dsm(dev, NOUVEAU_DSM_ACTIVE, NOUVEAU_DSM_ACTIVE_QUERY, + if (nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STATE, &result)) return -ENODEV; NV_INFO(dev, "_DSM hardware status gave 0x%x\n", result); - if (result & 0x1) { /* Stamina mode - disable the external GPU */ + if (result) { /* Ensure that the external GPU is enabled */ + nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_SPEED, NULL); + nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_SPEED, + NULL); + } else { /* Stamina mode - disable the external GPU */ nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_STAMINA, NULL); nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STAMINA, NULL); - } else { /* Ensure that the external GPU is enabled */ - nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_SPEED, NULL); - nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_SPEED, - NULL); } return 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index ba14397..0e9cd1d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -310,63 +310,22 @@ valid_reg(struct nvbios *bios, uint32_t reg) struct drm_device *dev = bios->dev; /* C51 has misaligned regs on purpose. Marvellous */ - if (reg & 0x2 || (reg & 0x1 && dev_priv->VBIOS.pub.chip_version != 0x51)) { - NV_ERROR(dev, "========== misaligned reg 0x%08X ==========\n", - reg); - return 0; - } - /* - * Warn on C51 regs that have not been verified accessible in - * mmiotracing - */ + if (reg & 0x2 || + (reg & 0x1 && dev_priv->VBIOS.pub.chip_version != 0x51)) + NV_ERROR(dev, "======= misaligned reg 0x%08X =======\n", reg); + + /* warn on C51 regs that haven't been verified accessible in tracing */ if (reg & 0x1 && dev_priv->VBIOS.pub.chip_version == 0x51 && reg != 0x130d && reg != 0x1311 && reg != 0x60081d) NV_WARN(dev, "=== C51 misaligned reg 0x%08X not verified ===\n", reg); - /* Trust the init scripts on G80 */ - if (dev_priv->card_type >= NV_50) - return 1; - - #define WITHIN(x, y, z) ((x >= y) && (x < y + z)) - if (WITHIN(reg, NV_PMC_OFFSET, NV_PMC_SIZE)) - return 1; - if (WITHIN(reg, NV_PBUS_OFFSET, NV_PBUS_SIZE)) - return 1; - if (WITHIN(reg, NV_PFIFO_OFFSET, NV_PFIFO_SIZE)) - return 1; - if (dev_priv->VBIOS.pub.chip_version >= 0x30 && - (WITHIN(reg, 0x4000, 0x600) || reg == 0x00004600)) - return 1; - if (dev_priv->VBIOS.pub.chip_version >= 0x40 && - WITHIN(reg, 0xc000, 0x48)) - return 1; - if (dev_priv->VBIOS.pub.chip_version >= 0x17 && reg == 0x0000d204) - return 1; - if (dev_priv->VBIOS.pub.chip_version >= 0x40) { - if (reg == 0x00011014 || reg == 0x00020328) - return 1; - if (WITHIN(reg, 0x88000, NV_PBUS_SIZE)) /* new PBUS */ - return 1; + if (reg >= (8*1024*1024)) { + NV_ERROR(dev, "=== reg 0x%08x out of mapped bounds ===\n", reg); + return 0; } - if (WITHIN(reg, NV_PFB_OFFSET, NV_PFB_SIZE)) - return 1; - if (WITHIN(reg, NV_PEXTDEV_OFFSET, NV_PEXTDEV_SIZE)) - return 1; - if (WITHIN(reg, NV_PCRTC0_OFFSET, NV_PCRTC0_SIZE * 2)) - return 1; - if (WITHIN(reg, NV_PRAMDAC0_OFFSET, NV_PRAMDAC0_SIZE * 2)) - return 1; - if (dev_priv->VBIOS.pub.chip_version >= 0x17 && reg == 0x0070fff0) - return 1; - if (dev_priv->VBIOS.pub.chip_version == 0x51 && - WITHIN(reg, NV_PRAMIN_OFFSET, NV_PRAMIN_SIZE)) - return 1; - #undef WITHIN - - NV_ERROR(dev, "========== unknown reg 0x%08X ==========\n", reg); - return 0; + return 1; } static bool @@ -1906,7 +1865,7 @@ init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) struct drm_nouveau_private *dev_priv = bios->dev->dev_private; - if (dev_priv->card_type >= NV_50) + if (dev_priv->card_type >= NV_40) return 1; /* @@ -3196,16 +3155,25 @@ static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entr } #ifdef __powerpc__ /* Powerbook specific quirks */ - if (script == LVDS_RESET && ((dev->pci_device & 0xffff) == 0x0179 || (dev->pci_device & 0xffff) == 0x0329)) - nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72); - if ((dev->pci_device & 0xffff) == 0x0179 || (dev->pci_device & 0xffff) == 0x0189 || (dev->pci_device & 0xffff) == 0x0329) { - if (script == LVDS_PANEL_ON) { - bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) | (1 << 31)); - bios_wr32(bios, NV_PCRTC_GPIO_EXT, bios_rd32(bios, NV_PCRTC_GPIO_EXT) | 1); - } - if (script == LVDS_PANEL_OFF) { - bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) & ~(1 << 31)); - bios_wr32(bios, NV_PCRTC_GPIO_EXT, bios_rd32(bios, NV_PCRTC_GPIO_EXT) & ~3); + if ((dev->pci_device & 0xffff) == 0x0179 || + (dev->pci_device & 0xffff) == 0x0189 || + (dev->pci_device & 0xffff) == 0x0329) { + if (script == LVDS_RESET) { + nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72); + + } else if (script == LVDS_PANEL_ON) { + bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, + bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) + | (1 << 31)); + bios_wr32(bios, NV_PCRTC_GPIO_EXT, + bios_rd32(bios, NV_PCRTC_GPIO_EXT) | 1); + + } else if (script == LVDS_PANEL_OFF) { + bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, + bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) + & ~(1 << 31)); + bios_wr32(bios, NV_PCRTC_GPIO_EXT, + bios_rd32(bios, NV_PCRTC_GPIO_EXT) & ~3); } } #endif @@ -3797,7 +3765,6 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, */ struct drm_nouveau_private *dev_priv = dev->dev_private; - struct init_exec iexec = {true, false}; struct nvbios *bios = &dev_priv->VBIOS; uint8_t *table = &bios->data[bios->display.script_table_ptr]; uint8_t *otable = NULL; @@ -3877,8 +3844,6 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } } - bios->display.output = dcbent; - if (pxclk == 0) { script = ROM16(otable[6]); if (!script) { @@ -3887,7 +3852,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } NV_TRACE(dev, "0x%04X: parsing output script 0\n", script); - parse_init_table(bios, script, &iexec); + nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk == -1) { script = ROM16(otable[8]); @@ -3897,7 +3862,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } NV_TRACE(dev, "0x%04X: parsing output script 1\n", script); - parse_init_table(bios, script, &iexec); + nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk == -2) { if (table[4] >= 12) @@ -3910,7 +3875,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } NV_TRACE(dev, "0x%04X: parsing output script 2\n", script); - parse_init_table(bios, script, &iexec); + nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk > 0) { script = ROM16(otable[table[4] + i*6 + 2]); @@ -3922,7 +3887,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } NV_TRACE(dev, "0x%04X: parsing clock script 0\n", script); - parse_init_table(bios, script, &iexec); + nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk < 0) { script = ROM16(otable[table[4] + i*6 + 4]); @@ -3934,7 +3899,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } NV_TRACE(dev, "0x%04X: parsing clock script 1\n", script); - parse_init_table(bios, script, &iexec); + nouveau_bios_run_init_table(dev, script, dcbent); } return 0; @@ -5434,52 +5399,49 @@ static bool parse_dcb15_entry(struct drm_device *dev, struct parsed_dcb *dcb, uint32_t conn, uint32_t conf, struct dcb_entry *entry) { - if (conn != 0xf0003f00 && conn != 0xf2247f10 && conn != 0xf2204001 && - conn != 0xf2204301 && conn != 0xf2204311 && conn != 0xf2208001 && - conn != 0xf2244001 && conn != 0xf2244301 && conn != 0xf2244311 && - conn != 0xf4204011 && conn != 0xf4208011 && conn != 0xf4248011 && - conn != 0xf2045ff2 && conn != 0xf2045f14 && conn != 0xf207df14 && - conn != 0xf2205004 && conn != 0xf2209004) { - NV_ERROR(dev, "Unknown DCB 1.5 entry, please report\n"); - - /* cause output setting to fail for !TV, so message is seen */ - if ((conn & 0xf) != 0x1) - dcb->entries = 0; - - return false; - } - /* most of the below is a "best guess" atm */ - entry->type = conn & 0xf; - if (entry->type == 2) - /* another way of specifying straps based lvds... */ + switch (conn & 0x0000000f) { + case 0: + entry->type = OUTPUT_ANALOG; + break; + case 1: + entry->type = OUTPUT_TV; + break; + case 2: + case 3: entry->type = OUTPUT_LVDS; - if (entry->type == 4) { /* digital */ - if (conn & 0x10) - entry->type = OUTPUT_LVDS; - else + break; + case 4: + switch ((conn & 0x000000f0) >> 4) { + case 0: entry->type = OUTPUT_TMDS; + break; + case 1: + entry->type = OUTPUT_LVDS; + break; + default: + NV_ERROR(dev, "Unknown DCB subtype 4/%d\n", + (conn & 0x000000f0) >> 4); + return false; + } + break; + default: + NV_ERROR(dev, "Unknown DCB type %d\n", conn & 0x0000000f); + return false; } - /* what's in bits 5-13? could be some encoder maker thing, in tv case */ - entry->i2c_index = (conn >> 14) & 0xf; - /* raw heads field is in range 0-1, so move to 1-2 */ - entry->heads = ((conn >> 18) & 0x7) + 1; - entry->location = (conn >> 21) & 0xf; - /* unused: entry->bus = (conn >> 25) & 0x7; */ - /* set or to be same as heads -- hopefully safe enough */ - entry->or = entry->heads; + + entry->i2c_index = (conn & 0x0003c000) >> 14; + entry->heads = ((conn & 0x001c0000) >> 18) + 1; + entry->or = entry->heads; /* same as heads, hopefully safe enough */ + entry->location = (conn & 0x01e00000) >> 21; + entry->bus = (conn & 0x0e000000) >> 25; entry->duallink_possible = false; switch (entry->type) { case OUTPUT_ANALOG: entry->crtconf.maxfreq = (conf & 0xffff) * 10; break; - case OUTPUT_LVDS: - /* - * This is probably buried in conn's unknown bits. - * This will upset EDID-ful models, if they exist - */ - entry->lvdsconf.use_straps_for_mode = true; - entry->lvdsconf.use_power_scripts = true; + case OUTPUT_TV: + entry->tvconf.has_component_output = false; break; case OUTPUT_TMDS: /* @@ -5488,8 +5450,12 @@ parse_dcb15_entry(struct drm_device *dev, struct parsed_dcb *dcb, */ fabricate_vga_output(dcb, entry->i2c_index, entry->heads); break; - case OUTPUT_TV: - entry->tvconf.has_component_output = false; + case OUTPUT_LVDS: + if ((conn & 0x00003f00) != 0x10) + entry->lvdsconf.use_straps_for_mode = true; + entry->lvdsconf.use_power_scripts = true; + break; + default: break; } @@ -5564,11 +5530,13 @@ void merge_like_dcb_entries(struct drm_device *dev, struct parsed_dcb *dcb) dcb->entries = newentries; } -static int parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) +static int +parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) { + struct drm_nouveau_private *dev_priv = dev->dev_private; struct bios_parsed_dcb *bdcb = &bios->bdcb; struct parsed_dcb *dcb; - uint16_t dcbptr, i2ctabptr = 0; + uint16_t dcbptr = 0, i2ctabptr = 0; uint8_t *dcbtable; uint8_t headerlen = 0x4, entries = DCB_MAX_NUM_ENTRIES; bool configblock = true; @@ -5579,16 +5547,18 @@ static int parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool two dcb->entries = 0; /* get the offset from 0x36 */ - dcbptr = ROM16(bios->data[0x36]); + if (dev_priv->card_type > NV_04) { + dcbptr = ROM16(bios->data[0x36]); + if (dcbptr == 0x0000) + NV_WARN(dev, "No output data (DCB) found in BIOS\n"); + } + /* this situation likely means a really old card, pre DCB */ if (dcbptr == 0x0) { - NV_WARN(dev, "No output data (DCB) found in BIOS, " - "assuming a CRT output exists\n"); - /* this situation likely means a really old card, pre DCB */ + NV_INFO(dev, "Assuming a CRT output exists\n"); fabricate_vga_output(dcb, LEGACY_I2C_CRT, 1); - if (nv04_tv_identify(dev, - bios->legacy.i2c_indices.tv) >= 0) + if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0) fabricate_tv_output(dcb, twoHeads); return 0; @@ -5892,9 +5862,11 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table, struct nvbios *bios = &dev_priv->VBIOS; struct init_exec iexec = { true, false }; + mutex_lock(&bios->lock); bios->display.output = dcbent; parse_init_table(bios, table, &iexec); bios->display.output = NULL; + mutex_unlock(&bios->lock); } static bool NVInitVBIOS(struct drm_device *dev) @@ -5903,6 +5875,7 @@ static bool NVInitVBIOS(struct drm_device *dev) struct nvbios *bios = &dev_priv->VBIOS; memset(bios, 0, sizeof(struct nvbios)); + mutex_init(&bios->lock); bios->dev = dev; if (!NVShadowVBIOS(dev, bios->data)) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index 058e98c..fd94bd6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -205,6 +205,8 @@ struct nvbios { struct drm_device *dev; struct nouveau_bios_info pub; + struct mutex lock; + uint8_t data[NV_PROM_SIZE]; unsigned int length; bool execute; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 0cad6d8..028719f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -33,10 +33,13 @@ #include "nouveau_drv.h" #include "nouveau_dma.h" +#include <linux/log2.h> + static void nouveau_bo_del_ttm(struct ttm_buffer_object *bo) { struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + struct drm_device *dev = dev_priv->dev; struct nouveau_bo *nvbo = nouveau_bo(bo); ttm_bo_kunmap(&nvbo->kmap); @@ -44,12 +47,87 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) if (unlikely(nvbo->gem)) DRM_ERROR("bo %p still attached to GEM object\n", bo); + if (nvbo->tile) + nv10_mem_expire_tiling(dev, nvbo->tile, NULL); + spin_lock(&dev_priv->ttm.bo_list_lock); list_del(&nvbo->head); spin_unlock(&dev_priv->ttm.bo_list_lock); kfree(nvbo); } +static void +nouveau_bo_fixup_align(struct drm_device *dev, + uint32_t tile_mode, uint32_t tile_flags, + int *align, int *size) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + /* + * Some of the tile_flags have a periodic structure of N*4096 bytes, + * align to to that as well as the page size. Align the size to the + * appropriate boundaries. This does imply that sizes are rounded up + * 3-7 pages, so be aware of this and do not waste memory by allocating + * many small buffers. + */ + if (dev_priv->card_type == NV_50) { + uint32_t block_size = nouveau_mem_fb_amount(dev) >> 15; + int i; + + switch (tile_flags) { + case 0x1800: + case 0x2800: + case 0x4800: + case 0x7a00: + if (is_power_of_2(block_size)) { + for (i = 1; i < 10; i++) { + *align = 12 * i * block_size; + if (!(*align % 65536)) + break; + } + } else { + for (i = 1; i < 10; i++) { + *align = 8 * i * block_size; + if (!(*align % 65536)) + break; + } + } + *size = roundup(*size, *align); + break; + default: + break; + } + + } else { + if (tile_mode) { + if (dev_priv->chipset >= 0x40) { + *align = 65536; + *size = roundup(*size, 64 * tile_mode); + + } else if (dev_priv->chipset >= 0x30) { + *align = 32768; + *size = roundup(*size, 64 * tile_mode); + + } else if (dev_priv->chipset >= 0x20) { + *align = 16384; + *size = roundup(*size, 64 * tile_mode); + + } else if (dev_priv->chipset >= 0x10) { + *align = 16384; + *size = roundup(*size, 32 * tile_mode); + } + } + } + + /* ALIGN works only on powers of two. */ + *size = roundup(*size, PAGE_SIZE); + + if (dev_priv->card_type == NV_50) { + *size = roundup(*size, 65536); + *align = max(65536, *align); + } +} + int nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, int size, int align, uint32_t flags, uint32_t tile_mode, @@ -58,7 +136,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_bo *nvbo; - int ret, n = 0; + int ret = 0; nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL); if (!nvbo) @@ -70,59 +148,14 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, nvbo->tile_mode = tile_mode; nvbo->tile_flags = tile_flags; - /* - * Some of the tile_flags have a periodic structure of N*4096 bytes, - * align to to that as well as the page size. Overallocate memory to - * avoid corruption of other buffer objects. - */ - switch (tile_flags) { - case 0x1800: - case 0x2800: - case 0x4800: - case 0x7a00: - if (dev_priv->chipset >= 0xA0) { - /* This is based on high end cards with 448 bits - * memory bus, could be different elsewhere.*/ - size += 6 * 28672; - /* 8 * 28672 is the actual alignment requirement, - * but we must also align to page size. */ - align = 2 * 8 * 28672; - } else if (dev_priv->chipset >= 0x90) { - size += 3 * 16384; - align = 12 * 16834; - } else { - size += 3 * 8192; - /* 12 * 8192 is the actual alignment requirement, - * but we must also align to page size. */ - align = 2 * 12 * 8192; - } - break; - default: - break; - } - + nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size); align >>= PAGE_SHIFT; - size = (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); - if (dev_priv->card_type == NV_50) { - size = (size + 65535) & ~65535; - if (align < (65536 / PAGE_SIZE)) - align = (65536 / PAGE_SIZE); - } - - if (flags & TTM_PL_FLAG_VRAM) - nvbo->placements[n++] = TTM_PL_FLAG_VRAM | TTM_PL_MASK_CACHING; - if (flags & TTM_PL_FLAG_TT) - nvbo->placements[n++] = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; nvbo->placement.fpfn = 0; nvbo->placement.lpfn = mappable ? dev_priv->fb_mappable_pages : 0; - nvbo->placement.placement = nvbo->placements; - nvbo->placement.busy_placement = nvbo->placements; - nvbo->placement.num_placement = n; - nvbo->placement.num_busy_placement = n; + nouveau_bo_placement_set(nvbo, flags); nvbo->channel = chan; - nouveau_bo_placement_set(nvbo, flags); ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size, ttm_bo_type_device, &nvbo->placement, align, 0, false, NULL, size, nouveau_bo_del_ttm); @@ -421,6 +454,7 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) /* GPU-assisted copy using NV_MEMORY_TO_MEMORY_FORMAT, can access * TTM_PL_{VRAM,TT} directly. */ + static int nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, struct nouveau_bo *nvbo, bool evict, bool no_wait, @@ -435,6 +469,8 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, evict, no_wait, new_mem); + if (nvbo->channel && nvbo->channel != chan) + ret = nouveau_fence_wait(fence, NULL, false, false); nouveau_fence_unref((void *)&fence); return ret; } @@ -455,11 +491,12 @@ nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan, } static int -nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, int no_wait, - struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) +nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, + int no_wait, struct ttm_mem_reg *new_mem) { struct nouveau_bo *nvbo = nouveau_bo(bo); struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + struct ttm_mem_reg *old_mem = &bo->mem; struct nouveau_channel *chan; uint64_t src_offset, dst_offset; uint32_t page_count; @@ -547,7 +584,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, placement.fpfn = placement.lpfn = 0; placement.num_placement = placement.num_busy_placement = 1; - placement.placement = &placement_memtype; + placement.placement = placement.busy_placement = &placement_memtype; tmp_mem = *new_mem; tmp_mem.mm_node = NULL; @@ -559,7 +596,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, if (ret) goto out; - ret = nouveau_bo_move_m2mf(bo, true, no_wait, &bo->mem, &tmp_mem); + ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait, &tmp_mem); if (ret) goto out; @@ -585,7 +622,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, placement.fpfn = placement.lpfn = 0; placement.num_placement = placement.num_busy_placement = 1; - placement.placement = &placement_memtype; + placement.placement = placement.busy_placement = &placement_memtype; tmp_mem = *new_mem; tmp_mem.mm_node = NULL; @@ -597,7 +634,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, if (ret) goto out; - ret = nouveau_bo_move_m2mf(bo, true, no_wait, &bo->mem, new_mem); + ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait, new_mem); if (ret) goto out; @@ -612,52 +649,106 @@ out: } static int -nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, - bool no_wait, struct ttm_mem_reg *new_mem) +nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem, + struct nouveau_tile_reg **new_tile) { struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); - struct nouveau_bo *nvbo = nouveau_bo(bo); struct drm_device *dev = dev_priv->dev; - struct ttm_mem_reg *old_mem = &bo->mem; + struct nouveau_bo *nvbo = nouveau_bo(bo); + uint64_t offset; int ret; - if (dev_priv->card_type == NV_50 && new_mem->mem_type == TTM_PL_VRAM && - !nvbo->no_vm) { - uint64_t offset = new_mem->mm_node->start << PAGE_SHIFT; + if (nvbo->no_vm || new_mem->mem_type != TTM_PL_VRAM) { + /* Nothing to do. */ + *new_tile = NULL; + return 0; + } + + offset = new_mem->mm_node->start << PAGE_SHIFT; + if (dev_priv->card_type == NV_50) { ret = nv50_mem_vm_bind_linear(dev, offset + dev_priv->vm_vram_base, new_mem->size, nvbo->tile_flags, offset); if (ret) return ret; + + } else if (dev_priv->card_type >= NV_10) { + *new_tile = nv10_mem_set_tiling(dev, offset, new_mem->size, + nvbo->tile_mode); + } + + return 0; +} + +static void +nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo, + struct nouveau_tile_reg *new_tile, + struct nouveau_tile_reg **old_tile) +{ + struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + struct drm_device *dev = dev_priv->dev; + + if (dev_priv->card_type >= NV_10 && + dev_priv->card_type < NV_50) { + if (*old_tile) + nv10_mem_expire_tiling(dev, *old_tile, bo->sync_obj); + + *old_tile = new_tile; } +} + +static int +nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, + bool no_wait, struct ttm_mem_reg *new_mem) +{ + struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + struct nouveau_bo *nvbo = nouveau_bo(bo); + struct ttm_mem_reg *old_mem = &bo->mem; + struct nouveau_tile_reg *new_tile = NULL; + int ret = 0; + + ret = nouveau_bo_vm_bind(bo, new_mem, &new_tile); + if (ret) + return ret; + /* Software copy if the card isn't up and running yet. */ if (dev_priv->init_state != NOUVEAU_CARD_INIT_DONE || - !dev_priv->channel) - return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); + !dev_priv->channel) { + ret = ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); + goto out; + } + /* Fake bo copy. */ if (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm) { BUG_ON(bo->mem.mm_node != NULL); bo->mem = *new_mem; new_mem->mm_node = NULL; - return 0; + goto out; } - if (new_mem->mem_type == TTM_PL_SYSTEM) { - if (old_mem->mem_type == TTM_PL_SYSTEM) - return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); - if (nouveau_bo_move_flipd(bo, evict, intr, no_wait, new_mem)) - return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); - } else if (old_mem->mem_type == TTM_PL_SYSTEM) { - if (nouveau_bo_move_flips(bo, evict, intr, no_wait, new_mem)) - return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); - } else { - if (nouveau_bo_move_m2mf(bo, evict, no_wait, old_mem, new_mem)) - return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); - } + /* Hardware assisted copy. */ + if (new_mem->mem_type == TTM_PL_SYSTEM) + ret = nouveau_bo_move_flipd(bo, evict, intr, no_wait, new_mem); + else if (old_mem->mem_type == TTM_PL_SYSTEM) + ret = nouveau_bo_move_flips(bo, evict, intr, no_wait, new_mem); + else + ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait, new_mem); - return 0; + if (!ret) + goto out; + + /* Fallback to software copy. */ + ret = ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); + +out: + if (ret) + nouveau_bo_vm_cleanup(bo, NULL, &new_tile); + else + nouveau_bo_vm_cleanup(bo, new_tile, &nvbo->tile); + + return ret; } static int diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 9aaa972..2281f99 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -158,6 +158,8 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, return ret; } + nouveau_dma_pre_init(chan); + /* Locate channel's user control regs */ if (dev_priv->card_type < NV_40) user = NV03_USER(channel); @@ -235,47 +237,6 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, return 0; } -int -nouveau_channel_idle(struct nouveau_channel *chan) -{ - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine *engine = &dev_priv->engine; - uint32_t caches; - int idle; - - if (!chan) { - NV_ERROR(dev, "no channel...\n"); - return 1; - } - - caches = nv_rd32(dev, NV03_PFIFO_CACHES); - nv_wr32(dev, NV03_PFIFO_CACHES, caches & ~1); - - if (engine->fifo.channel_id(dev) != chan->id) { - struct nouveau_gpuobj *ramfc = - chan->ramfc ? chan->ramfc->gpuobj : NULL; - - if (!ramfc) { - NV_ERROR(dev, "No RAMFC for channel %d\n", chan->id); - return 1; - } - - engine->instmem.prepare_access(dev, false); - if (nv_ro32(dev, ramfc, 0) != nv_ro32(dev, ramfc, 1)) - idle = 0; - else - idle = 1; - engine->instmem.finish_access(dev); - } else { - idle = (nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET) == - nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT)); - } - - nv_wr32(dev, NV03_PFIFO_CACHES, caches); - return idle; -} - /* stops a fifo */ void nouveau_channel_free(struct nouveau_channel *chan) @@ -317,12 +278,11 @@ nouveau_channel_free(struct nouveau_channel *chan) /* Ensure the channel is no longer active on the GPU */ pfifo->reassign(dev, false); - if (pgraph->channel(dev) == chan) { - pgraph->fifo_access(dev, false); + pgraph->fifo_access(dev, false); + if (pgraph->channel(dev) == chan) pgraph->unload_context(dev); - pgraph->fifo_access(dev, true); - } pgraph->destroy_context(chan); + pgraph->fifo_access(dev, true); if (pfifo->channel_id(dev) == chan->id) { pfifo->disable(dev); @@ -414,7 +374,9 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, init->subchan[0].grclass = 0x0039; else init->subchan[0].grclass = 0x5039; - init->nr_subchan = 1; + init->subchan[1].handle = NvSw; + init->subchan[1].grclass = NV_SW; + init->nr_subchan = 2; /* Named memory object area */ ret = drm_gem_handle_create(file_priv, chan->notifier_bo->gem, diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 5a10deb..d2f6335 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -24,9 +24,12 @@ * */ +#include <acpi/button.h> + #include "drmP.h" #include "drm_edid.h" #include "drm_crtc_helper.h" + #include "nouveau_reg.h" #include "nouveau_drv.h" #include "nouveau_encoder.h" @@ -83,14 +86,17 @@ nouveau_encoder_connector_get(struct nouveau_encoder *encoder) static void nouveau_connector_destroy(struct drm_connector *drm_connector) { - struct nouveau_connector *connector = nouveau_connector(drm_connector); - struct drm_device *dev = connector->base.dev; + struct nouveau_connector *nv_connector = + nouveau_connector(drm_connector); + struct drm_device *dev; - NV_DEBUG_KMS(dev, "\n"); - - if (!connector) + if (!nv_connector) return; + dev = nv_connector->base.dev; + NV_DEBUG_KMS(dev, "\n"); + + kfree(nv_connector->edid); drm_sysfs_connector_remove(drm_connector); drm_connector_cleanup(drm_connector); kfree(drm_connector); @@ -233,10 +239,21 @@ nouveau_connector_detect(struct drm_connector *connector) if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS); if (nv_encoder && nv_connector->native_mode) { +#ifdef CONFIG_ACPI + if (!nouveau_ignorelid && !acpi_lid_open()) + return connector_status_disconnected; +#endif nouveau_connector_set_encoder(connector, nv_encoder); return connector_status_connected; } + /* Cleanup the previous EDID block. */ + if (nv_connector->edid) { + drm_mode_connector_update_edid_property(connector, NULL); + kfree(nv_connector->edid); + nv_connector->edid = NULL; + } + i2c = nouveau_connector_ddc_detect(connector, &nv_encoder); if (i2c) { nouveau_connector_ddc_prepare(connector, &flags); @@ -247,7 +264,7 @@ nouveau_connector_detect(struct drm_connector *connector) if (!nv_connector->edid) { NV_ERROR(dev, "DDC responded, but no EDID for %s\n", drm_get_connector_name(connector)); - return connector_status_disconnected; + goto detect_analog; } if (nv_encoder->dcb->type == OUTPUT_DP && @@ -281,6 +298,7 @@ nouveau_connector_detect(struct drm_connector *connector) return connector_status_connected; } +detect_analog: nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG); if (!nv_encoder) nv_encoder = find_encoder_by_type(connector, OUTPUT_TV); @@ -687,8 +705,12 @@ nouveau_connector_create_lvds(struct drm_device *dev, */ if (!nv_connector->edid && !nv_connector->native_mode && !dev_priv->VBIOS.pub.fp_no_ddc) { - nv_connector->edid = + struct edid *edid = (struct edid *)nouveau_bios_embedded_edid(dev); + if (edid) { + nv_connector->edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + *(nv_connector->edid) = *edid; + } } if (!nv_connector->edid) diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index 7035536..50d9e67 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -29,12 +29,22 @@ #include "nouveau_drv.h" #include "nouveau_dma.h" +void +nouveau_dma_pre_init(struct nouveau_channel *chan) +{ + chan->dma.max = (chan->pushbuf_bo->bo.mem.size >> 2) - 2; + chan->dma.put = 0; + chan->dma.cur = chan->dma.put; + chan->dma.free = chan->dma.max - chan->dma.cur; +} + int nouveau_dma_init(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *m2mf = NULL; + struct nouveau_gpuobj *nvsw = NULL; int ret, i; /* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */ @@ -47,6 +57,15 @@ nouveau_dma_init(struct nouveau_channel *chan) if (ret) return ret; + /* Create an NV_SW object for various sync purposes */ + ret = nouveau_gpuobj_sw_new(chan, NV_SW, &nvsw); + if (ret) + return ret; + + ret = nouveau_gpuobj_ref_add(dev, chan, NvSw, nvsw, NULL); + if (ret) + return ret; + /* NV_MEMORY_TO_MEMORY_FORMAT requires a notifier object */ ret = nouveau_notifier_alloc(chan, NvNotify0, 32, &chan->m2mf_ntfy); if (ret) @@ -64,12 +83,6 @@ nouveau_dma_init(struct nouveau_channel *chan) return ret; } - /* Initialise DMA vars */ - chan->dma.max = (chan->pushbuf_bo->bo.mem.size >> 2) - 2; - chan->dma.put = 0; - chan->dma.cur = chan->dma.put; - chan->dma.free = chan->dma.max - chan->dma.cur; - /* Insert NOPS for NOUVEAU_DMA_SKIPS */ ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); if (ret) @@ -87,6 +100,13 @@ nouveau_dma_init(struct nouveau_channel *chan) BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1); OUT_RING(chan, NvNotify0); + /* Initialise NV_SW */ + ret = RING_SPACE(chan, 2); + if (ret) + return ret; + BEGIN_RING(chan, NvSubSw, 0, 1); + OUT_RING(chan, NvSw); + /* Sit back and pray the channel works.. */ FIRE_RING(chan); @@ -106,47 +126,52 @@ OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords) chan->dma.cur += nr_dwords; } -static inline bool -READ_GET(struct nouveau_channel *chan, uint32_t *get) +/* Fetch and adjust GPU GET pointer + * + * Returns: + * value >= 0, the adjusted GET pointer + * -EINVAL if GET pointer currently outside main push buffer + * -EBUSY if timeout exceeded + */ +static inline int +READ_GET(struct nouveau_channel *chan, uint32_t *prev_get, uint32_t *timeout) { uint32_t val; val = nvchan_rd32(chan, chan->user_get); - if (val < chan->pushbuf_base || - val >= chan->pushbuf_base + chan->pushbuf_bo->bo.mem.size) { - /* meaningless to dma_wait() except to know whether the - * GPU has stalled or not - */ - *get = val; - return false; + + /* reset counter as long as GET is still advancing, this is + * to avoid misdetecting a GPU lockup if the GPU happens to + * just be processing an operation that takes a long time + */ + if (val != *prev_get) { + *prev_get = val; + *timeout = 0; + } + + if ((++*timeout & 0xff) == 0) { + DRM_UDELAY(1); + if (*timeout > 100000) + return -EBUSY; } - *get = (val - chan->pushbuf_base) >> 2; - return true; + if (val < chan->pushbuf_base || + val > chan->pushbuf_base + (chan->dma.max << 2)) + return -EINVAL; + + return (val - chan->pushbuf_base) >> 2; } int nouveau_dma_wait(struct nouveau_channel *chan, int size) { - uint32_t get, prev_get = 0, cnt = 0; - bool get_valid; + uint32_t prev_get = 0, cnt = 0; + int get; while (chan->dma.free < size) { - /* reset counter as long as GET is still advancing, this is - * to avoid misdetecting a GPU lockup if the GPU happens to - * just be processing an operation that takes a long time - */ - get_valid = READ_GET(chan, &get); - if (get != prev_get) { - prev_get = get; - cnt = 0; - } - - if ((++cnt & 0xff) == 0) { - DRM_UDELAY(1); - if (cnt > 100000) - return -EBUSY; - } + get = READ_GET(chan, &prev_get, &cnt); + if (unlikely(get == -EBUSY)) + return -EBUSY; /* loop until we have a usable GET pointer. the value * we read from the GPU may be outside the main ring if @@ -157,7 +182,7 @@ nouveau_dma_wait(struct nouveau_channel *chan, int size) * from the SKIPS area, so the code below doesn't have to deal * with some fun corner cases. */ - if (!get_valid || get < NOUVEAU_DMA_SKIPS) + if (unlikely(get == -EINVAL) || get < NOUVEAU_DMA_SKIPS) continue; if (get <= chan->dma.cur) { @@ -183,6 +208,19 @@ nouveau_dma_wait(struct nouveau_channel *chan, int size) * after processing the currently pending commands. */ OUT_RING(chan, chan->pushbuf_base | 0x20000000); + + /* wait for GET to depart from the skips area. + * prevents writing GET==PUT and causing a race + * condition that causes us to think the GPU is + * idle when it's not. + */ + do { + get = READ_GET(chan, &prev_get, &cnt); + if (unlikely(get == -EBUSY)) + return -EBUSY; + if (unlikely(get == -EINVAL)) + continue; + } while (get <= NOUVEAU_DMA_SKIPS); WRITE_PUT(NOUVEAU_DMA_SKIPS); /* we're now submitting commands at the start of diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h index 04e85d8..dabfd65 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.h +++ b/drivers/gpu/drm/nouveau/nouveau_dma.h @@ -46,10 +46,11 @@ /* Hardcoded object assignments to subchannels (subchannel id). */ enum { NvSubM2MF = 0, - NvSub2D = 1, - NvSubCtxSurf2D = 1, - NvSubGdiRect = 2, - NvSubImageBlit = 3 + NvSubSw = 1, + NvSub2D = 2, + NvSubCtxSurf2D = 2, + NvSubGdiRect = 3, + NvSubImageBlit = 4 }; /* Object handles. */ @@ -67,6 +68,7 @@ enum { NvClipRect = 0x8000000b, NvGdiRect = 0x8000000c, NvImageBlit = 0x8000000d, + NvSw = 0x8000000e, /* G80+ display objects */ NvEvoVRAM = 0x01000000, diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 9e2926c..f954ad9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -490,7 +490,8 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, if (!nv_wait(NV50_AUXCH_CTRL(index), 0x00010000, 0x00000000)) { NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n", nv_rd32(dev, NV50_AUXCH_CTRL(index))); - return -EBUSY; + ret = -EBUSY; + goto out; } udelay(400); @@ -502,6 +503,11 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, } if (cmd & 1) { + if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) { + ret = -EREMOTEIO; + goto out; + } + for (i = 0; i < 4; i++) { data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i)); NV_DEBUG_KMS(dev, "rd %d: 0x%08x\n", i, data32[i]); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 06eb993..da3b93b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -56,7 +56,7 @@ int nouveau_vram_pushbuf; module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); MODULE_PARM_DESC(vram_notify, "Force DMA notifiers to be in VRAM"); -int nouveau_vram_notify; +int nouveau_vram_notify = 1; module_param_named(vram_notify, nouveau_vram_notify, int, 0400); MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (>=GeForce 8)"); @@ -71,6 +71,18 @@ MODULE_PARM_DESC(uscript_tmds, "TMDS output script table ID (>=GeForce 8)"); int nouveau_uscript_tmds = -1; module_param_named(uscript_tmds, nouveau_uscript_tmds, int, 0400); +MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status"); +int nouveau_ignorelid = 0; +module_param_named(ignorelid, nouveau_ignorelid, int, 0400); + +MODULE_PARM_DESC(noagp, "Disable all acceleration"); +int nouveau_noaccel = 0; +module_param_named(noaccel, nouveau_noaccel, int, 0400); + +MODULE_PARM_DESC(noagp, "Disable fbcon acceleration"); +int nouveau_nofbaccel = 0; +module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400); + MODULE_PARM_DESC(tv_norm, "Default TV norm.\n" "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n" "\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n" diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 5f8cbb7..5445cef 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -59,11 +59,19 @@ struct nouveau_grctx; #define MAX_NUM_DCB_ENTRIES 16 #define NOUVEAU_MAX_CHANNEL_NR 128 +#define NOUVEAU_MAX_TILE_NR 15 #define NV50_VM_MAX_VRAM (2*1024*1024*1024ULL) #define NV50_VM_BLOCK (512*1024*1024ULL) #define NV50_VM_VRAM_NR (NV50_VM_MAX_VRAM / NV50_VM_BLOCK) +struct nouveau_tile_reg { + struct nouveau_fence *fence; + uint32_t addr; + uint32_t size; + bool used; +}; + struct nouveau_bo { struct ttm_buffer_object bo; struct ttm_placement placement; @@ -83,6 +91,7 @@ struct nouveau_bo { uint32_t tile_mode; uint32_t tile_flags; + struct nouveau_tile_reg *tile; struct drm_gem_object *gem; struct drm_file *cpu_filp; @@ -277,8 +286,13 @@ struct nouveau_timer_engine { }; struct nouveau_fb_engine { + int num_tiles; + int (*init)(struct drm_device *dev); void (*takedown)(struct drm_device *dev); + + void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch); }; struct nouveau_fifo_engine { @@ -292,6 +306,8 @@ struct nouveau_fifo_engine { void (*disable)(struct drm_device *); void (*enable)(struct drm_device *); bool (*reassign)(struct drm_device *, bool enable); + bool (*cache_flush)(struct drm_device *dev); + bool (*cache_pull)(struct drm_device *dev, bool enable); int (*channel_id)(struct drm_device *); @@ -330,6 +346,9 @@ struct nouveau_pgraph_engine { void (*destroy_context)(struct nouveau_channel *); int (*load_context)(struct nouveau_channel *); int (*unload_context)(struct drm_device *); + + void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch); }; struct nouveau_engine { @@ -490,6 +509,8 @@ struct drm_nouveau_private { void __iomem *ramin; uint32_t ramin_size; + struct nouveau_bo *vga_ram; + struct workqueue_struct *wq; struct work_struct irq_work; @@ -548,6 +569,12 @@ struct drm_nouveau_private { unsigned long sg_handle; } gart_info; + /* nv10-nv40 tiling regions */ + struct { + struct nouveau_tile_reg reg[NOUVEAU_MAX_TILE_NR]; + spinlock_t lock; + } tile; + /* G8x/G9x virtual address space */ uint64_t vm_gart_base; uint64_t vm_gart_size; @@ -650,6 +677,9 @@ extern char *nouveau_tv_norm; extern int nouveau_reg_debug; extern char *nouveau_vbios; extern int nouveau_ctxfw; +extern int nouveau_ignorelid; +extern int nouveau_nofbaccel; +extern int nouveau_noaccel; /* nouveau_state.c */ extern void nouveau_preclose(struct drm_device *dev, struct drm_file *); @@ -685,6 +715,13 @@ extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap); extern int nouveau_mem_init(struct drm_device *); extern int nouveau_mem_init_agp(struct drm_device *); extern void nouveau_mem_close(struct drm_device *); +extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev, + uint32_t addr, + uint32_t size, + uint32_t pitch); +extern void nv10_mem_expire_tiling(struct drm_device *dev, + struct nouveau_tile_reg *tile, + struct nouveau_fence *fence); extern int nv50_mem_vm_bind_linear(struct drm_device *, uint64_t virt, uint32_t size, uint32_t flags, uint64_t phys); @@ -713,7 +750,6 @@ extern int nouveau_channel_alloc(struct drm_device *dev, struct drm_file *file_priv, uint32_t fb_ctxdma, uint32_t tt_ctxdma); extern void nouveau_channel_free(struct nouveau_channel *); -extern int nouveau_channel_idle(struct nouveau_channel *chan); /* nouveau_object.c */ extern int nouveau_gpuobj_early_init(struct drm_device *); @@ -756,6 +792,8 @@ extern int nouveau_gpuobj_gart_dma_new(struct nouveau_channel *, uint32_t *o_ret); extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, int class, struct nouveau_gpuobj **); +extern int nouveau_gpuobj_sw_new(struct nouveau_channel *, int class, + struct nouveau_gpuobj **); extern int nouveau_ioctl_grobj_alloc(struct drm_device *, void *data, struct drm_file *); extern int nouveau_ioctl_gpuobj_free(struct drm_device *, void *data, @@ -804,6 +842,7 @@ nouveau_debugfs_channel_fini(struct nouveau_channel *chan) #endif /* nouveau_dma.c */ +extern void nouveau_dma_pre_init(struct nouveau_channel *); extern int nouveau_dma_init(struct nouveau_channel *); extern int nouveau_dma_wait(struct nouveau_channel *, int size); @@ -879,16 +918,22 @@ extern void nv04_fb_takedown(struct drm_device *); /* nv10_fb.c */ extern int nv10_fb_init(struct drm_device *); extern void nv10_fb_takedown(struct drm_device *); +extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t, + uint32_t, uint32_t); /* nv40_fb.c */ extern int nv40_fb_init(struct drm_device *); extern void nv40_fb_takedown(struct drm_device *); +extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t, + uint32_t, uint32_t); /* nv04_fifo.c */ extern int nv04_fifo_init(struct drm_device *); extern void nv04_fifo_disable(struct drm_device *); extern void nv04_fifo_enable(struct drm_device *); extern bool nv04_fifo_reassign(struct drm_device *, bool); +extern bool nv04_fifo_cache_flush(struct drm_device *); +extern bool nv04_fifo_cache_pull(struct drm_device *, bool); extern int nv04_fifo_channel_id(struct drm_device *); extern int nv04_fifo_create_context(struct nouveau_channel *); extern void nv04_fifo_destroy_context(struct nouveau_channel *); @@ -941,6 +986,8 @@ extern void nv10_graph_destroy_context(struct nouveau_channel *); extern int nv10_graph_load_context(struct nouveau_channel *); extern int nv10_graph_unload_context(struct drm_device *); extern void nv10_graph_context_switch(struct drm_device *); +extern void nv10_graph_set_region_tiling(struct drm_device *, int, uint32_t, + uint32_t, uint32_t); /* nv20_graph.c */ extern struct nouveau_pgraph_object_class nv20_graph_grclass[]; @@ -952,6 +999,8 @@ extern int nv20_graph_unload_context(struct drm_device *); extern int nv20_graph_init(struct drm_device *); extern void nv20_graph_takedown(struct drm_device *); extern int nv30_graph_init(struct drm_device *); +extern void nv20_graph_set_region_tiling(struct drm_device *, int, uint32_t, + uint32_t, uint32_t); /* nv40_graph.c */ extern struct nouveau_pgraph_object_class nv40_graph_grclass[]; @@ -963,6 +1012,8 @@ extern void nv40_graph_destroy_context(struct nouveau_channel *); extern int nv40_graph_load_context(struct nouveau_channel *); extern int nv40_graph_unload_context(struct drm_device *); extern void nv40_grctx_init(struct nouveau_grctx *); +extern void nv40_graph_set_region_tiling(struct drm_device *, int, uint32_t, + uint32_t, uint32_t); /* nv50_graph.c */ extern struct nouveau_pgraph_object_class nv50_graph_grclass[]; @@ -1030,8 +1081,7 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, /* nv04_dac.c */ extern int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry); -extern enum drm_connector_status nv17_dac_detect(struct drm_encoder *encoder, - struct drm_connector *connector); +extern uint32_t nv17_dac_sample_load(struct drm_encoder *encoder); extern int nv04_dac_output_offset(struct drm_encoder *encoder); extern void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable); @@ -1049,9 +1099,6 @@ extern int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry); /* nv17_tv.c */ extern int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry); -extern enum drm_connector_status nv17_tv_detect(struct drm_encoder *encoder, - struct drm_connector *connector, - uint32_t pin_mask); /* nv04_display.c */ extern int nv04_display_create(struct drm_device *); @@ -1290,14 +1337,14 @@ nv_two_reg_pll(struct drm_device *dev) return false; } -#define NV50_NVSW 0x0000506e -#define NV50_NVSW_DMA_SEMAPHORE 0x00000060 -#define NV50_NVSW_SEMAPHORE_OFFSET 0x00000064 -#define NV50_NVSW_SEMAPHORE_ACQUIRE 0x00000068 -#define NV50_NVSW_SEMAPHORE_RELEASE 0x0000006c -#define NV50_NVSW_DMA_VBLSEM 0x0000018c -#define NV50_NVSW_VBLSEM_OFFSET 0x00000400 -#define NV50_NVSW_VBLSEM_RELEASE_VALUE 0x00000404 -#define NV50_NVSW_VBLSEM_RELEASE 0x00000408 +#define NV_SW 0x0000506e +#define NV_SW_DMA_SEMAPHORE 0x00000060 +#define NV_SW_SEMAPHORE_OFFSET 0x00000064 +#define NV_SW_SEMAPHORE_ACQUIRE 0x00000068 +#define NV_SW_SEMAPHORE_RELEASE 0x0000006c +#define NV_SW_DMA_VBLSEM 0x0000018c +#define NV_SW_VBLSEM_OFFSET 0x00000400 +#define NV_SW_VBLSEM_RELEASE_VALUE 0x00000404 +#define NV_SW_VBLSEM_RELEASE 0x00000408 #endif /* __NOUVEAU_DRV_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 84af25c..ea879a2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -64,8 +64,7 @@ nouveau_fbcon_sync(struct fb_info *info) return 0; if (RING_SPACE(chan, 4)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); return 0; } @@ -86,8 +85,7 @@ nouveau_fbcon_sync(struct fb_info *info) } if (ret) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); return 0; } @@ -109,6 +107,34 @@ static struct fb_ops nouveau_fbcon_ops = { .fb_setcmap = drm_fb_helper_setcmap, }; +static struct fb_ops nv04_fbcon_ops = { + .owner = THIS_MODULE, + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_setcolreg = drm_fb_helper_setcolreg, + .fb_fillrect = nv04_fbcon_fillrect, + .fb_copyarea = nv04_fbcon_copyarea, + .fb_imageblit = nv04_fbcon_imageblit, + .fb_sync = nouveau_fbcon_sync, + .fb_pan_display = drm_fb_helper_pan_display, + .fb_blank = drm_fb_helper_blank, + .fb_setcmap = drm_fb_helper_setcmap, +}; + +static struct fb_ops nv50_fbcon_ops = { + .owner = THIS_MODULE, + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_setcolreg = drm_fb_helper_setcolreg, + .fb_fillrect = nv50_fbcon_fillrect, + .fb_copyarea = nv50_fbcon_copyarea, + .fb_imageblit = nv50_fbcon_imageblit, + .fb_sync = nouveau_fbcon_sync, + .fb_pan_display = drm_fb_helper_pan_display, + .fb_blank = drm_fb_helper_blank, + .fb_setcmap = drm_fb_helper_setcmap, +}; + static void nouveau_fbcon_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno) { @@ -212,11 +238,11 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, mode_cmd.bpp = surface_bpp; mode_cmd.pitch = mode_cmd.width * (mode_cmd.bpp >> 3); - mode_cmd.pitch = ALIGN(mode_cmd.pitch, 256); + mode_cmd.pitch = roundup(mode_cmd.pitch, 256); mode_cmd.depth = surface_depth; size = mode_cmd.pitch * mode_cmd.height; - size = ALIGN(size, PAGE_SIZE); + size = roundup(size, PAGE_SIZE); ret = nouveau_gem_new(dev, dev_priv->channel, size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000, false, true, &nvbo); @@ -269,8 +295,12 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, dev_priv->fbdev_info = info; strcpy(info->fix.id, "nouveaufb"); - info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | - FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_IMAGEBLIT; + if (nouveau_nofbaccel) + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_DISABLED; + else + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_IMAGEBLIT; info->fbops = &nouveau_fbcon_ops; info->fix.smem_start = dev->mode_config.fb_base + nvbo->bo.offset - dev_priv->vm_vram_base; @@ -318,13 +348,15 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, par->nouveau_fb = nouveau_fb; par->dev = dev; - if (dev_priv->channel) { + if (dev_priv->channel && !nouveau_nofbaccel) { switch (dev_priv->card_type) { case NV_50: nv50_fbcon_accel_init(info); + info->fbops = &nv50_fbcon_ops; break; default: nv04_fbcon_accel_init(info); + info->fbops = &nv04_fbcon_ops; break; }; } @@ -380,3 +412,12 @@ nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb) return 0; } + +void nouveau_fbcon_gpu_lockup(struct fb_info *info) +{ + struct nouveau_fbcon_par *par = info->par; + struct drm_device *dev = par->dev; + + NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); + info->flags |= FBINFO_HWACCEL_DISABLED; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index 8531140..f9c34e1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -40,8 +40,15 @@ int nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb); void nouveau_fbcon_restore(void); void nouveau_fbcon_zfill(struct drm_device *dev); +void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); +void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +void nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); int nv04_fbcon_accel_init(struct fb_info *info); +void nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +void nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); +void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); int nv50_fbcon_accel_init(struct fb_info *info); +void nouveau_fbcon_gpu_lockup(struct fb_info *info); #endif /* __NV50_FBCON_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index dacac9a..faddf53 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -142,7 +142,7 @@ nouveau_fence_emit(struct nouveau_fence *fence) list_add_tail(&fence->entry, &chan->fence.pending); spin_unlock_irqrestore(&chan->fence.lock, flags); - BEGIN_RING(chan, NvSubM2MF, USE_REFCNT ? 0x0050 : 0x0150, 1); + BEGIN_RING(chan, NvSubSw, USE_REFCNT ? 0x0050 : 0x0150, 1); OUT_RING(chan, fence->sequence); FIRE_RING(chan); diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 18fd8ac..70cc308 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -220,7 +220,6 @@ nouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains, } struct validate_op { - struct nouveau_fence *fence; struct list_head vram_list; struct list_head gart_list; struct list_head both_list; @@ -252,17 +251,11 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence) } static void -validate_fini(struct validate_op *op, bool success) +validate_fini(struct validate_op *op, struct nouveau_fence* fence) { - struct nouveau_fence *fence = op->fence; - - if (unlikely(!success)) - op->fence = NULL; - - validate_fini_list(&op->vram_list, op->fence); - validate_fini_list(&op->gart_list, op->fence); - validate_fini_list(&op->both_list, op->fence); - nouveau_fence_unref((void *)&fence); + validate_fini_list(&op->vram_list, fence); + validate_fini_list(&op->gart_list, fence); + validate_fini_list(&op->both_list, fence); } static int @@ -328,6 +321,7 @@ retry: else { NV_ERROR(dev, "invalid valid domains: 0x%08x\n", b->valid_domains); + list_add_tail(&nvbo->entry, &op->both_list); validate_fini(op, NULL); return -EINVAL; } @@ -420,10 +414,6 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, INIT_LIST_HEAD(&op->gart_list); INIT_LIST_HEAD(&op->both_list); - ret = nouveau_fence_new(chan, &op->fence, false); - if (ret) - return ret; - if (nr_buffers == 0) return 0; @@ -477,13 +467,14 @@ u_memcpya(uint64_t user, unsigned nmemb, unsigned size) static int nouveau_gem_pushbuf_reloc_apply(struct nouveau_channel *chan, int nr_bo, struct drm_nouveau_gem_pushbuf_bo *bo, - int nr_relocs, uint64_t ptr_relocs, - int nr_dwords, int first_dword, + unsigned nr_relocs, uint64_t ptr_relocs, + unsigned nr_dwords, unsigned first_dword, uint32_t *pushbuf, bool is_iomem) { struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL; struct drm_device *dev = chan->dev; - int ret = 0, i; + int ret = 0; + unsigned i; reloc = u_memcpya(ptr_relocs, nr_relocs, sizeof(*reloc)); if (IS_ERR(reloc)) @@ -541,6 +532,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, struct drm_nouveau_gem_pushbuf_bo *bo = NULL; struct nouveau_channel *chan; struct validate_op op; + struct nouveau_fence* fence = 0; uint32_t *pushbuf = NULL; int ret = 0, do_reloc = 0, i; @@ -597,7 +589,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, OUT_RINGp(chan, pushbuf, req->nr_dwords); - ret = nouveau_fence_emit(op.fence); + ret = nouveau_fence_new(chan, &fence, true); if (ret) { NV_ERROR(dev, "error fencing pushbuf: %d\n", ret); WIND_RING(chan); @@ -605,7 +597,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, } if (nouveau_gem_pushbuf_sync(chan)) { - ret = nouveau_fence_wait(op.fence, NULL, false, false); + ret = nouveau_fence_wait(fence, NULL, false, false); if (ret) { for (i = 0; i < req->nr_dwords; i++) NV_ERROR(dev, "0x%08x\n", pushbuf[i]); @@ -614,7 +606,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, } out: - validate_fini(&op, ret == 0); + validate_fini(&op, fence); + nouveau_fence_unref((void**)&fence); mutex_unlock(&dev->struct_mutex); kfree(pushbuf); kfree(bo); @@ -634,6 +627,7 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data, struct drm_gem_object *gem; struct nouveau_bo *pbbo; struct validate_op op; + struct nouveau_fence* fence = 0; int i, ret = 0, do_reloc = 0; NOUVEAU_CHECK_INITIALISED_WITH_RETURN; @@ -675,6 +669,18 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data, } pbbo = nouveau_gem_object(gem); + if ((req->offset & 3) || req->nr_dwords < 2 || + (unsigned long)req->offset > (unsigned long)pbbo->bo.mem.size || + (unsigned long)req->nr_dwords > + ((unsigned long)(pbbo->bo.mem.size - req->offset ) >> 2)) { + NV_ERROR(dev, "pb call misaligned or out of bounds: " + "%d + %d * 4 > %ld\n", + req->offset, req->nr_dwords, pbbo->bo.mem.size); + ret = -EINVAL; + drm_gem_object_unreference(gem); + goto out; + } + ret = ttm_bo_reserve(&pbbo->bo, false, false, true, chan->fence.sequence); if (ret) { @@ -772,7 +778,7 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data, OUT_RING(chan, 0); } - ret = nouveau_fence_emit(op.fence); + ret = nouveau_fence_new(chan, &fence, true); if (ret) { NV_ERROR(dev, "error fencing pushbuf: %d\n", ret); WIND_RING(chan); @@ -780,7 +786,8 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data, } out: - validate_fini(&op, ret == 0); + validate_fini(&op, fence); + nouveau_fence_unref((void**)&fence); mutex_unlock(&dev->struct_mutex); kfree(bo); @@ -918,7 +925,9 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, } if (req->flags & NOUVEAU_GEM_CPU_PREP_NOBLOCK) { + spin_lock(&nvbo->bo.lock); ret = ttm_bo_wait(&nvbo->bo, false, false, no_wait); + spin_unlock(&nvbo->bo.lock); } else { ret = ttm_bo_synccpu_write_grab(&nvbo->bo, no_wait); if (ret == 0) diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.c b/drivers/gpu/drm/nouveau/nouveau_grctx.c index 419f4c2..c7ebec6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_grctx.c +++ b/drivers/gpu/drm/nouveau/nouveau_grctx.c @@ -97,8 +97,8 @@ nouveau_grctx_prog_load(struct drm_device *dev) } pgraph->ctxvals = kmalloc(fw->size, GFP_KERNEL); - if (!pgraph->ctxprog) { - NV_ERROR(dev, "OOM copying ctxprog\n"); + if (!pgraph->ctxvals) { + NV_ERROR(dev, "OOM copying ctxvals\n"); release_firmware(fw); nouveau_grctx_fini(dev); return -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 370c72c..447f9f6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -211,6 +211,20 @@ nouveau_fifo_irq_handler(struct drm_device *dev) get + 4); } + if (status & NV_PFIFO_INTR_SEMAPHORE) { + uint32_t sem; + + status &= ~NV_PFIFO_INTR_SEMAPHORE; + nv_wr32(dev, NV03_PFIFO_INTR_0, + NV_PFIFO_INTR_SEMAPHORE); + + sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE); + nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); + + nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); + nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); + } + if (status) { NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", status, chid); @@ -483,6 +497,13 @@ nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource) if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { if (nouveau_pgraph_intr_swmthd(dev, &trap)) unhandled = 1; + } else if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) { + uint32_t v = nv_rd32(dev, 0x402000); + nv_wr32(dev, 0x402000, v); + + /* dump the error anyway for now: it's useful for + Gallium development */ + unhandled = 1; } else { unhandled = 1; } @@ -559,85 +580,99 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) static void nv50_pgraph_irq_handler(struct drm_device *dev) { - uint32_t status, nsource; + uint32_t status; - status = nv_rd32(dev, NV03_PGRAPH_INTR); - nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); + while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) { + uint32_t nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); - if (status & 0x00000001) { - nouveau_pgraph_intr_notify(dev, nsource); - status &= ~0x00000001; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001); - } + if (status & 0x00000001) { + nouveau_pgraph_intr_notify(dev, nsource); + status &= ~0x00000001; + nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001); + } - if (status & 0x00000010) { - nouveau_pgraph_intr_error(dev, nsource | - NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD); + if (status & 0x00000010) { + nouveau_pgraph_intr_error(dev, nsource | + NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD); - status &= ~0x00000010; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010); - } + status &= ~0x00000010; + nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010); + } - if (status & 0x00001000) { - nv_wr32(dev, 0x400500, 0x00000000); - nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); - nv_wr32(dev, NV40_PGRAPH_INTR_EN, nv_rd32(dev, - NV40_PGRAPH_INTR_EN) & ~NV_PGRAPH_INTR_CONTEXT_SWITCH); - nv_wr32(dev, 0x400500, 0x00010001); + if (status & 0x00001000) { + nv_wr32(dev, 0x400500, 0x00000000); + nv_wr32(dev, NV03_PGRAPH_INTR, + NV_PGRAPH_INTR_CONTEXT_SWITCH); + nv_wr32(dev, NV40_PGRAPH_INTR_EN, nv_rd32(dev, + NV40_PGRAPH_INTR_EN) & + ~NV_PGRAPH_INTR_CONTEXT_SWITCH); + nv_wr32(dev, 0x400500, 0x00010001); - nv50_graph_context_switch(dev); + nv50_graph_context_switch(dev); - status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; - } + status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; + } - if (status & 0x00100000) { - nouveau_pgraph_intr_error(dev, nsource | - NV03_PGRAPH_NSOURCE_DATA_ERROR); + if (status & 0x00100000) { + nouveau_pgraph_intr_error(dev, nsource | + NV03_PGRAPH_NSOURCE_DATA_ERROR); - status &= ~0x00100000; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000); - } + status &= ~0x00100000; + nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000); + } - if (status & 0x00200000) { - int r; - - nouveau_pgraph_intr_error(dev, nsource | - NV03_PGRAPH_NSOURCE_PROTECTION_ERROR); - - NV_ERROR(dev, "magic set 1:\n"); - for (r = 0x408900; r <= 0x408910; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r)); - nv_wr32(dev, 0x408900, nv_rd32(dev, 0x408904) | 0xc0000000); - for (r = 0x408e08; r <= 0x408e24; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r)); - nv_wr32(dev, 0x408e08, nv_rd32(dev, 0x408e08) | 0xc0000000); - - NV_ERROR(dev, "magic set 2:\n"); - for (r = 0x409900; r <= 0x409910; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r)); - nv_wr32(dev, 0x409900, nv_rd32(dev, 0x409904) | 0xc0000000); - for (r = 0x409e08; r <= 0x409e24; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r)); - nv_wr32(dev, 0x409e08, nv_rd32(dev, 0x409e08) | 0xc0000000); - - status &= ~0x00200000; - nv_wr32(dev, NV03_PGRAPH_NSOURCE, nsource); - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000); - } + if (status & 0x00200000) { + int r; + + nouveau_pgraph_intr_error(dev, nsource | + NV03_PGRAPH_NSOURCE_PROTECTION_ERROR); + + NV_ERROR(dev, "magic set 1:\n"); + for (r = 0x408900; r <= 0x408910; r += 4) + NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, + nv_rd32(dev, r)); + nv_wr32(dev, 0x408900, + nv_rd32(dev, 0x408904) | 0xc0000000); + for (r = 0x408e08; r <= 0x408e24; r += 4) + NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, + nv_rd32(dev, r)); + nv_wr32(dev, 0x408e08, + nv_rd32(dev, 0x408e08) | 0xc0000000); + + NV_ERROR(dev, "magic set 2:\n"); + for (r = 0x409900; r <= 0x409910; r += 4) + NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, + nv_rd32(dev, r)); + nv_wr32(dev, 0x409900, + nv_rd32(dev, 0x409904) | 0xc0000000); + for (r = 0x409e08; r <= 0x409e24; r += 4) + NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, + nv_rd32(dev, r)); + nv_wr32(dev, 0x409e08, + nv_rd32(dev, 0x409e08) | 0xc0000000); + + status &= ~0x00200000; + nv_wr32(dev, NV03_PGRAPH_NSOURCE, nsource); + nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000); + } - if (status) { - NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", status); - nv_wr32(dev, NV03_PGRAPH_INTR, status); - } + if (status) { + NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", + status); + nv_wr32(dev, NV03_PGRAPH_INTR, status); + } - { - const int isb = (1 << 16) | (1 << 0); + { + const int isb = (1 << 16) | (1 << 0); - if ((nv_rd32(dev, 0x400500) & isb) != isb) - nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | isb); + if ((nv_rd32(dev, 0x400500) & isb) != isb) + nv_wr32(dev, 0x400500, + nv_rd32(dev, 0x400500) | isb); + } } nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); + nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); } static void diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 5158a12..8f3a12f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -192,6 +192,92 @@ void nouveau_mem_release(struct drm_file *file_priv, struct mem_block *heap) } /* + * NV10-NV40 tiling helpers + */ + +static void +nv10_mem_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; + + tile->addr = addr; + tile->size = size; + tile->used = !!pitch; + nouveau_fence_unref((void **)&tile->fence); + + if (!pfifo->cache_flush(dev)) + return; + + pfifo->reassign(dev, false); + pfifo->cache_flush(dev); + pfifo->cache_pull(dev, false); + + nouveau_wait_for_idle(dev); + + pgraph->set_region_tiling(dev, i, addr, size, pitch); + pfb->set_region_tiling(dev, i, addr, size, pitch); + + pfifo->cache_pull(dev, true); + pfifo->reassign(dev, true); +} + +struct nouveau_tile_reg * +nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size, + uint32_t pitch) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + struct nouveau_tile_reg *tile = dev_priv->tile.reg, *found = NULL; + int i; + + spin_lock(&dev_priv->tile.lock); + + for (i = 0; i < pfb->num_tiles; i++) { + if (tile[i].used) + /* Tile region in use. */ + continue; + + if (tile[i].fence && + !nouveau_fence_signalled(tile[i].fence, NULL)) + /* Pending tile region. */ + continue; + + if (max(tile[i].addr, addr) < + min(tile[i].addr + tile[i].size, addr + size)) + /* Kill an intersecting tile region. */ + nv10_mem_set_region_tiling(dev, i, 0, 0, 0); + + if (pitch && !found) { + /* Free tile region. */ + nv10_mem_set_region_tiling(dev, i, addr, size, pitch); + found = &tile[i]; + } + } + + spin_unlock(&dev_priv->tile.lock); + + return found; +} + +void +nv10_mem_expire_tiling(struct drm_device *dev, struct nouveau_tile_reg *tile, + struct nouveau_fence *fence) +{ + if (fence) { + /* Mark it as pending. */ + tile->fence = fence; + nouveau_fence_ref(fence); + } + + tile->used = false; +} + +/* * NV50 VM helpers */ int @@ -297,9 +383,8 @@ void nouveau_mem_close(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - if (dev_priv->ttm.bdev.man[TTM_PL_PRIV0].has_type) - ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_PRIV0); - ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); + nouveau_bo_unpin(dev_priv->vga_ram); + nouveau_bo_ref(NULL, &dev_priv->vga_ram); ttm_bo_device_release(&dev_priv->ttm.bdev); @@ -513,6 +598,7 @@ nouveau_mem_init(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->ttm.bo_list); spin_lock_init(&dev_priv->ttm.bo_list_lock); + spin_lock_init(&dev_priv->tile.lock); dev_priv->fb_available_size = nouveau_mem_fb_amount(dev); @@ -535,6 +621,15 @@ nouveau_mem_init(struct drm_device *dev) return ret; } + ret = nouveau_bo_new(dev, NULL, 256*1024, 0, TTM_PL_FLAG_VRAM, + 0, 0, true, true, &dev_priv->vga_ram); + if (ret == 0) + ret = nouveau_bo_pin(dev_priv->vga_ram, TTM_PL_FLAG_VRAM); + if (ret) { + NV_WARN(dev, "failed to reserve VGA memory\n"); + nouveau_bo_ref(NULL, &dev_priv->vga_ram); + } + /* GART */ #if !defined(__powerpc__) && !defined(__ia64__) if (drm_device_is_agp(dev) && dev->agp) { @@ -566,6 +661,7 @@ nouveau_mem_init(struct drm_device *dev) dev_priv->fb_mtrr = drm_mtrr_add(drm_get_resource_start(dev, 1), drm_get_resource_len(dev, 1), DRM_MTRR_WC); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c index 6c66a34..d99dc08 100644 --- a/drivers/gpu/drm/nouveau/nouveau_notifier.c +++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c @@ -34,15 +34,20 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct nouveau_bo *ntfy = NULL; + uint32_t flags; int ret; - ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, nouveau_vram_notify ? - TTM_PL_FLAG_VRAM : TTM_PL_FLAG_TT, + if (nouveau_vram_notify) + flags = TTM_PL_FLAG_VRAM; + else + flags = TTM_PL_FLAG_TT; + + ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, flags, 0, 0x0000, false, true, &ntfy); if (ret) return ret; - ret = nouveau_bo_pin(ntfy, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(ntfy, flags); if (ret) goto out_err; @@ -128,6 +133,8 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, target = NV_DMA_TARGET_PCI; } else { target = NV_DMA_TARGET_AGP; + if (dev_priv->card_type >= NV_50) + offset += dev_priv->vm_gart_base; } } else { NV_ERROR(dev, "Bad DMA target, mem_type %d!\n", diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 93379bb..e7c100b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -881,15 +881,16 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, return 0; } -static int +int nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class, struct nouveau_gpuobj **gpuobj_ret) { - struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct drm_nouveau_private *dev_priv; struct nouveau_gpuobj *gpuobj; if (!chan || !gpuobj_ret || *gpuobj_ret != NULL) return -EINVAL; + dev_priv = chan->dev->dev_private; gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL); if (!gpuobj) diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index fa1b0e7..aa9b310 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -99,6 +99,7 @@ * the card will hang early on in the X init process. */ # define NV_PMC_ENABLE_UNK13 (1<<13) +#define NV40_PMC_GRAPH_UNITS 0x00001540 #define NV40_PMC_BACKLIGHT 0x000015f0 # define NV40_PMC_BACKLIGHT_MASK 0x001f0000 #define NV40_PMC_1700 0x00001700 @@ -349,19 +350,19 @@ #define NV04_PGRAPH_BLEND 0x00400824 #define NV04_PGRAPH_STORED_FMT 0x00400830 #define NV04_PGRAPH_PATT_COLORRAM 0x00400900 -#define NV40_PGRAPH_TILE0(i) (0x00400900 + (i*16)) -#define NV40_PGRAPH_TLIMIT0(i) (0x00400904 + (i*16)) -#define NV40_PGRAPH_TSIZE0(i) (0x00400908 + (i*16)) -#define NV40_PGRAPH_TSTATUS0(i) (0x0040090C + (i*16)) +#define NV20_PGRAPH_TILE(i) (0x00400900 + (i*16)) +#define NV20_PGRAPH_TLIMIT(i) (0x00400904 + (i*16)) +#define NV20_PGRAPH_TSIZE(i) (0x00400908 + (i*16)) +#define NV20_PGRAPH_TSTATUS(i) (0x0040090C + (i*16)) #define NV10_PGRAPH_TILE(i) (0x00400B00 + (i*16)) #define NV10_PGRAPH_TLIMIT(i) (0x00400B04 + (i*16)) #define NV10_PGRAPH_TSIZE(i) (0x00400B08 + (i*16)) #define NV10_PGRAPH_TSTATUS(i) (0x00400B0C + (i*16)) #define NV04_PGRAPH_U_RAM 0x00400D00 -#define NV47_PGRAPH_TILE0(i) (0x00400D00 + (i*16)) -#define NV47_PGRAPH_TLIMIT0(i) (0x00400D04 + (i*16)) -#define NV47_PGRAPH_TSIZE0(i) (0x00400D08 + (i*16)) -#define NV47_PGRAPH_TSTATUS0(i) (0x00400D0C + (i*16)) +#define NV47_PGRAPH_TILE(i) (0x00400D00 + (i*16)) +#define NV47_PGRAPH_TLIMIT(i) (0x00400D04 + (i*16)) +#define NV47_PGRAPH_TSIZE(i) (0x00400D08 + (i*16)) +#define NV47_PGRAPH_TSTATUS(i) (0x00400D0C + (i*16)) #define NV04_PGRAPH_V_RAM 0x00400D40 #define NV04_PGRAPH_W_RAM 0x00400D80 #define NV10_PGRAPH_COMBINER0_IN_ALPHA 0x00400E40 diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 4c7f1e4..ed15905 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -54,11 +54,12 @@ static void nouveau_sgdma_clear(struct ttm_backend *be) { struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; - struct drm_device *dev = nvbe->dev; - - NV_DEBUG(nvbe->dev, "\n"); + struct drm_device *dev; if (nvbe && nvbe->pages) { + dev = nvbe->dev; + NV_DEBUG(dev, "\n"); + if (nvbe->bound) be->func->unbind(be); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index e76ec2d..a4851af 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -76,6 +76,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; + engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv04_fifo_channel_id; engine->fifo.create_context = nv04_fifo_create_context; engine->fifo.destroy_context = nv04_fifo_destroy_context; @@ -100,6 +102,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv10_fb_init; engine->fb.takedown = nv10_fb_takedown; + engine->fb.set_region_tiling = nv10_fb_set_region_tiling; engine->graph.grclass = nv10_graph_grclass; engine->graph.init = nv10_graph_init; engine->graph.takedown = nv10_graph_takedown; @@ -109,12 +112,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.fifo_access = nv04_graph_fifo_access; engine->graph.load_context = nv10_graph_load_context; engine->graph.unload_context = nv10_graph_unload_context; + engine->graph.set_region_tiling = nv10_graph_set_region_tiling; engine->fifo.channels = 32; engine->fifo.init = nv10_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; + engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv10_fifo_channel_id; engine->fifo.create_context = nv10_fifo_create_context; engine->fifo.destroy_context = nv10_fifo_destroy_context; @@ -139,6 +145,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv10_fb_init; engine->fb.takedown = nv10_fb_takedown; + engine->fb.set_region_tiling = nv10_fb_set_region_tiling; engine->graph.grclass = nv20_graph_grclass; engine->graph.init = nv20_graph_init; engine->graph.takedown = nv20_graph_takedown; @@ -148,12 +155,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.fifo_access = nv04_graph_fifo_access; engine->graph.load_context = nv20_graph_load_context; engine->graph.unload_context = nv20_graph_unload_context; + engine->graph.set_region_tiling = nv20_graph_set_region_tiling; engine->fifo.channels = 32; engine->fifo.init = nv10_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; + engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv10_fifo_channel_id; engine->fifo.create_context = nv10_fifo_create_context; engine->fifo.destroy_context = nv10_fifo_destroy_context; @@ -178,6 +188,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv10_fb_init; engine->fb.takedown = nv10_fb_takedown; + engine->fb.set_region_tiling = nv10_fb_set_region_tiling; engine->graph.grclass = nv30_graph_grclass; engine->graph.init = nv30_graph_init; engine->graph.takedown = nv20_graph_takedown; @@ -187,12 +198,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.destroy_context = nv20_graph_destroy_context; engine->graph.load_context = nv20_graph_load_context; engine->graph.unload_context = nv20_graph_unload_context; + engine->graph.set_region_tiling = nv20_graph_set_region_tiling; engine->fifo.channels = 32; engine->fifo.init = nv10_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; + engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv10_fifo_channel_id; engine->fifo.create_context = nv10_fifo_create_context; engine->fifo.destroy_context = nv10_fifo_destroy_context; @@ -218,6 +232,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv40_fb_init; engine->fb.takedown = nv40_fb_takedown; + engine->fb.set_region_tiling = nv40_fb_set_region_tiling; engine->graph.grclass = nv40_graph_grclass; engine->graph.init = nv40_graph_init; engine->graph.takedown = nv40_graph_takedown; @@ -227,12 +242,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.destroy_context = nv40_graph_destroy_context; engine->graph.load_context = nv40_graph_load_context; engine->graph.unload_context = nv40_graph_unload_context; + engine->graph.set_region_tiling = nv40_graph_set_region_tiling; engine->fifo.channels = 32; engine->fifo.init = nv40_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; + engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv10_fifo_channel_id; engine->fifo.create_context = nv40_fifo_create_context; engine->fifo.destroy_context = nv40_fifo_destroy_context; @@ -292,6 +310,14 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) static unsigned int nouveau_vga_set_decode(void *priv, bool state) { + struct drm_device *dev = priv; + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->chipset >= 0x40) + nv_wr32(dev, 0x88054, state); + else + nv_wr32(dev, 0x1854, state); + if (state) return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; @@ -409,15 +435,19 @@ nouveau_card_init(struct drm_device *dev) if (ret) goto out_timer; - /* PGRAPH */ - ret = engine->graph.init(dev); - if (ret) - goto out_fb; + if (nouveau_noaccel) + engine->graph.accel_blocked = true; + else { + /* PGRAPH */ + ret = engine->graph.init(dev); + if (ret) + goto out_fb; - /* PFIFO */ - ret = engine->fifo.init(dev); - if (ret) - goto out_graph; + /* PFIFO */ + ret = engine->fifo.init(dev); + if (ret) + goto out_graph; + } /* this call irq_preinstall, register irq handler and * call irq_postinstall @@ -461,9 +491,11 @@ nouveau_card_init(struct drm_device *dev) out_irq: drm_irq_uninstall(dev); out_fifo: - engine->fifo.takedown(dev); + if (!nouveau_noaccel) + engine->fifo.takedown(dev); out_graph: - engine->graph.takedown(dev); + if (!nouveau_noaccel) + engine->graph.takedown(dev); out_fb: engine->fb.takedown(dev); out_timer: @@ -500,13 +532,16 @@ static void nouveau_card_takedown(struct drm_device *dev) dev_priv->channel = NULL; } - engine->fifo.takedown(dev); - engine->graph.takedown(dev); + if (!nouveau_noaccel) { + engine->fifo.takedown(dev); + engine->graph.takedown(dev); + } engine->fb.takedown(dev); engine->timer.takedown(dev); engine->mc.takedown(dev); mutex_lock(&dev->struct_mutex); + ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); mutex_unlock(&dev->struct_mutex); nouveau_sgdma_takedown(dev); @@ -624,7 +659,10 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev_priv->chipset = (reg0 & 0xff00000) >> 20; /* NV04 or NV05 */ } else if ((reg0 & 0xff00fff0) == 0x20004000) { - dev_priv->chipset = 0x04; + if (reg0 & 0x00f00000) + dev_priv->chipset = 0x05; + else + dev_priv->chipset = 0x04; } else dev_priv->chipset = 0xff; @@ -704,8 +742,8 @@ static void nouveau_close(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - /* In the case of an error dev_priv may not be be allocated yet */ - if (dev_priv && dev_priv->card_type) + /* In the case of an error dev_priv may not be allocated yet */ + if (dev_priv) nouveau_card_takedown(dev); } @@ -795,6 +833,15 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, case NOUVEAU_GETPARAM_VM_VRAM_BASE: getparam->value = dev_priv->vm_vram_base; break; + case NOUVEAU_GETPARAM_GRAPH_UNITS: + /* NV40 and NV50 versions are quite different, but register + * address is the same. User is supposed to know the card + * family anyway... */ + if (dev_priv->chipset >= 0x40) { + getparam->value = nv_rd32(dev, NV40_PMC_GRAPH_UNITS); + break; + } + /* FALLTHRU */ default: NV_ERROR(dev, "unknown parameter %lld\n", getparam->param); return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 187eb84..c385d50 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -28,45 +28,17 @@ #include "nouveau_drv.h" -static struct vm_operations_struct nouveau_ttm_vm_ops; -static const struct vm_operations_struct *ttm_vm_ops; - -static int -nouveau_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct ttm_buffer_object *bo = vma->vm_private_data; - int ret; - - if (unlikely(bo == NULL)) - return VM_FAULT_NOPAGE; - - ret = ttm_vm_ops->fault(vma, vmf); - return ret; -} - int nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma) { struct drm_file *file_priv = filp->private_data; struct drm_nouveau_private *dev_priv = file_priv->minor->dev->dev_private; - int ret; if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) return drm_mmap(filp, vma); - ret = ttm_bo_mmap(filp, vma, &dev_priv->ttm.bdev); - if (unlikely(ret != 0)) - return ret; - - if (unlikely(ttm_vm_ops == NULL)) { - ttm_vm_ops = vma->vm_ops; - nouveau_ttm_vm_ops = *ttm_vm_ops; - nouveau_ttm_vm_ops.fault = &nouveau_ttm_fault; - } - - vma->vm_ops = &nouveau_ttm_vm_ops; - return 0; + return ttm_bo_mmap(filp, vma, &dev_priv->ttm.bdev); } static int diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c index d9f3287..d0e038d 100644 --- a/drivers/gpu/drm/nouveau/nv04_dac.c +++ b/drivers/gpu/drm/nouveau/nv04_dac.c @@ -212,16 +212,15 @@ out: return connector_status_disconnected; } -enum drm_connector_status nv17_dac_detect(struct drm_encoder *encoder, - struct drm_connector *connector) +uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; - uint32_t testval, regoffset = nv04_dac_output_offset(encoder); + uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder); uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput, saved_rtest_ctrl, saved_gpio0, saved_gpio1, temp, routput; - int head, present = 0; + int head; #define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20) if (dcb->type == OUTPUT_TV) { @@ -287,13 +286,7 @@ enum drm_connector_status nv17_dac_detect(struct drm_encoder *encoder, temp | NV_PRAMDAC_TEST_CONTROL_TP_INS_EN_ASSERTED); msleep(5); - temp = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset); - - if (dcb->type == OUTPUT_TV) - present = (nv17_tv_detect(encoder, connector, temp) - == connector_status_connected); - else - present = temp & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI; + sample = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset); temp = NVReadRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL); NVWriteRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL, @@ -310,15 +303,25 @@ enum drm_connector_status nv17_dac_detect(struct drm_encoder *encoder, nv17_gpio_set(dev, DCB_GPIO_TVDAC1, saved_gpio1); nv17_gpio_set(dev, DCB_GPIO_TVDAC0, saved_gpio0); - if (present) { - NV_INFO(dev, "Load detected on output %c\n", '@' + ffs(dcb->or)); + return sample; +} + +static enum drm_connector_status +nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; + uint32_t sample = nv17_dac_sample_load(encoder); + + if (sample & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) { + NV_INFO(dev, "Load detected on output %c\n", + '@' + ffs(dcb->or)); return connector_status_connected; + } else { + return connector_status_disconnected; } - - return connector_status_disconnected; } - static bool nv04_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index 09a3107..fd01caa 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -27,7 +27,7 @@ #include "nouveau_dma.h" #include "nouveau_fbcon.h" -static void +void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) { struct nouveau_fbcon_par *par = info->par; @@ -39,8 +39,7 @@ nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) return; if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 4)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { @@ -55,21 +54,19 @@ nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) FIRE_RING(chan); } -static void +void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct nouveau_fbcon_par *par = info->par; struct drm_device *dev = par->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; - uint32_t color = ((uint32_t *) info->pseudo_palette)[rect->color]; if (info->state != FBINFO_STATE_RUNNING) return; if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 7)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { @@ -80,14 +77,18 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) BEGIN_RING(chan, NvSubGdiRect, 0x02fc, 1); OUT_RING(chan, (rect->rop != ROP_COPY) ? 1 : 3); BEGIN_RING(chan, NvSubGdiRect, 0x03fc, 1); - OUT_RING(chan, color); + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) + OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]); + else + OUT_RING(chan, rect->color); BEGIN_RING(chan, NvSubGdiRect, 0x0400, 2); OUT_RING(chan, (rect->dx << 16) | rect->dy); OUT_RING(chan, (rect->width << 16) | rect->height); FIRE_RING(chan); } -static void +void nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { struct nouveau_fbcon_par *par = info->par; @@ -109,8 +110,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) } if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 8)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { @@ -144,8 +144,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) int iter_len = dsize > 128 ? 128 : dsize; if (RING_SPACE(chan, iter_len + 1)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); cfb_imageblit(info, image); return; } @@ -184,6 +183,7 @@ nv04_fbcon_accel_init(struct fb_info *info) struct drm_device *dev = par->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; + const int sub = NvSubCtxSurf2D; int surface_fmt, pattern_fmt, rect_fmt; int ret; @@ -242,30 +242,29 @@ nv04_fbcon_accel_init(struct fb_info *info) return ret; if (RING_SPACE(chan, 49)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); return 0; } - BEGIN_RING(chan, 1, 0x0000, 1); + BEGIN_RING(chan, sub, 0x0000, 1); OUT_RING(chan, NvCtxSurf2D); - BEGIN_RING(chan, 1, 0x0184, 2); + BEGIN_RING(chan, sub, 0x0184, 2); OUT_RING(chan, NvDmaFB); OUT_RING(chan, NvDmaFB); - BEGIN_RING(chan, 1, 0x0300, 4); + BEGIN_RING(chan, sub, 0x0300, 4); OUT_RING(chan, surface_fmt); OUT_RING(chan, info->fix.line_length | (info->fix.line_length << 16)); OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base); OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base); - BEGIN_RING(chan, 1, 0x0000, 1); + BEGIN_RING(chan, sub, 0x0000, 1); OUT_RING(chan, NvRop); - BEGIN_RING(chan, 1, 0x0300, 1); + BEGIN_RING(chan, sub, 0x0300, 1); OUT_RING(chan, 0x55); - BEGIN_RING(chan, 1, 0x0000, 1); + BEGIN_RING(chan, sub, 0x0000, 1); OUT_RING(chan, NvImagePatt); - BEGIN_RING(chan, 1, 0x0300, 8); + BEGIN_RING(chan, sub, 0x0300, 8); OUT_RING(chan, pattern_fmt); #ifdef __BIG_ENDIAN OUT_RING(chan, 2); @@ -279,9 +278,9 @@ nv04_fbcon_accel_init(struct fb_info *info) OUT_RING(chan, ~0); OUT_RING(chan, ~0); - BEGIN_RING(chan, 1, 0x0000, 1); + BEGIN_RING(chan, sub, 0x0000, 1); OUT_RING(chan, NvClipRect); - BEGIN_RING(chan, 1, 0x0300, 2); + BEGIN_RING(chan, sub, 0x0300, 2); OUT_RING(chan, 0); OUT_RING(chan, (info->var.yres_virtual << 16) | info->var.xres_virtual); @@ -308,9 +307,6 @@ nv04_fbcon_accel_init(struct fb_info *info) FIRE_RING(chan); - info->fbops->fb_fillrect = nv04_fbcon_fillrect; - info->fbops->fb_copyarea = nv04_fbcon_copyarea; - info->fbops->fb_imageblit = nv04_fbcon_imageblit; return 0; } diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c index 0c3cd53..f31347b 100644 --- a/drivers/gpu/drm/nouveau/nv04_fifo.c +++ b/drivers/gpu/drm/nouveau/nv04_fifo.c @@ -71,6 +71,40 @@ nv04_fifo_reassign(struct drm_device *dev, bool enable) return (reassign == 1); } +bool +nv04_fifo_cache_flush(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; + uint64_t start = ptimer->read(dev); + + do { + if (nv_rd32(dev, NV03_PFIFO_CACHE1_GET) == + nv_rd32(dev, NV03_PFIFO_CACHE1_PUT)) + return true; + + } while (ptimer->read(dev) - start < 100000000); + + NV_ERROR(dev, "Timeout flushing the PFIFO cache.\n"); + + return false; +} + +bool +nv04_fifo_cache_pull(struct drm_device *dev, bool enable) +{ + uint32_t pull = nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0); + + if (enable) { + nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull | 1); + } else { + nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull & ~1); + nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0); + } + + return !!(pull & 1); +} + int nv04_fifo_channel_id(struct drm_device *dev) { diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c index d561d77..e260986 100644 --- a/drivers/gpu/drm/nouveau/nv04_graph.c +++ b/drivers/gpu/drm/nouveau/nv04_graph.c @@ -28,6 +28,10 @@ #include "nouveau_drv.h" static uint32_t nv04_graph_ctx_regs[] = { + 0x0040053c, + 0x00400544, + 0x00400540, + 0x00400548, NV04_PGRAPH_CTX_SWITCH1, NV04_PGRAPH_CTX_SWITCH2, NV04_PGRAPH_CTX_SWITCH3, @@ -102,69 +106,69 @@ static uint32_t nv04_graph_ctx_regs[] = { NV04_PGRAPH_PATT_COLOR0, NV04_PGRAPH_PATT_COLOR1, NV04_PGRAPH_PATT_COLORRAM+0x00, - NV04_PGRAPH_PATT_COLORRAM+0x01, - NV04_PGRAPH_PATT_COLORRAM+0x02, - NV04_PGRAPH_PATT_COLORRAM+0x03, NV04_PGRAPH_PATT_COLORRAM+0x04, - NV04_PGRAPH_PATT_COLORRAM+0x05, - NV04_PGRAPH_PATT_COLORRAM+0x06, - NV04_PGRAPH_PATT_COLORRAM+0x07, NV04_PGRAPH_PATT_COLORRAM+0x08, - NV04_PGRAPH_PATT_COLORRAM+0x09, - NV04_PGRAPH_PATT_COLORRAM+0x0A, - NV04_PGRAPH_PATT_COLORRAM+0x0B, - NV04_PGRAPH_PATT_COLORRAM+0x0C, - NV04_PGRAPH_PATT_COLORRAM+0x0D, - NV04_PGRAPH_PATT_COLORRAM+0x0E, - NV04_PGRAPH_PATT_COLORRAM+0x0F, + NV04_PGRAPH_PATT_COLORRAM+0x0c, NV04_PGRAPH_PATT_COLORRAM+0x10, - NV04_PGRAPH_PATT_COLORRAM+0x11, - NV04_PGRAPH_PATT_COLORRAM+0x12, - NV04_PGRAPH_PATT_COLORRAM+0x13, NV04_PGRAPH_PATT_COLORRAM+0x14, - NV04_PGRAPH_PATT_COLORRAM+0x15, - NV04_PGRAPH_PATT_COLORRAM+0x16, - NV04_PGRAPH_PATT_COLORRAM+0x17, NV04_PGRAPH_PATT_COLORRAM+0x18, - NV04_PGRAPH_PATT_COLORRAM+0x19, - NV04_PGRAPH_PATT_COLORRAM+0x1A, - NV04_PGRAPH_PATT_COLORRAM+0x1B, - NV04_PGRAPH_PATT_COLORRAM+0x1C, - NV04_PGRAPH_PATT_COLORRAM+0x1D, - NV04_PGRAPH_PATT_COLORRAM+0x1E, - NV04_PGRAPH_PATT_COLORRAM+0x1F, + NV04_PGRAPH_PATT_COLORRAM+0x1c, NV04_PGRAPH_PATT_COLORRAM+0x20, - NV04_PGRAPH_PATT_COLORRAM+0x21, - NV04_PGRAPH_PATT_COLORRAM+0x22, - NV04_PGRAPH_PATT_COLORRAM+0x23, NV04_PGRAPH_PATT_COLORRAM+0x24, - NV04_PGRAPH_PATT_COLORRAM+0x25, - NV04_PGRAPH_PATT_COLORRAM+0x26, - NV04_PGRAPH_PATT_COLORRAM+0x27, NV04_PGRAPH_PATT_COLORRAM+0x28, - NV04_PGRAPH_PATT_COLORRAM+0x29, - NV04_PGRAPH_PATT_COLORRAM+0x2A, - NV04_PGRAPH_PATT_COLORRAM+0x2B, - NV04_PGRAPH_PATT_COLORRAM+0x2C, - NV04_PGRAPH_PATT_COLORRAM+0x2D, - NV04_PGRAPH_PATT_COLORRAM+0x2E, - NV04_PGRAPH_PATT_COLORRAM+0x2F, + NV04_PGRAPH_PATT_COLORRAM+0x2c, NV04_PGRAPH_PATT_COLORRAM+0x30, - NV04_PGRAPH_PATT_COLORRAM+0x31, - NV04_PGRAPH_PATT_COLORRAM+0x32, - NV04_PGRAPH_PATT_COLORRAM+0x33, NV04_PGRAPH_PATT_COLORRAM+0x34, - NV04_PGRAPH_PATT_COLORRAM+0x35, - NV04_PGRAPH_PATT_COLORRAM+0x36, - NV04_PGRAPH_PATT_COLORRAM+0x37, NV04_PGRAPH_PATT_COLORRAM+0x38, - NV04_PGRAPH_PATT_COLORRAM+0x39, - NV04_PGRAPH_PATT_COLORRAM+0x3A, - NV04_PGRAPH_PATT_COLORRAM+0x3B, - NV04_PGRAPH_PATT_COLORRAM+0x3C, - NV04_PGRAPH_PATT_COLORRAM+0x3D, - NV04_PGRAPH_PATT_COLORRAM+0x3E, - NV04_PGRAPH_PATT_COLORRAM+0x3F, + NV04_PGRAPH_PATT_COLORRAM+0x3c, + NV04_PGRAPH_PATT_COLORRAM+0x40, + NV04_PGRAPH_PATT_COLORRAM+0x44, + NV04_PGRAPH_PATT_COLORRAM+0x48, + NV04_PGRAPH_PATT_COLORRAM+0x4c, + NV04_PGRAPH_PATT_COLORRAM+0x50, + NV04_PGRAPH_PATT_COLORRAM+0x54, + NV04_PGRAPH_PATT_COLORRAM+0x58, + NV04_PGRAPH_PATT_COLORRAM+0x5c, + NV04_PGRAPH_PATT_COLORRAM+0x60, + NV04_PGRAPH_PATT_COLORRAM+0x64, + NV04_PGRAPH_PATT_COLORRAM+0x68, + NV04_PGRAPH_PATT_COLORRAM+0x6c, + NV04_PGRAPH_PATT_COLORRAM+0x70, + NV04_PGRAPH_PATT_COLORRAM+0x74, + NV04_PGRAPH_PATT_COLORRAM+0x78, + NV04_PGRAPH_PATT_COLORRAM+0x7c, + NV04_PGRAPH_PATT_COLORRAM+0x80, + NV04_PGRAPH_PATT_COLORRAM+0x84, + NV04_PGRAPH_PATT_COLORRAM+0x88, + NV04_PGRAPH_PATT_COLORRAM+0x8c, + NV04_PGRAPH_PATT_COLORRAM+0x90, + NV04_PGRAPH_PATT_COLORRAM+0x94, + NV04_PGRAPH_PATT_COLORRAM+0x98, + NV04_PGRAPH_PATT_COLORRAM+0x9c, + NV04_PGRAPH_PATT_COLORRAM+0xa0, + NV04_PGRAPH_PATT_COLORRAM+0xa4, + NV04_PGRAPH_PATT_COLORRAM+0xa8, + NV04_PGRAPH_PATT_COLORRAM+0xac, + NV04_PGRAPH_PATT_COLORRAM+0xb0, + NV04_PGRAPH_PATT_COLORRAM+0xb4, + NV04_PGRAPH_PATT_COLORRAM+0xb8, + NV04_PGRAPH_PATT_COLORRAM+0xbc, + NV04_PGRAPH_PATT_COLORRAM+0xc0, + NV04_PGRAPH_PATT_COLORRAM+0xc4, + NV04_PGRAPH_PATT_COLORRAM+0xc8, + NV04_PGRAPH_PATT_COLORRAM+0xcc, + NV04_PGRAPH_PATT_COLORRAM+0xd0, + NV04_PGRAPH_PATT_COLORRAM+0xd4, + NV04_PGRAPH_PATT_COLORRAM+0xd8, + NV04_PGRAPH_PATT_COLORRAM+0xdc, + NV04_PGRAPH_PATT_COLORRAM+0xe0, + NV04_PGRAPH_PATT_COLORRAM+0xe4, + NV04_PGRAPH_PATT_COLORRAM+0xe8, + NV04_PGRAPH_PATT_COLORRAM+0xec, + NV04_PGRAPH_PATT_COLORRAM+0xf0, + NV04_PGRAPH_PATT_COLORRAM+0xf4, + NV04_PGRAPH_PATT_COLORRAM+0xf8, + NV04_PGRAPH_PATT_COLORRAM+0xfc, NV04_PGRAPH_PATTERN, 0x0040080c, NV04_PGRAPH_PATTERN_SHAPE, @@ -247,14 +251,6 @@ static uint32_t nv04_graph_ctx_regs[] = { 0x004004f8, 0x0040047c, 0x004004fc, - 0x0040053c, - 0x00400544, - 0x00400540, - 0x00400548, - 0x00400560, - 0x00400568, - 0x00400564, - 0x0040056c, 0x00400534, 0x00400538, 0x00400514, @@ -341,9 +337,8 @@ static uint32_t nv04_graph_ctx_regs[] = { 0x00400500, 0x00400504, NV04_PGRAPH_VALID1, - NV04_PGRAPH_VALID2 - - + NV04_PGRAPH_VALID2, + NV04_PGRAPH_DEBUG_3 }; struct graph_state { @@ -388,6 +383,18 @@ nv04_graph_context_switch(struct drm_device *dev) pgraph->fifo_access(dev, true); } +static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) { + if (nv04_graph_ctx_regs[i] == reg) + return &ctx->nv04[i]; + } + + return NULL; +} + int nv04_graph_create_context(struct nouveau_channel *chan) { struct graph_state *pgraph_ctx; @@ -398,15 +405,8 @@ int nv04_graph_create_context(struct nouveau_channel *chan) if (pgraph_ctx == NULL) return -ENOMEM; - /* dev_priv->fifos[channel].pgraph_ctx_user = channel << 24; */ - pgraph_ctx->nv04[0] = 0x0001ffff; - /* is it really needed ??? */ -#if 0 - dev_priv->fifos[channel].pgraph_ctx[1] = - nv_rd32(dev, NV_PGRAPH_DEBUG_4); - dev_priv->fifos[channel].pgraph_ctx[2] = - nv_rd32(dev, 0x004006b0); -#endif + *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31; + return 0; } @@ -429,9 +429,13 @@ int nv04_graph_load_context(struct nouveau_channel *chan) nv_wr32(dev, nv04_graph_ctx_regs[i], pgraph_ctx->nv04[i]); nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL, 0x10010100); - nv_wr32(dev, NV04_PGRAPH_CTX_USER, chan->id << 24); + + tmp = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff; + nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp | chan->id << 24); + tmp = nv_rd32(dev, NV04_PGRAPH_FFINTFC_ST2); nv_wr32(dev, NV04_PGRAPH_FFINTFC_ST2, tmp & 0x000fffff); + return 0; } @@ -494,7 +498,7 @@ int nv04_graph_init(struct drm_device *dev) nv_wr32(dev, NV04_PGRAPH_STATE , 0xFFFFFFFF); nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL , 0x10000100); tmp = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff; - tmp |= dev_priv->engine.fifo.channels << 24; + tmp |= (dev_priv->engine.fifo.channels - 1) << 24; nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp); /* These don't belong here, they're part of a per-channel context */ @@ -533,7 +537,7 @@ nv04_graph_mthd_set_operation(struct nouveau_channel *chan, int grclass, int mthd, uint32_t data) { struct drm_device *dev = chan->dev; - uint32_t instance = nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff; + uint32_t instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4; int subc = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; uint32_t tmp; @@ -547,7 +551,7 @@ nv04_graph_mthd_set_operation(struct nouveau_channel *chan, int grclass, return 0; } -static struct nouveau_pgraph_object_method nv04_graph_mthds_m2mf[] = { +static struct nouveau_pgraph_object_method nv04_graph_mthds_sw[] = { { 0x0150, nv04_graph_mthd_set_ref }, {} }; @@ -558,7 +562,7 @@ static struct nouveau_pgraph_object_method nv04_graph_mthds_set_operation[] = { }; struct nouveau_pgraph_object_class nv04_graph_grclass[] = { - { 0x0039, false, nv04_graph_mthds_m2mf }, + { 0x0039, false, NULL }, { 0x004a, false, nv04_graph_mthds_set_operation }, /* gdirect */ { 0x005f, false, nv04_graph_mthds_set_operation }, /* imageblit */ { 0x0061, false, nv04_graph_mthds_set_operation }, /* ifc */ @@ -574,6 +578,7 @@ struct nouveau_pgraph_object_class nv04_graph_grclass[] = { { 0x0053, false, NULL }, /* surf3d */ { 0x0054, false, NULL }, /* tex_tri */ { 0x0055, false, NULL }, /* multitex_tri */ + { 0x506e, true, nv04_graph_mthds_sw }, {} }; diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c index a20c206..a3b9563 100644 --- a/drivers/gpu/drm/nouveau/nv04_instmem.c +++ b/drivers/gpu/drm/nouveau/nv04_instmem.c @@ -30,7 +30,7 @@ nv04_instmem_determine_amount(struct drm_device *dev) * of vram. For now, only reserve a small piece until we know * more about what each chipset requires. */ - switch (dev_priv->chipset & 0xf0) { + switch (dev_priv->chipset) { case 0x40: case 0x47: case 0x49: diff --git a/drivers/gpu/drm/nouveau/nv10_fb.c b/drivers/gpu/drm/nouveau/nv10_fb.c index 79e2d10..cc5cda4 100644 --- a/drivers/gpu/drm/nouveau/nv10_fb.c +++ b/drivers/gpu/drm/nouveau/nv10_fb.c @@ -3,17 +3,37 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" +void +nv10_fb_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t limit = max(1u, addr + size) - 1; + + if (pitch) { + if (dev_priv->card_type >= NV_20) + addr |= 1; + else + addr |= 1 << 31; + } + + nv_wr32(dev, NV10_PFB_TLIMIT(i), limit); + nv_wr32(dev, NV10_PFB_TSIZE(i), pitch); + nv_wr32(dev, NV10_PFB_TILE(i), addr); +} + int nv10_fb_init(struct drm_device *dev) { - uint32_t fb_bar_size; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; int i; - fb_bar_size = drm_get_resource_len(dev, 0) - 1; - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) { - nv_wr32(dev, NV10_PFB_TILE(i), 0); - nv_wr32(dev, NV10_PFB_TLIMIT(i), fb_bar_size); - } + pfb->num_tiles = NV10_PFB_TILE__SIZE; + + /* Turn all the tiling regions off. */ + for (i = 0; i < pfb->num_tiles; i++) + pfb->set_region_tiling(dev, i, 0, 0, 0); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c index 6870e0e..fcf2cdd 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -807,6 +807,20 @@ void nv10_graph_destroy_context(struct nouveau_channel *chan) chan->pgraph_ctx = NULL; } +void +nv10_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch) +{ + uint32_t limit = max(1u, addr + size) - 1; + + if (pitch) + addr |= 1 << 31; + + nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), limit); + nv_wr32(dev, NV10_PGRAPH_TSIZE(i), pitch); + nv_wr32(dev, NV10_PGRAPH_TILE(i), addr); +} + int nv10_graph_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -838,17 +852,9 @@ int nv10_graph_init(struct drm_device *dev) } else nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00000000); - /* copy tile info from PFB */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) { - nv_wr32(dev, NV10_PGRAPH_TILE(i), - nv_rd32(dev, NV10_PFB_TILE(i))); - nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), - nv_rd32(dev, NV10_PFB_TLIMIT(i))); - nv_wr32(dev, NV10_PGRAPH_TSIZE(i), - nv_rd32(dev, NV10_PFB_TSIZE(i))); - nv_wr32(dev, NV10_PGRAPH_TSTATUS(i), - nv_rd32(dev, NV10_PFB_TSTATUS(i))); - } + /* Turn all the tiling regions off. */ + for (i = 0; i < NV10_PFB_TILE__SIZE; i++) + nv10_graph_set_region_tiling(dev, i, 0, 0, 0); nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH1, 0x00000000); nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH2, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c index 81c0135..21ac6e4 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c @@ -33,13 +33,103 @@ #include "nouveau_hw.h" #include "nv17_tv.h" -enum drm_connector_status nv17_tv_detect(struct drm_encoder *encoder, - struct drm_connector *connector, - uint32_t pin_mask) +static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) { + struct drm_device *dev = encoder->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t testval, regoffset = nv04_dac_output_offset(encoder); + uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end, + fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c; + uint32_t sample = 0; + int head; + +#define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20) + testval = RGB_TEST_DATA(0x82, 0xeb, 0x82); + if (dev_priv->vbios->tvdactestval) + testval = dev_priv->vbios->tvdactestval; + + dacclk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset); + head = (dacclk & 0x100) >> 8; + + /* Save the previous state. */ + gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1); + gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0); + fp_htotal = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL); + fp_hsync_start = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START); + fp_hsync_end = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END); + fp_control = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL); + test_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset); + ctv_1c = NVReadRAMDAC(dev, head, 0x680c1c); + ctv_14 = NVReadRAMDAC(dev, head, 0x680c14); + ctv_6c = NVReadRAMDAC(dev, head, 0x680c6c); + + /* Prepare the DAC for load detection. */ + nv17_gpio_set(dev, DCB_GPIO_TVDAC1, true); + nv17_gpio_set(dev, DCB_GPIO_TVDAC0, true); + + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, 1183); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL, + NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS | + NV_PRAMDAC_FP_TG_CONTROL_WIDTH_12 | + NV_PRAMDAC_FP_TG_CONTROL_READ_PROG | + NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS | + NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS); + + NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, 0); + + NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, + (dacclk & ~0xff) | 0x22); + msleep(1); + NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, + (dacclk & ~0xff) | 0x21); + + NVWriteRAMDAC(dev, head, 0x680c1c, 1 << 20); + NVWriteRAMDAC(dev, head, 0x680c14, 4 << 16); + + /* Sample pin 0x4 (usually S-video luma). */ + NVWriteRAMDAC(dev, head, 0x680c6c, testval >> 10 & 0x3ff); + msleep(20); + sample |= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset) + & 0x4 << 28; + + /* Sample the remaining pins. */ + NVWriteRAMDAC(dev, head, 0x680c6c, testval & 0x3ff); + msleep(20); + sample |= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset) + & 0xa << 28; + + /* Restore the previous state. */ + NVWriteRAMDAC(dev, head, 0x680c1c, ctv_1c); + NVWriteRAMDAC(dev, head, 0x680c14, ctv_14); + NVWriteRAMDAC(dev, head, 0x680c6c, ctv_6c); + NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, dacclk); + NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, test_ctrl); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL, fp_control); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal); + nv17_gpio_set(dev, DCB_GPIO_TVDAC1, gpio1); + nv17_gpio_set(dev, DCB_GPIO_TVDAC0, gpio0); + + return sample; +} + +static enum drm_connector_status +nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_mode_config *conf = &dev->mode_config; struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder); + struct dcb_entry *dcb = tv_enc->base.dcb; - tv_enc->pin_mask = pin_mask >> 28 & 0xe; + if (dev_priv->chipset == 0x42 || + dev_priv->chipset == 0x43) + tv_enc->pin_mask = nv42_tv_sample_load(encoder) >> 28 & 0xe; + else + tv_enc->pin_mask = nv17_dac_sample_load(encoder) >> 28 & 0xe; switch (tv_enc->pin_mask) { case 0x2: @@ -50,7 +140,7 @@ enum drm_connector_status nv17_tv_detect(struct drm_encoder *encoder, tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_SVIDEO; break; case 0xe: - if (nouveau_encoder(encoder)->dcb->tvconf.has_component_output) + if (dcb->tvconf.has_component_output) tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_Component; else tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_SCART; @@ -61,11 +151,16 @@ enum drm_connector_status nv17_tv_detect(struct drm_encoder *encoder, } drm_connector_property_set_value(connector, - encoder->dev->mode_config.tv_subconnector_property, - tv_enc->subconnector); + conf->tv_subconnector_property, + tv_enc->subconnector); - return tv_enc->subconnector ? connector_status_connected : - connector_status_disconnected; + if (tv_enc->subconnector) { + NV_INFO(dev, "Load detected on output %c\n", + '@' + ffs(dcb->or)); + return connector_status_connected; + } else { + return connector_status_disconnected; + } } static const struct { @@ -484,6 +579,8 @@ static void nv17_tv_restore(struct drm_encoder *encoder) nouveau_encoder(encoder)->restore.output); nv17_tv_state_load(dev, &to_tv_enc(encoder)->saved_state); + + nouveau_encoder(encoder)->last_dpms = NV_DPMS_CLEARED; } static int nv17_tv_create_resources(struct drm_encoder *encoder, @@ -633,7 +730,7 @@ static struct drm_encoder_helper_funcs nv17_tv_helper_funcs = { .prepare = nv17_tv_prepare, .commit = nv17_tv_commit, .mode_set = nv17_tv_mode_set, - .detect = nv17_dac_detect, + .detect = nv17_tv_detect, }; static struct drm_encoder_slave_funcs nv17_tv_slave_funcs = { diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c index 18ba74f..d6fc0a8 100644 --- a/drivers/gpu/drm/nouveau/nv20_graph.c +++ b/drivers/gpu/drm/nouveau/nv20_graph.c @@ -514,6 +514,27 @@ nv20_graph_rdi(struct drm_device *dev) nouveau_wait_for_idle(dev); } +void +nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch) +{ + uint32_t limit = max(1u, addr + size) - 1; + + if (pitch) + addr |= 1; + + nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit); + nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch); + nv_wr32(dev, NV20_PGRAPH_TILE(i), addr); + + nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i); + nv_wr32(dev, NV10_PGRAPH_RDI_DATA, limit); + nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i); + nv_wr32(dev, NV10_PGRAPH_RDI_DATA, pitch); + nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); + nv_wr32(dev, NV10_PGRAPH_RDI_DATA, addr); +} + int nv20_graph_init(struct drm_device *dev) { @@ -572,27 +593,10 @@ nv20_graph_init(struct drm_device *dev) nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000030); } - /* copy tile info from PFB */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) { - nv_wr32(dev, 0x00400904 + i * 0x10, - nv_rd32(dev, NV10_PFB_TLIMIT(i))); - /* which is NV40_PGRAPH_TLIMIT0(i) ?? */ - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + i * 4); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, - nv_rd32(dev, NV10_PFB_TLIMIT(i))); - nv_wr32(dev, 0x00400908 + i * 0x10, - nv_rd32(dev, NV10_PFB_TSIZE(i))); - /* which is NV40_PGRAPH_TSIZE0(i) ?? */ - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + i * 4); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, - nv_rd32(dev, NV10_PFB_TSIZE(i))); - nv_wr32(dev, 0x00400900 + i * 0x10, - nv_rd32(dev, NV10_PFB_TILE(i))); - /* which is NV40_PGRAPH_TILE0(i) ?? */ - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + i * 4); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, - nv_rd32(dev, NV10_PFB_TILE(i))); - } + /* Turn all the tiling regions off. */ + for (i = 0; i < NV10_PFB_TILE__SIZE; i++) + nv20_graph_set_region_tiling(dev, i, 0, 0, 0); + for (i = 0; i < 8; i++) { nv_wr32(dev, 0x400980 + i * 4, nv_rd32(dev, 0x100300 + i * 4)); nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0090 + i * 4); @@ -704,18 +708,9 @@ nv30_graph_init(struct drm_device *dev) nv_wr32(dev, 0x4000c0, 0x00000016); - /* copy tile info from PFB */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) { - nv_wr32(dev, 0x00400904 + i * 0x10, - nv_rd32(dev, NV10_PFB_TLIMIT(i))); - /* which is NV40_PGRAPH_TLIMIT0(i) ?? */ - nv_wr32(dev, 0x00400908 + i * 0x10, - nv_rd32(dev, NV10_PFB_TSIZE(i))); - /* which is NV40_PGRAPH_TSIZE0(i) ?? */ - nv_wr32(dev, 0x00400900 + i * 0x10, - nv_rd32(dev, NV10_PFB_TILE(i))); - /* which is NV40_PGRAPH_TILE0(i) ?? */ - } + /* Turn all the tiling regions off. */ + for (i = 0; i < NV10_PFB_TILE__SIZE; i++) + nv20_graph_set_region_tiling(dev, i, 0, 0, 0); nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100); nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF); diff --git a/drivers/gpu/drm/nouveau/nv40_fb.c b/drivers/gpu/drm/nouveau/nv40_fb.c index ca1d271..3cd07d8 100644 --- a/drivers/gpu/drm/nouveau/nv40_fb.c +++ b/drivers/gpu/drm/nouveau/nv40_fb.c @@ -3,12 +3,37 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" +void +nv40_fb_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t limit = max(1u, addr + size) - 1; + + if (pitch) + addr |= 1; + + switch (dev_priv->chipset) { + case 0x40: + nv_wr32(dev, NV10_PFB_TLIMIT(i), limit); + nv_wr32(dev, NV10_PFB_TSIZE(i), pitch); + nv_wr32(dev, NV10_PFB_TILE(i), addr); + break; + + default: + nv_wr32(dev, NV40_PFB_TLIMIT(i), limit); + nv_wr32(dev, NV40_PFB_TSIZE(i), pitch); + nv_wr32(dev, NV40_PFB_TILE(i), addr); + break; + } +} + int nv40_fb_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t fb_bar_size, tmp; - int num_tiles; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + uint32_t tmp; int i; /* This is strictly a NV4x register (don't know about NV5x). */ @@ -23,35 +48,23 @@ nv40_fb_init(struct drm_device *dev) case 0x45: tmp = nv_rd32(dev, NV10_PFB_CLOSE_PAGE2); nv_wr32(dev, NV10_PFB_CLOSE_PAGE2, tmp & ~(1 << 15)); - num_tiles = NV10_PFB_TILE__SIZE; + pfb->num_tiles = NV10_PFB_TILE__SIZE; break; case 0x46: /* G72 */ case 0x47: /* G70 */ case 0x49: /* G71 */ case 0x4b: /* G73 */ case 0x4c: /* C51 (G7X version) */ - num_tiles = NV40_PFB_TILE__SIZE_1; + pfb->num_tiles = NV40_PFB_TILE__SIZE_1; break; default: - num_tiles = NV40_PFB_TILE__SIZE_0; + pfb->num_tiles = NV40_PFB_TILE__SIZE_0; break; } - fb_bar_size = drm_get_resource_len(dev, 0) - 1; - switch (dev_priv->chipset) { - case 0x40: - for (i = 0; i < num_tiles; i++) { - nv_wr32(dev, NV10_PFB_TILE(i), 0); - nv_wr32(dev, NV10_PFB_TLIMIT(i), fb_bar_size); - } - break; - default: - for (i = 0; i < num_tiles; i++) { - nv_wr32(dev, NV40_PFB_TILE(i), 0); - nv_wr32(dev, NV40_PFB_TLIMIT(i), fb_bar_size); - } - break; - } + /* Turn all the tiling regions off. */ + for (i = 0; i < pfb->num_tiles; i++) + pfb->set_region_tiling(dev, i, 0, 0, 0); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index 2b332bb..53e8afe 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -181,6 +181,48 @@ nv40_graph_unload_context(struct drm_device *dev) return ret; } +void +nv40_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t limit = max(1u, addr + size) - 1; + + if (pitch) + addr |= 1; + + switch (dev_priv->chipset) { + case 0x44: + case 0x4a: + case 0x4e: + nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch); + nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit); + nv_wr32(dev, NV20_PGRAPH_TILE(i), addr); + break; + + case 0x46: + case 0x47: + case 0x49: + case 0x4b: + nv_wr32(dev, NV47_PGRAPH_TSIZE(i), pitch); + nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), limit); + nv_wr32(dev, NV47_PGRAPH_TILE(i), addr); + nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), pitch); + nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), limit); + nv_wr32(dev, NV40_PGRAPH_TILE1(i), addr); + break; + + default: + nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch); + nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit); + nv_wr32(dev, NV20_PGRAPH_TILE(i), addr); + nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), pitch); + nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), limit); + nv_wr32(dev, NV40_PGRAPH_TILE1(i), addr); + break; + } +} + /* * G70 0x47 * G71 0x49 @@ -195,7 +237,8 @@ nv40_graph_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = (struct drm_nouveau_private *)dev->dev_private; - uint32_t vramsz, tmp; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + uint32_t vramsz; int i, j; nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & @@ -292,74 +335,9 @@ nv40_graph_init(struct drm_device *dev) nv_wr32(dev, 0x400b38, 0x2ffff800); nv_wr32(dev, 0x400b3c, 0x00006000); - /* copy tile info from PFB */ - switch (dev_priv->chipset) { - case 0x40: /* vanilla NV40 */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) { - tmp = nv_rd32(dev, NV10_PFB_TILE(i)); - nv_wr32(dev, NV40_PGRAPH_TILE0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TILE1(i), tmp); - tmp = nv_rd32(dev, NV10_PFB_TLIMIT(i)); - nv_wr32(dev, NV40_PGRAPH_TLIMIT0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tmp); - tmp = nv_rd32(dev, NV10_PFB_TSIZE(i)); - nv_wr32(dev, NV40_PGRAPH_TSIZE0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tmp); - tmp = nv_rd32(dev, NV10_PFB_TSTATUS(i)); - nv_wr32(dev, NV40_PGRAPH_TSTATUS0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TSTATUS1(i), tmp); - } - break; - case 0x44: - case 0x4a: - case 0x4e: /* NV44-based cores don't have 0x406900? */ - for (i = 0; i < NV40_PFB_TILE__SIZE_0; i++) { - tmp = nv_rd32(dev, NV40_PFB_TILE(i)); - nv_wr32(dev, NV40_PGRAPH_TILE0(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TLIMIT(i)); - nv_wr32(dev, NV40_PGRAPH_TLIMIT0(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TSIZE(i)); - nv_wr32(dev, NV40_PGRAPH_TSIZE0(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TSTATUS(i)); - nv_wr32(dev, NV40_PGRAPH_TSTATUS0(i), tmp); - } - break; - case 0x46: - case 0x47: - case 0x49: - case 0x4b: /* G7X-based cores */ - for (i = 0; i < NV40_PFB_TILE__SIZE_1; i++) { - tmp = nv_rd32(dev, NV40_PFB_TILE(i)); - nv_wr32(dev, NV47_PGRAPH_TILE0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TILE1(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TLIMIT(i)); - nv_wr32(dev, NV47_PGRAPH_TLIMIT0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TSIZE(i)); - nv_wr32(dev, NV47_PGRAPH_TSIZE0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TSTATUS(i)); - nv_wr32(dev, NV47_PGRAPH_TSTATUS0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TSTATUS1(i), tmp); - } - break; - default: /* everything else */ - for (i = 0; i < NV40_PFB_TILE__SIZE_0; i++) { - tmp = nv_rd32(dev, NV40_PFB_TILE(i)); - nv_wr32(dev, NV40_PGRAPH_TILE0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TILE1(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TLIMIT(i)); - nv_wr32(dev, NV40_PGRAPH_TLIMIT0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TSIZE(i)); - nv_wr32(dev, NV40_PGRAPH_TSIZE0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TSTATUS(i)); - nv_wr32(dev, NV40_PGRAPH_TSTATUS0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TSTATUS1(i), tmp); - } - break; - } + /* Turn all the tiling regions off. */ + for (i = 0; i < pfb->num_tiles; i++) + nv40_graph_set_region_tiling(dev, i, 0, 0, 0); /* begin RAM config */ vramsz = drm_get_resource_len(dev, 0) - 1; diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 118d328..d1a651e 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -298,14 +298,17 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk) static void nv50_crtc_destroy(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - - NV_DEBUG_KMS(dev, "\n"); + struct drm_device *dev; + struct nouveau_crtc *nv_crtc; if (!crtc) return; + dev = crtc->dev; + nv_crtc = nouveau_crtc(crtc); + + NV_DEBUG_KMS(dev, "\n"); + drm_crtc_cleanup(&nv_crtc->base); nv50_cursor_fini(nv_crtc); @@ -432,6 +435,7 @@ nv50_crtc_prepare(struct drm_crtc *crtc) struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_encoder *encoder; + uint32_t dac = 0, sor = 0; NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); @@ -439,9 +443,28 @@ nv50_crtc_prepare(struct drm_crtc *crtc) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - if (drm_helper_encoder_in_use(encoder)) + if (!drm_helper_encoder_in_use(encoder)) continue; + if (nv_encoder->dcb->type == OUTPUT_ANALOG || + nv_encoder->dcb->type == OUTPUT_TV) + dac |= (1 << nv_encoder->or); + else + sor |= (1 << nv_encoder->or); + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + + if (nv_encoder->dcb->type == OUTPUT_ANALOG || + nv_encoder->dcb->type == OUTPUT_TV) { + if (dac & (1 << nv_encoder->or)) + continue; + } else { + if (sor & (1 << nv_encoder->or)) + continue; + } + nv_encoder->disconnect(nv_encoder); } diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index a9263d9..90f0bf5 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -690,9 +690,21 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent, int pxclk) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_connector *nv_connector = NULL; + struct drm_encoder *encoder; struct nvbios *bios = &dev_priv->VBIOS; uint32_t mc, script = 0, or; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + + if (nv_encoder->dcb != dcbent) + continue; + + nv_connector = nouveau_encoder_connector_get(nv_encoder); + break; + } + or = ffs(dcbent->or) - 1; mc = nv50_display_mode_ctrl(dev, dcbent->type != OUTPUT_ANALOG, or); switch (dcbent->type) { @@ -711,6 +723,11 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent, } else if (bios->fp.strapless_is_24bit & 1) script |= 0x0200; + + if (nv_connector && nv_connector->edid && + (nv_connector->edid->revision >= 4) && + (nv_connector->edid->input & 0x70) >= 0x20) + script |= 0x0200; } if (nouveau_uscript_lvds >= 0) { diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 6bcc6d3..0f57cdf 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -3,7 +3,7 @@ #include "nouveau_dma.h" #include "nouveau_fbcon.h" -static void +void nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct nouveau_fbcon_par *par = info->par; @@ -16,9 +16,7 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { @@ -31,7 +29,11 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) OUT_RING(chan, 1); } BEGIN_RING(chan, NvSub2D, 0x0588, 1); - OUT_RING(chan, rect->color); + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) + OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]); + else + OUT_RING(chan, rect->color); BEGIN_RING(chan, NvSub2D, 0x0600, 4); OUT_RING(chan, rect->dx); OUT_RING(chan, rect->dy); @@ -44,7 +46,7 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) FIRE_RING(chan); } -static void +void nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) { struct nouveau_fbcon_par *par = info->par; @@ -56,9 +58,7 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) return; if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 12)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { @@ -81,7 +81,7 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) FIRE_RING(chan); } -static void +void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { struct nouveau_fbcon_par *par = info->par; @@ -101,8 +101,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) } if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 11)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { @@ -135,9 +134,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) int push = dwords > 2047 ? 2047 : dwords; if (RING_SPACE(chan, push + 1)) { - NV_ERROR(dev, - "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); cfb_imageblit(info, image); return; } @@ -199,7 +196,7 @@ nv50_fbcon_accel_init(struct fb_info *info) ret = RING_SPACE(chan, 59); if (ret) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); + nouveau_fbcon_gpu_lockup(info); return ret; } @@ -265,9 +262,6 @@ nv50_fbcon_accel_init(struct fb_info *info) OUT_RING(chan, info->fix.smem_start - dev_priv->fb_phys + dev_priv->vm_vram_base); - info->fbops->fb_fillrect = nv50_fbcon_fillrect; - info->fbops->fb_copyarea = nv50_fbcon_copyarea; - info->fbops->fb_imageblit = nv50_fbcon_imageblit; return 0; } diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index b728228..204a79f 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -272,7 +272,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan) return ret; ramfc = chan->ramfc->gpuobj; - ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 4096, 256, + ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 4096, 1024, 0, &chan->cache); if (ret) return ret; @@ -317,17 +317,20 @@ void nv50_fifo_destroy_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; + struct nouveau_gpuobj_ref *ramfc = chan->ramfc; NV_DEBUG(dev, "ch%d\n", chan->id); - nouveau_gpuobj_ref_del(dev, &chan->ramfc); - nouveau_gpuobj_ref_del(dev, &chan->cache); - + /* This will ensure the channel is seen as disabled. */ + chan->ramfc = NULL; nv50_fifo_channel_disable(dev, chan->id, false); /* Dummy channel, also used on ch 127 */ if (chan->id == 0) nv50_fifo_channel_disable(dev, 127, false); + + nouveau_gpuobj_ref_del(dev, &ramfc); + nouveau_gpuobj_ref_del(dev, &chan->cache); } int @@ -384,8 +387,8 @@ nv50_fifo_load_context(struct nouveau_channel *chan) nv_wr32(dev, NV40_PFIFO_CACHE1_DATA(ptr), nv_ro32(dev, cache, (ptr * 2) + 1)); } - nv_wr32(dev, 0x3210, cnt << 2); - nv_wr32(dev, 0x3270, 0); + nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, cnt << 2); + nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); /* guessing that all the 0x34xx regs aren't on NV50 */ if (!IS_G80) { @@ -398,8 +401,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan) dev_priv->engine.instmem.finish_access(dev); - nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); - nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0); nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16)); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index ca79f32..6d50480 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -84,7 +84,7 @@ nv50_graph_init_regs__nv(struct drm_device *dev) nv_wr32(dev, 0x400804, 0xc0000000); nv_wr32(dev, 0x406800, 0xc0000000); nv_wr32(dev, 0x400c04, 0xc0000000); - nv_wr32(dev, 0x401804, 0xc0000000); + nv_wr32(dev, 0x401800, 0xc0000000); nv_wr32(dev, 0x405018, 0xc0000000); nv_wr32(dev, 0x402000, 0xc0000000); @@ -165,6 +165,12 @@ nv50_graph_channel(struct drm_device *dev) uint32_t inst; int i; + /* Be sure we're not in the middle of a context switch or bad things + * will happen, such as unloading the wrong pgraph context. + */ + if (!nv_wait(0x400300, 0x00000001, 0x00000000)) + NV_ERROR(dev, "Ctxprog is still running\n"); + inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR); if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED)) return NULL; @@ -275,19 +281,18 @@ nv50_graph_load_context(struct nouveau_channel *chan) int nv50_graph_unload_context(struct drm_device *dev) { - uint32_t inst, fifo = nv_rd32(dev, 0x400500); + uint32_t inst; inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR); if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED)) return 0; inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE; - nv_wr32(dev, 0x400500, fifo & ~1); + nouveau_wait_for_idle(dev); nv_wr32(dev, 0x400784, inst); nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20); nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01); nouveau_wait_for_idle(dev); - nv_wr32(dev, 0x400500, fifo); nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst); return 0; diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c index e395c16..c2fff54 100644 --- a/drivers/gpu/drm/nouveau/nv50_sor.c +++ b/drivers/gpu/drm/nouveau/nv50_sor.c @@ -90,11 +90,25 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_encoder *enc; uint32_t val; int or = nv_encoder->or; NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode); + nv_encoder->last_dpms = mode; + list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { + struct nouveau_encoder *nvenc = nouveau_encoder(enc); + + if (nvenc == nv_encoder || + nvenc->disconnect != nv50_sor_disconnect || + nvenc->dcb->or != nv_encoder->dcb->or) + continue; + + if (nvenc->last_dpms == DRM_MODE_DPMS_ON) + return; + } + /* wait for it to be done */ if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_CTRL(or), NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING, 0)) { diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig index 5982321..1c02d23 100644 --- a/drivers/gpu/drm/radeon/Kconfig +++ b/drivers/gpu/drm/radeon/Kconfig @@ -1,10 +1,14 @@ config DRM_RADEON_KMS - bool "Enable modesetting on radeon by default" + bool "Enable modesetting on radeon by default - NEW DRIVER" 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. + Choose this option if you want kernel modesetting enabled by default. + + This is a completely new driver. It's only part of the existing drm + for compatibility reasons. It requires an entirely different graphics + stack above it and works very differently from the old drm stack. + i.e. don't enable this unless you know what you are doing it may + cause issues or bugs compared to the previous userspace driver stack. When kernel modesetting is enabled the IOCTL of radeon/drm driver are considered as invalid and an error message is printed diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index b5f5fe7..1cc7b93 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -24,6 +24,9 @@ $(obj)/rv515_reg_safe.h: $(src)/reg_srcs/rv515 $(obj)/mkregtable $(obj)/r300_reg_safe.h: $(src)/reg_srcs/r300 $(obj)/mkregtable $(call if_changed,mkregtable) +$(obj)/r420_reg_safe.h: $(src)/reg_srcs/r420 $(obj)/mkregtable + $(call if_changed,mkregtable) + $(obj)/rs600_reg_safe.h: $(src)/reg_srcs/rs600 $(obj)/mkregtable $(call if_changed,mkregtable) @@ -35,6 +38,8 @@ $(obj)/rv515.o: $(obj)/rv515_reg_safe.h $(obj)/r300.o: $(obj)/r300_reg_safe.h +$(obj)/r420.o: $(obj)/r420_reg_safe.h + $(obj)/rs600.o: $(obj)/rs600_reg_safe.h radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o \ diff --git a/drivers/gpu/drm/radeon/ObjectID.h b/drivers/gpu/drm/radeon/ObjectID.h index 6d0183c..c714179 100644 --- a/drivers/gpu/drm/radeon/ObjectID.h +++ b/drivers/gpu/drm/radeon/ObjectID.h @@ -1,5 +1,5 @@ /* -* Copyright 2006-2007 Advanced Micro Devices, Inc. +* 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"), @@ -41,14 +41,14 @@ /****************************************************/ /* Encoder Object ID Definition */ /****************************************************/ -#define ENCODER_OBJECT_ID_NONE 0x00 +#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_DAC2 0x05 /* TV/CV DAC */ #define ENCODER_OBJECT_ID_INTERNAL_SDVOA 0x06 #define ENCODER_OBJECT_ID_INTERNAL_SDVOB 0x07 @@ -56,11 +56,11 @@ #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_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_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 @@ -68,9 +68,9 @@ #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_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 @@ -86,7 +86,7 @@ /****************************************************/ /* Connector Object ID Definition */ /****************************************************/ -#define CONNECTOR_OBJECT_ID_NONE 0x00 +#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 @@ -96,7 +96,7 @@ #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_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 @@ -106,6 +106,8 @@ #define CONNECTOR_OBJECT_ID_CROSSFIRE 0x11 #define CONNECTOR_OBJECT_ID_HARDCODE_DVI 0x12 #define CONNECTOR_OBJECT_ID_DISPLAYPORT 0x13 +#define CONNECTOR_OBJECT_ID_eDP 0x14 +#define CONNECTOR_OBJECT_ID_MXM 0x15 /* deleted */ @@ -116,6 +118,14 @@ #define ROUTER_OBJECT_ID_I2C_EXTENDER_CNTL 0x01 /****************************************************/ +/* Generic Object ID Definition */ +/****************************************************/ +#define GENERIC_OBJECT_ID_NONE 0x00 +#define GENERIC_OBJECT_ID_GLSYNC 0x01 +#define GENERIC_OBJECT_ID_PX2_NON_DRIVABLE 0x02 +#define GENERIC_OBJECT_ID_MXM_OPM 0x03 + +/****************************************************/ /* Graphics Object ENUM ID Definition */ /****************************************************/ #define GRAPH_OBJECT_ENUM_ID1 0x01 @@ -124,6 +134,7 @@ #define GRAPH_OBJECT_ENUM_ID4 0x04 #define GRAPH_OBJECT_ENUM_ID5 0x05 #define GRAPH_OBJECT_ENUM_ID6 0x06 +#define GRAPH_OBJECT_ENUM_ID7 0x07 /****************************************************/ /* Graphics Object ID Bit definition */ @@ -133,35 +144,35 @@ #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) +#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) +#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_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_SIL170B_ENUM_ID1 0x2108 #define ENCODER_CH7303_ENUM_ID1 0x2109 #define ENCODER_CH7301_ENUM_ID1 0x210A #define ENCODER_INTERNAL_DVO1_ENUM_ID1 0x210B @@ -175,8 +186,8 @@ #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_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 @@ -185,205 +196,169 @@ #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) +#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 */ @@ -406,167 +381,253 @@ #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) +#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_LVDS_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_LVDS << OBJECT_ID_SHIFT) + +#define CONNECTOR_eDP_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_eDP << OBJECT_ID_SHIFT) + +#define CONNECTOR_eDP_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_eDP << 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_DUAL_LINK_DVI_D_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT) + +#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID3 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID3 << 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_COMPOSITE_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << 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_SVIDEO_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << 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_YPbPr_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << 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_D_CONNECTOR_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << 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_9PIN_DIN_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << 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_SCART_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << 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_A_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT) + +#define CONNECTOR_HDMI_TYPE_A_ENUM_ID3 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID3 << 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_HDMI_TYPE_B_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << 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_7PIN_DIN_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << 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) + +#define CONNECTOR_DISPLAYPORT_ENUM_ID5 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID5 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + +#define CONNECTOR_DISPLAYPORT_ENUM_ID6 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID6 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + +#define CONNECTOR_MXM_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_DP_A + +#define CONNECTOR_MXM_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_DP_B + +#define CONNECTOR_MXM_ENUM_ID3 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_DP_C + +#define CONNECTOR_MXM_ENUM_ID4 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_DP_D + +#define CONNECTOR_MXM_ENUM_ID5 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID5 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_LVDS_TXxx + +#define CONNECTOR_MXM_ENUM_ID6 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID6 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_LVDS_UXxx + +#define CONNECTOR_MXM_ENUM_ID7 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID7 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_DAC /****************************************************/ /* 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) +#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 */ /****************************************************/ +/* Generic Object ID definition - Shared with BIOS */ +/****************************************************/ +#define GENERICOBJECT_GLSYNC_ENUM_ID1 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + GENERIC_OBJECT_ID_GLSYNC << OBJECT_ID_SHIFT) + +#define GENERICOBJECT_PX2_NON_DRIVABLE_ID1 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + GENERIC_OBJECT_ID_PX2_NON_DRIVABLE<< OBJECT_ID_SHIFT) + +#define GENERICOBJECT_PX2_NON_DRIVABLE_ID2 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + GENERIC_OBJECT_ID_PX2_NON_DRIVABLE<< OBJECT_ID_SHIFT) + +#define GENERICOBJECT_MXM_OPM_ENUM_ID1 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + GENERIC_OBJECT_ID_MXM_OPM << OBJECT_ID_SHIFT) + +/****************************************************/ /* 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 @@ -575,4 +636,8 @@ #pragma pack() #endif -#endif /*GRAPHICTYPE */ +#endif /*GRAPHICTYPE */ + + + + diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 388140a7..7f152f6 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -24,6 +24,7 @@ #include <linux/module.h> #include <linux/sched.h> +#include <asm/unaligned.h> #define ATOM_DEBUG @@ -212,7 +213,9 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, case ATOM_ARG_PS: idx = U8(*ptr); (*ptr)++; - val = le32_to_cpu(ctx->ps[idx]); + /* get_unaligned_le32 avoids unaligned accesses from atombios + * tables, noticed on a DEC Alpha. */ + val = get_unaligned_le32((u32 *)&ctx->ps[idx]); if (print) DEBUG("PS[0x%02X,0x%04X]", idx, val); break; @@ -246,6 +249,9 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, case ATOM_WS_ATTRIBUTES: val = gctx->io_attr; break; + case ATOM_WS_REGPTR: + val = gctx->reg_block; + break; default: val = ctx->ws[idx]; } @@ -385,6 +391,32 @@ 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_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr) +{ + uint32_t val = 0xCDCDCDCD; + + switch (align) { + case ATOM_SRC_DWORD: + val = U32(*ptr); + (*ptr) += 4; + break; + case ATOM_SRC_WORD0: + case ATOM_SRC_WORD8: + case ATOM_SRC_WORD16: + val = U16(*ptr); + (*ptr) += 2; + break; + case ATOM_SRC_BYTE0: + case ATOM_SRC_BYTE8: + case ATOM_SRC_BYTE16: + case ATOM_SRC_BYTE24: + val = U8(*ptr); + (*ptr)++; + break; + } + return val; +} + static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr, uint32_t *saved, int print) { @@ -482,6 +514,9 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, case ATOM_WS_ATTRIBUTES: gctx->io_attr = val; break; + case ATOM_WS_REGPTR: + gctx->reg_block = val; + break; default: ctx->ws[idx] = val; } @@ -608,7 +643,7 @@ 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)); + udelay(count); else schedule_timeout_uninterruptible(msecs_to_jiffies(count)); } @@ -677,7 +712,7 @@ static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); SDEBUG(" src1: "); - src1 = atom_get_src(ctx, attr, ptr); + src1 = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); SDEBUG(" src2: "); src2 = atom_get_src(ctx, attr, ptr); dst &= src1; @@ -809,6 +844,38 @@ static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg) SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block); } +static void atom_op_shift_left(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 = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); + SDEBUG(" shift: %d\n", shift); + dst <<= shift; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_shift_right(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 = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); + SDEBUG(" shift: %d\n", shift); + dst >>= shift; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) { uint8_t attr = U8((*ptr)++), shift; @@ -818,7 +885,7 @@ static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) attr |= atom_def_dst[attr >> 3] << 6; SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); - shift = U8((*ptr)++); + shift = atom_get_src(ctx, attr, ptr); SDEBUG(" shift: %d\n", shift); dst <<= shift; SDEBUG(" dst: "); @@ -834,7 +901,7 @@ static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg) attr |= atom_def_dst[attr >> 3] << 6; SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); - shift = U8((*ptr)++); + shift = atom_get_src(ctx, attr, ptr); SDEBUG(" shift: %d\n", shift); dst >>= shift; SDEBUG(" dst: "); @@ -937,18 +1004,18 @@ static struct { 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_shift_left, ATOM_ARG_REG}, { + atom_op_shift_left, ATOM_ARG_PS}, { + atom_op_shift_left, ATOM_ARG_WS}, { + atom_op_shift_left, ATOM_ARG_FB}, { + atom_op_shift_left, ATOM_ARG_PLL}, { + atom_op_shift_left, ATOM_ARG_MC}, { + atom_op_shift_right, ATOM_ARG_REG}, { + atom_op_shift_right, ATOM_ARG_PS}, { + atom_op_shift_right, ATOM_ARG_WS}, { + atom_op_shift_right, ATOM_ARG_FB}, { + atom_op_shift_right, ATOM_ARG_PLL}, { + atom_op_shift_right, ATOM_ARG_MC}, { atom_op_mul, ATOM_ARG_REG}, { atom_op_mul, ATOM_ARG_PS}, { atom_op_mul, ATOM_ARG_WS}, { @@ -1058,8 +1125,6 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3 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; @@ -1096,6 +1161,12 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3 void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) { mutex_lock(&ctx->mutex); + /* reset reg block */ + ctx->reg_block = 0; + /* reset fb window */ + ctx->fb_base = 0; + /* reset io mode */ + ctx->io_mode = ATOM_IO_MM; atom_execute_table_locked(ctx, index, params); mutex_unlock(&ctx->mutex); } diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h index 47fd943..bc73781 100644 --- a/drivers/gpu/drm/radeon/atom.h +++ b/drivers/gpu/drm/radeon/atom.h @@ -91,6 +91,7 @@ #define ATOM_WS_AND_MASK 0x45 #define ATOM_WS_FB_WINDOW 0x46 #define ATOM_WS_ATTRIBUTES 0x47 +#define ATOM_WS_REGPTR 0x48 #define ATOM_IIO_NOP 0 #define ATOM_IIO_START 1 diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 260fcf5..af464e35 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -307,7 +307,6 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, args.susModeMiscInfo.usAccess = cpu_to_le16(misc); args.ucCRTC = radeon_crtc->crtc_id; - printk("executing set crtc dtd timing\n"); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } @@ -347,7 +346,6 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc, args.susModeMiscInfo.usAccess = cpu_to_le16(misc); args.ucCRTC = radeon_crtc->crtc_id; - printk("executing set crtc timing\n"); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } @@ -409,59 +407,57 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable) } } -void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) +union adjust_pixel_clock { + ADJUST_DISPLAY_PLL_PS_ALLOCATION v1; +}; + +static u32 atombios_adjust_pll(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct radeon_pll *pll) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct drm_encoder *encoder = NULL; struct radeon_encoder *radeon_encoder = NULL; - uint8_t frev, crev; - int index; - 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 pll_clock = mode->clock; - uint32_t adjusted_clock; - uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; - struct radeon_pll *pll; - int pll_flags = 0; + u32 adjusted_clock = mode->clock; - memset(&args, 0, sizeof(args)); + /* reset the pll flags */ + pll->flags = 0; if (ASIC_IS_AVIVO(rdev)) { if ((rdev->family == CHIP_RS600) || (rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) - pll_flags |= (RADEON_PLL_USE_FRAC_FB_DIV | - RADEON_PLL_PREFER_CLOSEST_LOWER); + pll->flags |= (RADEON_PLL_USE_FRAC_FB_DIV | + RADEON_PLL_PREFER_CLOSEST_LOWER); if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ - pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else - pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; } else { - pll_flags |= RADEON_PLL_LEGACY; + pll->flags |= RADEON_PLL_LEGACY; if (mode->clock > 200000) /* range limits??? */ - pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else - pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; } list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { - if (!ASIC_IS_AVIVO(rdev)) { - if (encoder->encoder_type != - DRM_MODE_ENCODER_DAC) - pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; - if (encoder->encoder_type == - DRM_MODE_ENCODER_LVDS) - pll_flags |= RADEON_PLL_USE_REF_DIV; - } radeon_encoder = to_radeon_encoder(encoder); + if (ASIC_IS_AVIVO(rdev)) { + /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) + adjusted_clock = mode->clock * 2; + } else { + if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) + pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; + if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) + pll->flags |= RADEON_PLL_USE_REF_DIV; + } break; } } @@ -471,46 +467,101 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) * special hw requirements. */ if (ASIC_IS_DCE3(rdev)) { - ADJUST_DISPLAY_PLL_PS_ALLOCATION adjust_pll_args; + union adjust_pixel_clock args; + struct radeon_encoder_atom_dig *dig; + u8 frev, crev; + int index; - if (!encoder) - return; - - memset(&adjust_pll_args, 0, sizeof(adjust_pll_args)); - adjust_pll_args.usPixelClock = cpu_to_le16(mode->clock / 10); - adjust_pll_args.ucTransmitterID = radeon_encoder->encoder_id; - adjust_pll_args.ucEncodeMode = atombios_get_encoder_mode(encoder); + if (!radeon_encoder->enc_priv) + return adjusted_clock; + dig = radeon_encoder->enc_priv; index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); - atom_execute_table(rdev->mode_info.atom_context, - index, (uint32_t *)&adjust_pll_args); - adjusted_clock = le16_to_cpu(adjust_pll_args.usPixelClock) * 10; - } else { - /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ - if (ASIC_IS_AVIVO(rdev) && - (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)) - adjusted_clock = mode->clock * 2; - else - adjusted_clock = mode->clock; + atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, + &crev); + + memset(&args, 0, sizeof(args)); + + switch (frev) { + case 1: + switch (crev) { + case 1: + case 2: + args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v1.ucTransmitterID = radeon_encoder->encoder_id; + args.v1.ucEncodeMode = atombios_get_encoder_mode(encoder); + + atom_execute_table(rdev->mode_info.atom_context, + index, (uint32_t *)&args); + adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; + break; + default: + DRM_ERROR("Unknown table version %d %d\n", frev, crev); + return adjusted_clock; + } + break; + default: + DRM_ERROR("Unknown table version %d %d\n", frev, crev); + return adjusted_clock; + } } + return adjusted_clock; +} + +union set_pixel_clock { + SET_PIXEL_CLOCK_PS_ALLOCATION base; + PIXEL_CLOCK_PARAMETERS v1; + PIXEL_CLOCK_PARAMETERS_V2 v2; + PIXEL_CLOCK_PARAMETERS_V3 v3; +}; + +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 radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder = NULL; + struct radeon_encoder *radeon_encoder = NULL; + u8 frev, crev; + int index; + union set_pixel_clock args; + u32 pll_clock = mode->clock; + u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; + struct radeon_pll *pll; + u32 adjusted_clock; + + memset(&args, 0, sizeof(args)); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + radeon_encoder = to_radeon_encoder(encoder); + break; + } + } + + if (!radeon_encoder) + return; if (radeon_crtc->crtc_id == 0) pll = &rdev->clock.p1pll; else pll = &rdev->clock.p2pll; + /* adjust pixel clock as needed */ + adjusted_clock = atombios_adjust_pll(crtc, mode, pll); + if (ASIC_IS_AVIVO(rdev)) { if (radeon_new_pll) radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, - &ref_div, &post_div, pll_flags); + &ref_div, &post_div); else radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, - &ref_div, &post_div, pll_flags); + &ref_div, &post_div); } else radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, - &ref_div, &post_div, pll_flags); + &ref_div, &post_div); index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, @@ -520,45 +571,38 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) case 1: switch (crev) { case 1: - spc1_ptr = (PIXEL_CLOCK_PARAMETERS *) & args.sPCLKInput; - spc1_ptr->usPixelClock = cpu_to_le16(mode->clock / 10); - spc1_ptr->usRefDiv = cpu_to_le16(ref_div); - spc1_ptr->usFbDiv = cpu_to_le16(fb_div); - spc1_ptr->ucFracFbDiv = frac_fb_div; - spc1_ptr->ucPostDiv = post_div; - spc1_ptr->ucPpll = + args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v1.usRefDiv = cpu_to_le16(ref_div); + args.v1.usFbDiv = cpu_to_le16(fb_div); + args.v1.ucFracFbDiv = frac_fb_div; + args.v1.ucPostDiv = post_div; + args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; - spc1_ptr->ucCRTC = radeon_crtc->crtc_id; - spc1_ptr->ucRefDivSrc = 1; + args.v1.ucCRTC = radeon_crtc->crtc_id; + args.v1.ucRefDivSrc = 1; break; case 2: - spc2_ptr = - (PIXEL_CLOCK_PARAMETERS_V2 *) & args.sPCLKInput; - spc2_ptr->usPixelClock = cpu_to_le16(mode->clock / 10); - spc2_ptr->usRefDiv = cpu_to_le16(ref_div); - spc2_ptr->usFbDiv = cpu_to_le16(fb_div); - spc2_ptr->ucFracFbDiv = frac_fb_div; - spc2_ptr->ucPostDiv = post_div; - spc2_ptr->ucPpll = + args.v2.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v2.usRefDiv = cpu_to_le16(ref_div); + args.v2.usFbDiv = cpu_to_le16(fb_div); + args.v2.ucFracFbDiv = frac_fb_div; + args.v2.ucPostDiv = post_div; + args.v2.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; - spc2_ptr->ucCRTC = radeon_crtc->crtc_id; - spc2_ptr->ucRefDivSrc = 1; + args.v2.ucCRTC = radeon_crtc->crtc_id; + args.v2.ucRefDivSrc = 1; break; case 3: - if (!encoder) - return; - spc3_ptr = - (PIXEL_CLOCK_PARAMETERS_V3 *) & args.sPCLKInput; - spc3_ptr->usPixelClock = cpu_to_le16(mode->clock / 10); - spc3_ptr->usRefDiv = cpu_to_le16(ref_div); - spc3_ptr->usFbDiv = cpu_to_le16(fb_div); - spc3_ptr->ucFracFbDiv = frac_fb_div; - spc3_ptr->ucPostDiv = post_div; - spc3_ptr->ucPpll = + args.v3.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v3.usRefDiv = cpu_to_le16(ref_div); + args.v3.usFbDiv = cpu_to_le16(fb_div); + args.v3.ucFracFbDiv = frac_fb_div; + args.v3.ucPostDiv = post_div; + args.v3.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 = + args.v3.ucMiscInfo = (radeon_crtc->crtc_id << 2); + args.v3.ucTransmitterId = radeon_encoder->encoder_id; + args.v3.ucEncoderMode = atombios_get_encoder_mode(encoder); break; default: @@ -571,12 +615,11 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) return; } - printk("executing set pll\n"); atom_execute_table(rdev->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) +static int avivo_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; @@ -706,6 +749,42 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, return 0; } +int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + + if (ASIC_IS_AVIVO(rdev)) + return avivo_crtc_set_base(crtc, x, y, old_fb); + else + return radeon_crtc_set_base(crtc, x, y, old_fb); +} + +/* properly set additional regs when using atombios */ +static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + u32 disp_merge_cntl; + + switch (radeon_crtc->crtc_id) { + case 0: + disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); + disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; + WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); + break; + case 1: + disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); + disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; + WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); + WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); + WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); + break; + } +} + int atombios_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -727,8 +806,8 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, else { if (radeon_crtc->crtc_id == 0) atombios_set_crtc_dtd_timing(crtc, adjusted_mode); - radeon_crtc_set_base(crtc, x, y, old_fb); - radeon_legacy_atom_set_surface(crtc); + atombios_crtc_set_base(crtc, x, y, old_fb); + radeon_legacy_atom_fixup(crtc); } atombios_overscan_setup(crtc, mode, adjusted_mode); atombios_scaler_setup(crtc); @@ -746,8 +825,8 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, static void atombios_crtc_prepare(struct drm_crtc *crtc) { - atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); atombios_lock_crtc(crtc, 1); + atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); } static void atombios_crtc_commit(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 0d63c44..99915a6 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -332,11 +332,13 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); unsigned char *base; + int retry_count = 0; memset(&args, 0, sizeof(args)); base = (unsigned char *)rdev->mode_info.atom_context->scratch; +retry: memcpy(base, req_bytes, num_bytes); args.lpAuxRequest = 0; @@ -347,10 +349,12 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - if (args.ucReplyStatus) { - DRM_DEBUG("failed to get auxch %02x%02x %02x %02x 0x%02x %02x\n", + if (args.ucReplyStatus && !args.ucDataOutLen) { + if (args.ucReplyStatus == 0x20 && retry_count++ < 10) + goto retry; + DRM_DEBUG("failed to get auxch %02x%02x %02x %02x 0x%02x %02x after %d retries\n", req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3], - chan->rec.i2c_id, args.ucReplyStatus); + chan->rec.i2c_id, args.ucReplyStatus, retry_count); return false; } @@ -468,7 +472,8 @@ void radeon_dp_set_link_config(struct drm_connector *connector, struct radeon_connector *radeon_connector; struct radeon_connector_atom_dig *dig_connector; - if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) + if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) && + (connector->connector_type != DRM_MODE_CONNECTOR_eDP)) return; radeon_connector = to_radeon_connector(connector); @@ -582,7 +587,8 @@ void dp_link_train(struct drm_encoder *encoder, u8 train_set[4]; int i; - if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) + if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) && + (connector->connector_type != DRM_MODE_CONNECTOR_eDP)) return; if (!radeon_encoder->enc_priv) @@ -594,21 +600,14 @@ void dp_link_train(struct drm_encoder *encoder, return; dig_connector = radeon_connector->con_priv; - if (ASIC_IS_DCE32(rdev)) { - if (dig->dig_block) - enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER; - else - enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER; - if (dig_connector->linkb) - enc_id |= ATOM_DP_CONFIG_LINK_B; - else - enc_id |= ATOM_DP_CONFIG_LINK_A; - } else { - if (dig_connector->linkb) - enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER | ATOM_DP_CONFIG_LINK_B; - else - enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER | ATOM_DP_CONFIG_LINK_A; - } + if (dig->dig_encoder) + enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER; + else + enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER; + if (dig_connector->linkb) + enc_id |= ATOM_DP_CONFIG_LINK_B; + else + enc_id |= ATOM_DP_CONFIG_LINK_A; memset(link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); if (dig_connector->dp_clock == 270000) diff --git a/drivers/gpu/drm/radeon/mkregtable.c b/drivers/gpu/drm/radeon/mkregtable.c index 0d79577..607241c 100644 --- a/drivers/gpu/drm/radeon/mkregtable.c +++ b/drivers/gpu/drm/radeon/mkregtable.c @@ -661,8 +661,10 @@ static int parser_auth(struct table *t, const char *filename) fseek(file, 0, SEEK_SET); /* get header */ - if (fgets(buf, 1024, file) == NULL) + if (fgets(buf, 1024, file) == NULL) { + fclose(file); return -1; + } /* first line will contain the last register * and gpu name */ diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 7172746..c0d4650 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -131,7 +131,8 @@ void r100_hpd_init(struct radeon_device *rdev) break; } } - r100_irq_set(rdev); + if (rdev->irq.installed) + r100_irq_set(rdev); } void r100_hpd_fini(struct radeon_device *rdev) @@ -243,6 +244,11 @@ int r100_irq_set(struct radeon_device *rdev) { uint32_t tmp = 0; + if (!rdev->irq.installed) { + WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); + WREG32(R_000040_GEN_INT_CNTL, 0); + return -EINVAL; + } if (rdev->irq.sw_int) { tmp |= RADEON_SW_INT_ENABLE; } @@ -348,14 +354,25 @@ u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc) return RREG32(RADEON_CRTC2_CRNT_FRAME); } +/* Who ever call radeon_fence_emit should call ring_lock and ask + * for enough space (today caller are ib schedule and buffer move) */ void r100_fence_ring_emit(struct radeon_device *rdev, struct radeon_fence *fence) { - /* Who ever call radeon_fence_emit should call ring_lock and ask - * for enough space (today caller are ib schedule and buffer move) */ + /* We have to make sure that caches are flushed before + * CPU might read something from VRAM. */ + radeon_ring_write(rdev, PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, RADEON_RB3D_DC_FLUSH_ALL); + radeon_ring_write(rdev, PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, RADEON_RB3D_ZC_FLUSH_ALL); /* Wait until IDLE & CLEAN */ radeon_ring_write(rdev, PACKET0(0x1720, 0)); radeon_ring_write(rdev, (1 << 16) | (1 << 17)); + radeon_ring_write(rdev, PACKET0(RADEON_HOST_PATH_CNTL, 0)); + radeon_ring_write(rdev, rdev->config.r100.hdp_cntl | + RADEON_HDP_READ_BUFFER_INVALIDATE); + radeon_ring_write(rdev, PACKET0(RADEON_HOST_PATH_CNTL, 0)); + radeon_ring_write(rdev, rdev->config.r100.hdp_cntl); /* Emit fence sequence & fire IRQ */ radeon_ring_write(rdev, PACKET0(rdev->fence_drv.scratch_reg, 0)); radeon_ring_write(rdev, fence->seq); @@ -1493,6 +1510,7 @@ static int r100_packet3_check(struct radeon_cs_parser *p, DRM_ERROR("PRIM_WALK must be 3 for IMMD draw\n"); return -EINVAL; } + track->vtx_size = r100_get_vtx_size(radeon_get_ib_value(p, idx + 0)); track->vap_vf_cntl = radeon_get_ib_value(p, idx + 1); track->immd_dwords = pkt->count - 1; r = r100_cs_track_check(p->rdev, track); @@ -1713,14 +1731,6 @@ void r100_gpu_init(struct radeon_device *rdev) r100_hdp_reset(rdev); } -void r100_hdp_flush(struct radeon_device *rdev) -{ - u32 tmp; - tmp = RREG32(RADEON_HOST_PATH_CNTL); - tmp |= RADEON_HDP_READ_BUFFER_INVALIDATE; - WREG32(RADEON_HOST_PATH_CNTL, tmp); -} - void r100_hdp_reset(struct radeon_device *rdev) { uint32_t tmp; @@ -3313,6 +3323,7 @@ static int r100_startup(struct radeon_device *rdev) } /* Enable IRQ */ r100_irq_set(rdev); + rdev->config.r100.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ r = r100_cp_init(rdev, 1024 * 1024); if (r) { @@ -3364,13 +3375,13 @@ int r100_suspend(struct radeon_device *rdev) void r100_fini(struct radeon_device *rdev) { - r100_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); radeon_gem_fini(rdev); if (rdev->flags & RADEON_IS_PCI) r100_pci_gart_fini(rdev); + radeon_agp_fini(rdev); radeon_irq_kms_fini(rdev); radeon_fence_driver_fini(rdev); radeon_bo_fini(rdev); @@ -3394,9 +3405,7 @@ int r100_mc_init(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); if (r) { - printk(KERN_WARNING "[drm] Disabling AGP\n"); - rdev->flags &= ~RADEON_IS_AGP; - rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + radeon_agp_disable(rdev); } else { rdev->mc.gtt_location = rdev->mc.agp_base; } @@ -3477,13 +3486,12 @@ int r100_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - r100_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); + radeon_irq_kms_fini(rdev); if (rdev->flags & RADEON_IS_PCI) r100_pci_gart_fini(rdev); - radeon_irq_kms_fini(rdev); rdev->accel_working = false; } return 0; diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c index 2094212..ff1e0cd 100644 --- a/drivers/gpu/drm/radeon/r200.c +++ b/drivers/gpu/drm/radeon/r200.c @@ -371,13 +371,16 @@ int r200_packet0_check(struct radeon_cs_parser *p, case 5: case 6: case 7: + /* 1D/2D */ track->textures[i].tex_coord_type = 0; break; case 1: - track->textures[i].tex_coord_type = 1; + /* CUBE */ + track->textures[i].tex_coord_type = 2; break; case 2: - track->textures[i].tex_coord_type = 2; + /* 3D */ + track->textures[i].tex_coord_type = 1; break; } break; diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 3f2cc9e..43b55a0 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -36,7 +36,15 @@ #include "rv350d.h" #include "r300_reg_safe.h" -/* This files gather functions specifics to: r300,r350,rv350,rv370,rv380 */ +/* This files gather functions specifics to: r300,r350,rv350,rv370,rv380 + * + * GPU Errata: + * - HOST_PATH_CNTL: r300 family seems to dislike write to HOST_PATH_CNTL + * using MMIO to flush host path read cache, this lead to HARDLOCKUP. + * However, scheduling such write to the ring seems harmless, i suspect + * the CP read collide with the flush somehow, or maybe the MC, hard to + * tell. (Jerome Glisse) + */ /* * rv370,rv380 PCIE GART @@ -178,6 +186,11 @@ void r300_fence_ring_emit(struct radeon_device *rdev, /* Wait until IDLE & CLEAN */ radeon_ring_write(rdev, PACKET0(0x1720, 0)); radeon_ring_write(rdev, (1 << 17) | (1 << 16) | (1 << 9)); + radeon_ring_write(rdev, PACKET0(RADEON_HOST_PATH_CNTL, 0)); + radeon_ring_write(rdev, rdev->config.r300.hdp_cntl | + RADEON_HDP_READ_BUFFER_INVALIDATE); + radeon_ring_write(rdev, PACKET0(RADEON_HOST_PATH_CNTL, 0)); + radeon_ring_write(rdev, rdev->config.r300.hdp_cntl); /* Emit fence sequence & fire IRQ */ radeon_ring_write(rdev, PACKET0(rdev->fence_drv.scratch_reg, 0)); radeon_ring_write(rdev, fence->seq); @@ -493,11 +506,14 @@ void r300_vram_info(struct radeon_device *rdev) /* DDR for all card after R300 & IGP */ rdev->mc.vram_is_ddr = true; + tmp = RREG32(RADEON_MEM_CNTL); - if (tmp & R300_MEM_NUM_CHANNELS_MASK) { - rdev->mc.vram_width = 128; - } else { - rdev->mc.vram_width = 64; + tmp &= R300_MEM_NUM_CHANNELS_MASK; + switch (tmp) { + case 0: rdev->mc.vram_width = 64; break; + case 1: rdev->mc.vram_width = 128; break; + case 2: rdev->mc.vram_width = 256; break; + default: rdev->mc.vram_width = 128; break; } r100_vram_init_sizes(rdev); @@ -1258,6 +1274,7 @@ static int r300_startup(struct radeon_device *rdev) } /* Enable IRQ */ r100_irq_set(rdev); + rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ r = r100_cp_init(rdev, 1024 * 1024); if (r) { @@ -1313,7 +1330,6 @@ int r300_suspend(struct radeon_device *rdev) void r300_fini(struct radeon_device *rdev) { - r300_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -1322,6 +1338,7 @@ void r300_fini(struct radeon_device *rdev) rv370_pcie_gart_fini(rdev); if (rdev->flags & RADEON_IS_PCI) r100_pci_gart_fini(rdev); + radeon_agp_fini(rdev); radeon_irq_kms_fini(rdev); radeon_fence_driver_fini(rdev); radeon_bo_fini(rdev); @@ -1403,15 +1420,15 @@ int r300_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - r300_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); + radeon_irq_kms_fini(rdev); if (rdev->flags & RADEON_IS_PCIE) rv370_pcie_gart_fini(rdev); if (rdev->flags & RADEON_IS_PCI) r100_pci_gart_fini(rdev); - radeon_irq_kms_fini(rdev); + radeon_agp_fini(rdev); rdev->accel_working = false; } return 0; diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index c05a727..d937324 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -30,7 +30,15 @@ #include "radeon_reg.h" #include "radeon.h" #include "atom.h" +#include "r100d.h" #include "r420d.h" +#include "r420_reg_safe.h" + +static void r420_set_reg_safe(struct radeon_device *rdev) +{ + rdev->config.r300.reg_safe_bm = r420_reg_safe_bm; + rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r420_reg_safe_bm); +} int r420_mc_init(struct radeon_device *rdev) { @@ -42,9 +50,7 @@ int r420_mc_init(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); if (r) { - printk(KERN_WARNING "[drm] Disabling AGP\n"); - rdev->flags &= ~RADEON_IS_AGP; - rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + radeon_agp_disable(rdev); } else { rdev->mc.gtt_location = rdev->mc.agp_base; } @@ -165,6 +171,34 @@ static void r420_clock_resume(struct radeon_device *rdev) WREG32_PLL(R_00000D_SCLK_CNTL, sclk_cntl); } +static void r420_cp_errata_init(struct radeon_device *rdev) +{ + /* RV410 and R420 can lock up if CP DMA to host memory happens + * while the 2D engine is busy. + * + * The proper workaround is to queue a RESYNC at the beginning + * of the CP init, apparently. + */ + radeon_scratch_get(rdev, &rdev->config.r300.resync_scratch); + radeon_ring_lock(rdev, 8); + radeon_ring_write(rdev, PACKET0(R300_CP_RESYNC_ADDR, 1)); + radeon_ring_write(rdev, rdev->config.r300.resync_scratch); + radeon_ring_write(rdev, 0xDEADBEEF); + radeon_ring_unlock_commit(rdev); +} + +static void r420_cp_errata_fini(struct radeon_device *rdev) +{ + /* Catch the RESYNC we dispatched all the way back, + * at the very beginning of the CP init. + */ + radeon_ring_lock(rdev, 8); + radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, R300_RB3D_DC_FINISH); + radeon_ring_unlock_commit(rdev); + radeon_scratch_free(rdev, rdev->config.r300.resync_scratch); +} + static int r420_startup(struct radeon_device *rdev) { int r; @@ -190,12 +224,14 @@ static int r420_startup(struct radeon_device *rdev) r420_pipes_init(rdev); /* Enable IRQ */ r100_irq_set(rdev); + rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ r = r100_cp_init(rdev, 1024 * 1024); if (r) { dev_err(rdev->dev, "failled initializing CP (%d).\n", r); return r; } + r420_cp_errata_init(rdev); r = r100_wb_init(rdev); if (r) { dev_err(rdev->dev, "failled initializing WB (%d).\n", r); @@ -238,6 +274,7 @@ int r420_resume(struct radeon_device *rdev) int r420_suspend(struct radeon_device *rdev) { + r420_cp_errata_fini(rdev); r100_cp_disable(rdev); r100_wb_disable(rdev); r100_irq_disable(rdev); @@ -346,22 +383,21 @@ int r420_init(struct radeon_device *rdev) if (r) return r; } - r300_set_reg_safe(rdev); + r420_set_reg_safe(rdev); rdev->accel_working = true; r = r420_startup(rdev); if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - r420_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); + radeon_irq_kms_fini(rdev); if (rdev->flags & RADEON_IS_PCIE) rv370_pcie_gart_fini(rdev); if (rdev->flags & RADEON_IS_PCI) r100_pci_gart_fini(rdev); radeon_agp_fini(rdev); - radeon_irq_kms_fini(rdev); rdev->accel_working = false; } return 0; diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 0f3843b..ddf5731 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -186,6 +186,7 @@ static int r520_startup(struct radeon_device *rdev) } /* Enable IRQ */ rs600_irq_set(rdev); + rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ r = r100_cp_init(rdev, 1024 * 1024); if (r) { @@ -293,13 +294,12 @@ int r520_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - rv515_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); + radeon_irq_kms_fini(rdev); rv370_pcie_gart_fini(rdev); radeon_agp_fini(rdev); - radeon_irq_kms_fini(rdev); rdev->accel_working = false; } return 0; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index a0ac3c1..2ffcf5a 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -285,7 +285,8 @@ void r600_hpd_init(struct radeon_device *rdev) } } } - r600_irq_set(rdev); + if (rdev->irq.installed) + r600_irq_set(rdev); } void r600_hpd_fini(struct radeon_device *rdev) @@ -623,7 +624,6 @@ int r600_mc_init(struct radeon_device *rdev) fixed20_12 a; u32 tmp; int chansize, numchan; - int r; /* Get VRAM informations */ rdev->mc.vram_is_ddr = true; @@ -666,9 +666,6 @@ int r600_mc_init(struct radeon_device *rdev) rdev->mc.real_vram_size = rdev->mc.aper_size; if (rdev->flags & RADEON_IS_AGP) { - r = radeon_agp_init(rdev); - if (r) - return r; /* gtt_size is setup by radeon_agp_init */ rdev->mc.gtt_location = rdev->mc.agp_base; tmp = 0xFFFFFFFFUL - rdev->mc.agp_base - rdev->mc.gtt_size; @@ -726,6 +723,10 @@ int r600_mc_init(struct radeon_device *rdev) a.full = rfixed_const(100); rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk); rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); + + if (rdev->flags & RADEON_IS_IGP) + rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); + return 0; } @@ -1384,11 +1385,6 @@ void r600_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v) (void)RREG32(PCIE_PORT_DATA); } -void r600_hdp_flush(struct radeon_device *rdev) -{ - WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); -} - /* * CP & Ring */ @@ -1658,6 +1654,12 @@ void r600_ring_init(struct radeon_device *rdev, unsigned ring_size) rdev->cp.align_mask = 16 - 1; } +void r600_cp_fini(struct radeon_device *rdev) +{ + r600_cp_stop(rdev); + radeon_ring_fini(rdev); +} + /* * GPU scratch registers helpers function. @@ -1785,28 +1787,31 @@ void r600_fence_ring_emit(struct radeon_device *rdev, radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1)); radeon_ring_write(rdev, ((rdev->fence_drv.scratch_reg - PACKET3_SET_CONFIG_REG_OFFSET) >> 2)); radeon_ring_write(rdev, fence->seq); + radeon_ring_write(rdev, PACKET0(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0)); + radeon_ring_write(rdev, 1); /* CP_INTERRUPT packet 3 no longer exists, use packet 0 */ radeon_ring_write(rdev, PACKET0(CP_INT_STATUS, 0)); radeon_ring_write(rdev, RB_INT_STAT); } -int r600_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, - uint64_t dst_offset, - unsigned num_pages, - struct radeon_fence *fence) -{ - /* FIXME: implement */ - return 0; -} - int r600_copy_blit(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_pages, struct radeon_fence *fence) { - r600_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE); + int r; + + mutex_lock(&rdev->r600_blit.mutex); + rdev->r600_blit.vb_ib = NULL; + r = r600_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE); + if (r) { + if (rdev->r600_blit.vb_ib) + radeon_ib_free(rdev, &rdev->r600_blit.vb_ib); + mutex_unlock(&rdev->r600_blit.mutex); + return r; + } r600_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE); r600_blit_done_copy(rdev, fence); + mutex_unlock(&rdev->r600_blit.mutex); return 0; } @@ -1862,26 +1867,25 @@ int r600_startup(struct radeon_device *rdev) return r; } r600_gpu_init(rdev); - - if (!rdev->r600_blit.shader_obj) { - r = r600_blit_init(rdev); + r = r600_blit_init(rdev); + if (r) { + r600_blit_fini(rdev); + rdev->asic->copy = NULL; + dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); + } + /* pin copy shader into vram */ + if (rdev->r600_blit.shader_obj) { + r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); + if (unlikely(r != 0)) + return r; + r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM, + &rdev->r600_blit.shader_gpu_addr); + radeon_bo_unreserve(rdev->r600_blit.shader_obj); if (r) { - DRM_ERROR("radeon: failed blitter (%d).\n", r); + dev_err(rdev->dev, "(%d) pin blit object failed\n", r); return r; } } - - r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); - if (unlikely(r != 0)) - return r; - r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM, - &rdev->r600_blit.shader_gpu_addr); - radeon_bo_unreserve(rdev->r600_blit.shader_obj); - if (r) { - dev_err(rdev->dev, "(%d) pin blit object failed\n", r); - return r; - } - /* Enable IRQ */ r = r600_irq_init(rdev); if (r) { @@ -1946,6 +1950,13 @@ int r600_resume(struct radeon_device *rdev) DRM_ERROR("radeon: failled testing IB (%d).\n", r); return r; } + + r = r600_audio_init(rdev); + if (r) { + DRM_ERROR("radeon: audio resume failed\n"); + return r; + } + return r; } @@ -1953,17 +1964,21 @@ int r600_suspend(struct radeon_device *rdev) { int r; + r600_audio_fini(rdev); /* FIXME: we should wait for ring to be empty */ r600_cp_stop(rdev); rdev->cp.ready = false; + r600_irq_suspend(rdev); r600_wb_disable(rdev); r600_pcie_gart_disable(rdev); /* unpin shaders bo */ - r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); - if (unlikely(r != 0)) - return r; - radeon_bo_unpin(rdev->r600_blit.shader_obj); - radeon_bo_unreserve(rdev->r600_blit.shader_obj); + if (rdev->r600_blit.shader_obj) { + r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); + if (!r) { + radeon_bo_unpin(rdev->r600_blit.shader_obj); + radeon_bo_unreserve(rdev->r600_blit.shader_obj); + } + } return 0; } @@ -2024,6 +2039,11 @@ int r600_init(struct radeon_device *rdev) r = radeon_fence_driver_init(rdev); if (r) return r; + if (rdev->flags & RADEON_IS_AGP) { + r = radeon_agp_init(rdev); + if (r) + radeon_agp_disable(rdev); + } r = r600_mc_init(rdev); if (r) return r; @@ -2049,22 +2069,25 @@ int r600_init(struct radeon_device *rdev) rdev->accel_working = true; r = r600_startup(rdev); if (r) { - r600_suspend(rdev); + dev_err(rdev->dev, "disabling GPU acceleration\n"); + r600_cp_fini(rdev); r600_wb_fini(rdev); - radeon_ring_fini(rdev); + r600_irq_fini(rdev); + radeon_irq_kms_fini(rdev); r600_pcie_gart_fini(rdev); rdev->accel_working = false; } if (rdev->accel_working) { r = radeon_ib_pool_init(rdev); if (r) { - DRM_ERROR("radeon: failed initializing IB pool (%d).\n", r); - rdev->accel_working = false; - } - r = r600_ib_test(rdev); - if (r) { - DRM_ERROR("radeon: failed testing IB (%d).\n", r); + dev_err(rdev->dev, "IB initialization failed (%d).\n", r); rdev->accel_working = false; + } else { + r = r600_ib_test(rdev); + if (r) { + dev_err(rdev->dev, "IB test failed (%d).\n", r); + rdev->accel_working = false; + } } } @@ -2076,21 +2099,17 @@ int r600_init(struct radeon_device *rdev) void r600_fini(struct radeon_device *rdev) { - /* Suspend operations */ - r600_suspend(rdev); - r600_audio_fini(rdev); r600_blit_fini(rdev); + r600_cp_fini(rdev); + r600_wb_fini(rdev); r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); - radeon_ring_fini(rdev); - r600_wb_fini(rdev); r600_pcie_gart_fini(rdev); + radeon_agp_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); radeon_clocks_fini(rdev); - if (rdev->flags & RADEON_IS_AGP) - radeon_agp_fini(rdev); radeon_bo_fini(rdev); radeon_atombios_fini(rdev); kfree(rdev->bios); @@ -2196,14 +2215,14 @@ void r600_ih_ring_init(struct radeon_device *rdev, unsigned ring_size) rb_bufsz = drm_order(ring_size / 4); ring_size = (1 << rb_bufsz) * 4; rdev->ih.ring_size = ring_size; - rdev->ih.align_mask = 4 - 1; + rdev->ih.ptr_mask = rdev->ih.ring_size - 1; + rdev->ih.rptr = 0; } -static int r600_ih_ring_alloc(struct radeon_device *rdev, unsigned ring_size) +static int r600_ih_ring_alloc(struct radeon_device *rdev) { int r; - rdev->ih.ring_size = ring_size; /* Allocate ring buffer */ if (rdev->ih.ring_obj == NULL) { r = radeon_bo_create(rdev, NULL, rdev->ih.ring_size, @@ -2233,9 +2252,6 @@ static int r600_ih_ring_alloc(struct radeon_device *rdev, unsigned ring_size) return r; } } - rdev->ih.ptr_mask = (rdev->cp.ring_size / 4) - 1; - rdev->ih.rptr = 0; - return 0; } @@ -2385,7 +2401,7 @@ int r600_irq_init(struct radeon_device *rdev) u32 interrupt_cntl, ih_cntl, ih_rb_cntl; /* allocate ring */ - ret = r600_ih_ring_alloc(rdev, rdev->ih.ring_size); + ret = r600_ih_ring_alloc(rdev); if (ret) return ret; @@ -2448,10 +2464,15 @@ int r600_irq_init(struct radeon_device *rdev) return ret; } -void r600_irq_fini(struct radeon_device *rdev) +void r600_irq_suspend(struct radeon_device *rdev) { r600_disable_interrupts(rdev); r600_rlc_stop(rdev); +} + +void r600_irq_fini(struct radeon_device *rdev) +{ + r600_irq_suspend(rdev); r600_ih_ring_fini(rdev); } @@ -2461,9 +2482,17 @@ int r600_irq_set(struct radeon_device *rdev) u32 mode_int = 0; u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0; + if (!rdev->irq.installed) { + WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); + return -EINVAL; + } /* don't enable anything if the ih is disabled */ - if (!rdev->ih.enabled) + if (!rdev->ih.enabled) { + r600_disable_interrupts(rdev); + /* force the active interrupt state to all disabled */ + r600_disable_interrupt_state(rdev); return 0; + } if (ASIC_IS_DCE3(rdev)) { hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN; @@ -2633,16 +2662,18 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { - WARN_ON(1); - /* XXX deal with overflow */ - DRM_ERROR("IH RB overflow\n"); + /* When a ring buffer overflow happen start parsing interrupt + * from the last not overwritten vector (wptr + 16). Hopefully + * this should allow us to catchup. + */ + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", + wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); } - wptr = wptr & WPTR_OFFSET_MASK; - - return wptr; + return (wptr & rdev->ih.ptr_mask); } /* r600 IV Ring @@ -2678,12 +2709,13 @@ int r600_irq_process(struct radeon_device *rdev) u32 wptr = r600_get_ih_wptr(rdev); u32 rptr = rdev->ih.rptr; u32 src_id, src_data; - u32 last_entry = rdev->ih.ring_size - 16; u32 ring_index, disp_int, disp_int_cont, disp_int_cont2; unsigned long flags; bool queue_hotplug = false; DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); + if (!rdev->ih.enabled) + return IRQ_NONE; spin_lock_irqsave(&rdev->ih.lock, flags); @@ -2724,7 +2756,7 @@ restart_ih: } break; default: - DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); break; } break; @@ -2744,7 +2776,7 @@ restart_ih: } break; default: - DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); break; } break; @@ -2793,7 +2825,7 @@ restart_ih: } break; default: - DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); break; } break; @@ -2807,15 +2839,13 @@ restart_ih: DRM_DEBUG("IH: CP EOP\n"); break; default: - DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); break; } /* wptr/rptr are in bytes! */ - if (rptr == last_entry) - rptr = 0; - else - rptr += 16; + rptr += 16; + rptr &= rdev->ih.ptr_mask; } /* make sure wptr hasn't changed while processing */ wptr = r600_get_ih_wptr(rdev); @@ -2883,3 +2913,18 @@ int r600_debugfs_mc_info_init(struct radeon_device *rdev) return 0; #endif } + +/** + * r600_ioctl_wait_idle - flush host path cache on wait idle ioctl + * rdev: radeon device structure + * bo: buffer object struct which userspace is waiting for idle + * + * Some R6XX/R7XX doesn't seems to take into account HDP flush performed + * through ring buffer, this leads to corruption in rendering, see + * http://bugzilla.kernel.org/show_bug.cgi?id=15186 to avoid this we + * directly perform HDP flush by writing register through MMIO. + */ +void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo) +{ + WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); +} diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index 99e2c38..0dcb690 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c @@ -35,7 +35,7 @@ */ static int r600_audio_chipset_supported(struct radeon_device *rdev) { - return rdev->family >= CHIP_R600 + return (rdev->family >= CHIP_R600 && rdev->family < CHIP_RV710) || rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740; @@ -261,7 +261,6 @@ void r600_audio_fini(struct radeon_device *rdev) if (!r600_audio_chipset_supported(rdev)) return; - WREG32_P(R600_AUDIO_ENABLE, 0x0, ~0x81000000); - del_timer(&rdev->audio_timer); + WREG32_P(R600_AUDIO_ENABLE, 0x0, ~0x81000000); } diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index 9aecafb..446b765 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -449,6 +449,7 @@ int r600_blit_init(struct radeon_device *rdev) u32 packet2s[16]; int num_packet2s = 0; + mutex_init(&rdev->r600_blit.mutex); rdev->r600_blit.state_offset = 0; if (rdev->family >= CHIP_RV770) @@ -512,14 +513,16 @@ void r600_blit_fini(struct radeon_device *rdev) { int r; + if (rdev->r600_blit.shader_obj == NULL) + return; + /* If we can't reserve the bo, unref should be enough to destroy + * it when it becomes idle. + */ r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); - if (unlikely(r != 0)) { - dev_err(rdev->dev, "(%d) can't finish r600 blit\n", r); - goto out_unref; + if (!r) { + radeon_bo_unpin(rdev->r600_blit.shader_obj); + radeon_bo_unreserve(rdev->r600_blit.shader_obj); } - radeon_bo_unpin(rdev->r600_blit.shader_obj); - radeon_bo_unreserve(rdev->r600_blit.shader_obj); -out_unref: radeon_bo_unref(&rdev->r600_blit.shader_obj); } @@ -540,9 +543,6 @@ int r600_vb_ib_get(struct radeon_device *rdev) void r600_vb_ib_put(struct radeon_device *rdev) { radeon_fence_emit(rdev, rdev->r600_blit.vb_ib->fence); - mutex_lock(&rdev->ib_pool.mutex); - list_add_tail(&rdev->r600_blit.vb_ib->list, &rdev->ib_pool.scheduled_ibs); - mutex_unlock(&rdev->ib_pool.mutex); radeon_ib_free(rdev, &rdev->r600_blit.vb_ib); } @@ -555,7 +555,8 @@ int r600_blit_prepare_copy(struct radeon_device *rdev, int size_bytes) int dwords_per_loop = 76, num_loops; r = r600_vb_ib_get(rdev); - WARN_ON(r); + if (r) + return r; /* set_render_target emits 2 extra dwords on rv6xx */ if (rdev->family > CHIP_R600 && rdev->family < CHIP_RV770) @@ -577,11 +578,12 @@ int r600_blit_prepare_copy(struct radeon_device *rdev, int size_bytes) ring_size = num_loops * dwords_per_loop; /* set default + shaders */ ring_size += 40; /* shaders + def state */ - ring_size += 5; /* fence emit for VB IB */ + ring_size += 7; /* fence emit for VB IB */ ring_size += 5; /* done copy */ - ring_size += 5; /* fence emit for done copy */ + ring_size += 7; /* fence emit for done copy */ r = radeon_ring_lock(rdev, ring_size); - WARN_ON(r); + if (r) + return r; set_default_state(rdev); /* 14 */ set_shaders(rdev); /* 26 */ diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index 6d5a711..75bcf35 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -1428,9 +1428,12 @@ static void r700_gfx_init(struct drm_device *dev, gb_tiling_config |= R600_BANK_SWAPS(1); - backend_map = r700_get_tile_pipe_to_backend_map(dev_priv->r600_max_tile_pipes, - dev_priv->r600_max_backends, - (0xff << dev_priv->r600_max_backends) & 0xff); + if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV740) + backend_map = 0x28; + else + backend_map = r700_get_tile_pipe_to_backend_map(dev_priv->r600_max_tile_pipes, + dev_priv->r600_max_backends, + (0xff << dev_priv->r600_max_backends) & 0xff); gb_tiling_config |= R600_BACKEND_MAP(backend_map); cc_gc_shader_pipe_config = diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 44060b9..e4c45ec 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -36,6 +36,10 @@ static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p, typedef int (*next_reloc_t)(struct radeon_cs_parser*, struct radeon_cs_reloc**); static next_reloc_t r600_cs_packet_next_reloc = &r600_cs_packet_next_reloc_mm; +struct r600_cs_track { + u32 cb_color0_base_last; +}; + /** * r600_cs_packet_parse() - parse cp packet and point ib index to next packet * @parser: parser structure holding parsing context. @@ -177,6 +181,28 @@ static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p, } /** + * r600_cs_packet_next_is_pkt3_nop() - test if next packet is packet3 nop for reloc + * @parser: parser structure holding parsing context. + * + * Check next packet is relocation packet3, do bo validation and compute + * GPU offset using the provided start. + **/ +static inline int r600_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p) +{ + struct radeon_cs_packet p3reloc; + int r; + + r = r600_cs_packet_parse(p, &p3reloc, p->idx); + if (r) { + return 0; + } + if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) { + return 0; + } + return 1; +} + +/** * r600_cs_packet_next_vline() - parse userspace VLINE packet * @parser: parser structure holding parsing context. * @@ -337,6 +363,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt) { struct radeon_cs_reloc *reloc; + struct r600_cs_track *track; volatile u32 *ib; unsigned idx; unsigned i; @@ -344,6 +371,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p, int r; u32 idx_value; + track = (struct r600_cs_track *)p->track; ib = p->ib->ptr; idx = pkt->idx + 1; idx_value = radeon_get_ib_value(p, idx); @@ -503,9 +531,60 @@ static int r600_packet3_check(struct radeon_cs_parser *p, for (i = 0; i < pkt->count; i++) { reg = start_reg + (4 * i); switch (reg) { + /* This register were added late, there is userspace + * which does provide relocation for those but set + * 0 offset. In order to avoid breaking old userspace + * we detect this and set address to point to last + * CB_COLOR0_BASE, note that if userspace doesn't set + * CB_COLOR0_BASE before this register we will report + * error. Old userspace always set CB_COLOR0_BASE + * before any of this. + */ + case R_0280E0_CB_COLOR0_FRAG: + case R_0280E4_CB_COLOR1_FRAG: + case R_0280E8_CB_COLOR2_FRAG: + case R_0280EC_CB_COLOR3_FRAG: + case R_0280F0_CB_COLOR4_FRAG: + case R_0280F4_CB_COLOR5_FRAG: + case R_0280F8_CB_COLOR6_FRAG: + case R_0280FC_CB_COLOR7_FRAG: + case R_0280C0_CB_COLOR0_TILE: + case R_0280C4_CB_COLOR1_TILE: + case R_0280C8_CB_COLOR2_TILE: + case R_0280CC_CB_COLOR3_TILE: + case R_0280D0_CB_COLOR4_TILE: + case R_0280D4_CB_COLOR5_TILE: + case R_0280D8_CB_COLOR6_TILE: + case R_0280DC_CB_COLOR7_TILE: + if (!r600_cs_packet_next_is_pkt3_nop(p)) { + if (!track->cb_color0_base_last) { + dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg); + return -EINVAL; + } + ib[idx+1+i] = track->cb_color0_base_last; + printk_once(KERN_WARNING "radeon: You have old & broken userspace " + "please consider updating mesa & xf86-video-ati\n"); + } else { + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); + return -EINVAL; + } + ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + } + break; case DB_DEPTH_BASE: case DB_HTILE_DATA_BASE: case CB_COLOR0_BASE: + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->cb_color0_base_last = ib[idx+1+i]; + break; case CB_COLOR1_BASE: case CB_COLOR2_BASE: case CB_COLOR3_BASE: @@ -678,8 +757,11 @@ static int r600_packet3_check(struct radeon_cs_parser *p, int r600_cs_parse(struct radeon_cs_parser *p) { struct radeon_cs_packet pkt; + struct r600_cs_track *track; int r; + track = kzalloc(sizeof(*track), GFP_KERNEL); + p->track = track; do { r = r600_cs_packet_parse(p, &pkt, p->idx); if (r) { @@ -757,6 +839,7 @@ int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp, /* initialize parser */ memset(&parser, 0, sizeof(struct radeon_cs_parser)); parser.filp = filp; + parser.dev = &dev->pdev->dev; parser.rdev = NULL; parser.family = family; parser.ib = &fake_ib; diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 05894ed..3048088 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -882,4 +882,29 @@ #define S_000E60_SOFT_RESET_VMC(x) (((x) & 1) << 17) #define R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480 + +#define R_0280E0_CB_COLOR0_FRAG 0x0280E0 +#define S_0280E0_BASE_256B(x) (((x) & 0xFFFFFFFF) << 0) +#define G_0280E0_BASE_256B(x) (((x) >> 0) & 0xFFFFFFFF) +#define C_0280E0_BASE_256B 0x00000000 +#define R_0280E4_CB_COLOR1_FRAG 0x0280E4 +#define R_0280E8_CB_COLOR2_FRAG 0x0280E8 +#define R_0280EC_CB_COLOR3_FRAG 0x0280EC +#define R_0280F0_CB_COLOR4_FRAG 0x0280F0 +#define R_0280F4_CB_COLOR5_FRAG 0x0280F4 +#define R_0280F8_CB_COLOR6_FRAG 0x0280F8 +#define R_0280FC_CB_COLOR7_FRAG 0x0280FC +#define R_0280C0_CB_COLOR0_TILE 0x0280C0 +#define S_0280C0_BASE_256B(x) (((x) & 0xFFFFFFFF) << 0) +#define G_0280C0_BASE_256B(x) (((x) >> 0) & 0xFFFFFFFF) +#define C_0280C0_BASE_256B 0x00000000 +#define R_0280C4_CB_COLOR1_TILE 0x0280C4 +#define R_0280C8_CB_COLOR2_TILE 0x0280C8 +#define R_0280CC_CB_COLOR3_TILE 0x0280CC +#define R_0280D0_CB_COLOR4_TILE 0x0280D0 +#define R_0280D4_CB_COLOR5_TILE 0x0280D4 +#define R_0280D8_CB_COLOR6_TILE 0x0280D8 +#define R_0280DC_CB_COLOR7_TILE 0x0280DC + + #endif diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 53b5560..c0356bb 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -96,6 +96,7 @@ extern int radeon_audio; * symbol; */ #define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */ +/* RADEON_IB_POOL_SIZE must be a power of 2 */ #define RADEON_IB_POOL_SIZE 16 #define RADEON_DEBUGFS_MAX_NUM_FILES 32 #define RADEONFB_CONN_LIMIT 4 @@ -319,10 +320,12 @@ struct radeon_mc { u64 real_vram_size; int vram_mtrr; bool vram_is_ddr; + bool igp_sideport_enabled; }; int radeon_mc_setup(struct radeon_device *rdev); - +bool radeon_combios_sideport_present(struct radeon_device *rdev); +bool radeon_atombios_sideport_present(struct radeon_device *rdev); /* * GPU scratch registers structures, functions & helpers @@ -361,11 +364,12 @@ void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev); */ struct radeon_ib { struct list_head list; - unsigned long idx; + unsigned idx; uint64_t gpu_addr; struct radeon_fence *fence; - uint32_t *ptr; + uint32_t *ptr; uint32_t length_dw; + bool free; }; /* @@ -375,10 +379,9 @@ struct radeon_ib { struct radeon_ib_pool { struct mutex mutex; struct radeon_bo *robj; - struct list_head scheduled_ibs; struct radeon_ib ibs[RADEON_IB_POOL_SIZE]; bool ready; - DECLARE_BITMAP(alloc_bm, RADEON_IB_POOL_SIZE); + unsigned head_id; }; struct radeon_cp { @@ -408,13 +411,13 @@ struct r600_ih { unsigned wptr_old; unsigned ring_size; uint64_t gpu_addr; - uint32_t align_mask; uint32_t ptr_mask; spinlock_t lock; bool enabled; }; struct r600_blit { + struct mutex mutex; struct radeon_bo *shader_obj; u64 shader_gpu_addr; u32 vs_offset, ps_offset; @@ -463,6 +466,7 @@ struct radeon_cs_chunk { }; struct radeon_cs_parser { + struct device *dev; struct radeon_device *rdev; struct drm_file *filp; /* chunks */ @@ -654,11 +658,17 @@ struct radeon_asic { uint32_t offset, uint32_t obj_size); int (*clear_surface_reg)(struct radeon_device *rdev, int reg); void (*bandwidth_update)(struct radeon_device *rdev); - void (*hdp_flush)(struct radeon_device *rdev); void (*hpd_init)(struct radeon_device *rdev); void (*hpd_fini)(struct radeon_device *rdev); bool (*hpd_sense)(struct radeon_device *rdev, enum radeon_hpd_id hpd); void (*hpd_set_polarity)(struct radeon_device *rdev, enum radeon_hpd_id hpd); + /* ioctl hw specific callback. Some hw might want to perform special + * operation on specific ioctl. For instance on wait idle some hw + * might want to perform and HDP flush through MMIO as it seems that + * some R6XX/R7XX hw doesn't take HDP flush into account if programmed + * through ring. + */ + void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); }; /* @@ -667,11 +677,14 @@ struct radeon_asic { struct r100_asic { const unsigned *reg_safe_bm; unsigned reg_safe_bm_size; + u32 hdp_cntl; }; struct r300_asic { const unsigned *reg_safe_bm; unsigned reg_safe_bm_size; + u32 resync_scratch; + u32 hdp_cntl; }; struct r600_asic { @@ -843,7 +856,7 @@ void r600_kms_blit_copy(struct radeon_device *rdev, static inline uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg) { - if (reg < 0x10000) + if (reg < rdev->rmmio_size) return readl(((void __iomem *)rdev->rmmio) + reg); else { writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); @@ -853,7 +866,7 @@ static inline uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg) static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) { - if (reg < 0x10000) + if (reg < rdev->rmmio_size) writel(v, ((void __iomem *)rdev->rmmio) + reg); else { writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); @@ -1007,13 +1020,14 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->set_surface_reg((rdev), (r), (f), (p), (o), (s))) #define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->clear_surface_reg((rdev), (r))) #define radeon_bandwidth_update(rdev) (rdev)->asic->bandwidth_update((rdev)) -#define radeon_hdp_flush(rdev) (rdev)->asic->hdp_flush((rdev)) #define radeon_hpd_init(rdev) (rdev)->asic->hpd_init((rdev)) #define radeon_hpd_fini(rdev) (rdev)->asic->hpd_fini((rdev)) #define radeon_hpd_sense(rdev, hpd) (rdev)->asic->hpd_sense((rdev), (hpd)) #define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd)) /* Common functions */ +/* AGP */ +extern void radeon_agp_disable(struct radeon_device *rdev); extern int radeon_gart_table_vram_pin(struct radeon_device *rdev); extern int radeon_modeset_init(struct radeon_device *rdev); extern void radeon_modeset_fini(struct radeon_device *rdev); @@ -1137,6 +1151,7 @@ extern bool r600_card_posted(struct radeon_device *rdev); extern void r600_cp_stop(struct radeon_device *rdev); extern void r600_ring_init(struct radeon_device *rdev, unsigned ring_size); extern int r600_cp_resume(struct radeon_device *rdev); +extern void r600_cp_fini(struct radeon_device *rdev); extern int r600_count_pipe_bits(uint32_t val); extern int r600_gart_clear_page(struct radeon_device *rdev, int i); extern int r600_mc_wait_for_idle(struct radeon_device *rdev); @@ -1157,7 +1172,8 @@ extern int r600_irq_init(struct radeon_device *rdev); extern void r600_irq_fini(struct radeon_device *rdev); extern void r600_ih_ring_init(struct radeon_device *rdev, unsigned ring_size); extern int r600_irq_set(struct radeon_device *rdev); - +extern void r600_irq_suspend(struct radeon_device *rdev); +/* r600 audio */ extern int r600_audio_init(struct radeon_device *rdev); extern int r600_audio_tmds_index(struct drm_encoder *encoder); extern void r600_audio_set_clock(struct drm_encoder *encoder, int clock); diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index 54bf49a..c0681a55 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -144,9 +144,19 @@ int radeon_agp_init(struct radeon_device *rdev) ret = drm_agp_info(rdev->ddev, &info); if (ret) { + drm_agp_release(rdev->ddev); DRM_ERROR("Unable to get AGP info: %d\n", ret); return ret; } + + if (rdev->ddev->agp->agp_info.aper_size < 32) { + drm_agp_release(rdev->ddev); + dev_warn(rdev->dev, "AGP aperture too small (%zuM) " + "need at least 32M, disabling AGP\n", + rdev->ddev->agp->agp_info.aper_size); + return -EINVAL; + } + mode.mode = info.mode; agp_status = (RREG32(RADEON_AGP_STATUS) | RADEON_AGPv3_MODE) & mode.mode; is_v3 = !!(agp_status & RADEON_AGPv3_MODE); @@ -221,6 +231,7 @@ int radeon_agp_init(struct radeon_device *rdev) ret = drm_agp_enable(rdev->ddev, mode); if (ret) { DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode); + drm_agp_release(rdev->ddev); return ret; } @@ -252,10 +263,8 @@ void radeon_agp_resume(struct radeon_device *rdev) void radeon_agp_fini(struct radeon_device *rdev) { #if __OS_HAS_AGP - if (rdev->flags & RADEON_IS_AGP) { - if (rdev->ddev->agp && rdev->ddev->agp->acquired) { - drm_agp_release(rdev->ddev); - } + if (rdev->ddev->agp && rdev->ddev->agp->acquired) { + drm_agp_release(rdev->ddev); } #endif } diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index eb29217..05ee1ae 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -77,7 +77,6 @@ int r100_clear_surface_reg(struct radeon_device *rdev, int reg); void r100_bandwidth_update(struct radeon_device *rdev); void r100_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int r100_ring_test(struct radeon_device *rdev); -void r100_hdp_flush(struct radeon_device *rdev); void r100_hpd_init(struct radeon_device *rdev); void r100_hpd_fini(struct radeon_device *rdev); bool r100_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); @@ -114,11 +113,11 @@ static struct radeon_asic r100_asic = { .set_surface_reg = r100_set_surface_reg, .clear_surface_reg = r100_clear_surface_reg, .bandwidth_update = &r100_bandwidth_update, - .hdp_flush = &r100_hdp_flush, .hpd_init = &r100_hpd_init, .hpd_fini = &r100_hpd_fini, .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; @@ -174,11 +173,11 @@ static struct radeon_asic r300_asic = { .set_surface_reg = r100_set_surface_reg, .clear_surface_reg = r100_clear_surface_reg, .bandwidth_update = &r100_bandwidth_update, - .hdp_flush = &r100_hdp_flush, .hpd_init = &r100_hpd_init, .hpd_fini = &r100_hpd_fini, .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; /* @@ -218,11 +217,11 @@ static struct radeon_asic r420_asic = { .set_surface_reg = r100_set_surface_reg, .clear_surface_reg = r100_clear_surface_reg, .bandwidth_update = &r100_bandwidth_update, - .hdp_flush = &r100_hdp_flush, .hpd_init = &r100_hpd_init, .hpd_fini = &r100_hpd_fini, .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; @@ -267,11 +266,11 @@ static struct radeon_asic rs400_asic = { .set_surface_reg = r100_set_surface_reg, .clear_surface_reg = r100_clear_surface_reg, .bandwidth_update = &r100_bandwidth_update, - .hdp_flush = &r100_hdp_flush, .hpd_init = &r100_hpd_init, .hpd_fini = &r100_hpd_fini, .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; @@ -324,11 +323,11 @@ static struct radeon_asic rs600_asic = { .set_pcie_lanes = NULL, .set_clock_gating = &radeon_atom_set_clock_gating, .bandwidth_update = &rs600_bandwidth_update, - .hdp_flush = &r100_hdp_flush, .hpd_init = &rs600_hpd_init, .hpd_fini = &rs600_hpd_fini, .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; @@ -372,11 +371,11 @@ static struct radeon_asic rs690_asic = { .set_surface_reg = r100_set_surface_reg, .clear_surface_reg = r100_clear_surface_reg, .bandwidth_update = &rs690_bandwidth_update, - .hdp_flush = &r100_hdp_flush, .hpd_init = &rs600_hpd_init, .hpd_fini = &rs600_hpd_fini, .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; @@ -424,11 +423,11 @@ static struct radeon_asic rv515_asic = { .set_surface_reg = r100_set_surface_reg, .clear_surface_reg = r100_clear_surface_reg, .bandwidth_update = &rv515_bandwidth_update, - .hdp_flush = &r100_hdp_flush, .hpd_init = &rs600_hpd_init, .hpd_fini = &rs600_hpd_fini, .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; @@ -467,11 +466,11 @@ static struct radeon_asic r520_asic = { .set_surface_reg = r100_set_surface_reg, .clear_surface_reg = r100_clear_surface_reg, .bandwidth_update = &rv515_bandwidth_update, - .hdp_flush = &r100_hdp_flush, .hpd_init = &rs600_hpd_init, .hpd_fini = &rs600_hpd_fini, .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; /* @@ -508,12 +507,12 @@ int r600_ring_test(struct radeon_device *rdev); int r600_copy_blit(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_pages, struct radeon_fence *fence); -void r600_hdp_flush(struct radeon_device *rdev); void r600_hpd_init(struct radeon_device *rdev); void r600_hpd_fini(struct radeon_device *rdev); bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void r600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); +extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); static struct radeon_asic r600_asic = { .init = &r600_init, @@ -544,11 +543,11 @@ static struct radeon_asic r600_asic = { .set_surface_reg = r600_set_surface_reg, .clear_surface_reg = r600_clear_surface_reg, .bandwidth_update = &rv515_bandwidth_update, - .hdp_flush = &r600_hdp_flush, .hpd_init = &r600_hpd_init, .hpd_fini = &r600_hpd_fini, .hpd_sense = &r600_hpd_sense, .hpd_set_polarity = &r600_hpd_set_polarity, + .ioctl_wait_idle = r600_ioctl_wait_idle, }; /* @@ -589,11 +588,11 @@ static struct radeon_asic rv770_asic = { .set_surface_reg = r600_set_surface_reg, .clear_surface_reg = r600_clear_surface_reg, .bandwidth_update = &rv515_bandwidth_update, - .hdp_flush = &r600_hdp_flush, .hpd_init = &r600_hpd_init, .hpd_fini = &r600_hpd_fini, .hpd_sense = &r600_hpd_sense, .hpd_set_polarity = &r600_hpd_set_polarity, + .ioctl_wait_idle = r600_ioctl_wait_idle, }; #endif diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 321044b..4d88315 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -114,6 +114,7 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev i2c.i2c_id = gpio->sucI2cId.ucAccess; i2c.valid = true; + break; } } @@ -205,6 +206,15 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, *connector_type = DRM_MODE_CONNECTOR_DVID; } + /* Asrock RS600 board lists the DVI port as HDMI */ + if ((dev->pdev->device == 0x7941) && + (dev->pdev->subsystem_vendor == 0x1849) && + (dev->pdev->subsystem_device == 0x7941)) { + 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) && @@ -286,6 +296,15 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, *connector_type = DRM_MODE_CONNECTOR_DVID; } + /* XFX Pine Group device rv730 reports no VGA DDC lines + * even though they are wired up to record 0x93 + */ + if ((dev->pdev->device == 0x9498) && + (dev->pdev->subsystem_vendor == 0x1682) && + (dev->pdev->subsystem_device == 0x2452)) { + struct radeon_device *rdev = dev->dev_private; + *i2c_bus = radeon_lookup_i2c_gpio(rdev, 0x93); + } return true; } @@ -345,7 +364,9 @@ const int object_connector_convert[] = { DRM_MODE_CONNECTOR_Unknown, DRM_MODE_CONNECTOR_Unknown, DRM_MODE_CONNECTOR_Unknown, - DRM_MODE_CONNECTOR_DisplayPort + DRM_MODE_CONNECTOR_DisplayPort, + DRM_MODE_CONNECTOR_eDP, + DRM_MODE_CONNECTOR_Unknown }; bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) @@ -935,6 +956,43 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) return false; } +union igp_info { + struct _ATOM_INTEGRATED_SYSTEM_INFO info; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; +}; + +bool radeon_atombios_sideport_present(struct radeon_device *rdev) +{ + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); + union igp_info *igp_info; + u8 frev, crev; + u16 data_offset; + + atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, + &crev, &data_offset); + + igp_info = (union igp_info *)(mode_info->atom_context->bios + + data_offset); + + if (igp_info) { + switch (crev) { + case 1: + if (igp_info->info.ucMemoryType & 0xf0) + return true; + break; + case 2: + if (igp_info->info_2.ucMemoryType & 0x0f) + return true; + break; + default: + DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); + break; + } + } + return false; +} + bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder, struct radeon_encoder_int_tmds *tmds) { @@ -1026,6 +1084,7 @@ static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct ss->delay = ss_info->asSS_Info[i].ucSS_Delay; ss->range = ss_info->asSS_Info[i].ucSS_Range; ss->refdiv = ss_info->asSS_Info[i].ucRecommendedRef_Div; + break; } } } diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c index 4ddfd4b..7932dc4 100644 --- a/drivers/gpu/drm/radeon/radeon_benchmark.c +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c @@ -65,31 +65,42 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize, if (r) { goto out_cleanup; } - start_jiffies = jiffies; - for (i = 0; i < n; i++) { - r = radeon_fence_create(rdev, &fence); - if (r) { - goto out_cleanup; + + /* r100 doesn't have dma engine so skip the test */ + if (rdev->asic->copy_dma) { + + start_jiffies = jiffies; + for (i = 0; i < n; i++) { + r = radeon_fence_create(rdev, &fence); + if (r) { + goto out_cleanup; + } + + r = radeon_copy_dma(rdev, saddr, daddr, + size / RADEON_GPU_PAGE_SIZE, fence); + + if (r) { + goto out_cleanup; + } + r = radeon_fence_wait(fence, false); + if (r) { + goto out_cleanup; + } + radeon_fence_unref(&fence); } - r = radeon_copy_dma(rdev, saddr, daddr, size / RADEON_GPU_PAGE_SIZE, fence); - if (r) { - goto out_cleanup; + end_jiffies = jiffies; + time = end_jiffies - start_jiffies; + time = jiffies_to_msecs(time); + if (time > 0) { + i = ((n * size) >> 10) / time; + printk(KERN_INFO "radeon: dma %u bo moves of %ukb from" + " %d to %d in %lums (%ukb/ms %ukb/s %uM/s)\n", + n, size >> 10, + sdomain, ddomain, time, + i, i * 1000, (i * 1000) / 1024); } - r = radeon_fence_wait(fence, false); - if (r) { - goto out_cleanup; - } - radeon_fence_unref(&fence); - } - end_jiffies = jiffies; - time = end_jiffies - start_jiffies; - time = jiffies_to_msecs(time); - if (time > 0) { - i = ((n * size) >> 10) / time; - printk(KERN_INFO "radeon: dma %u bo moves of %ukb from %d to %d" - " in %lums (%ukb/ms %ukb/s %uM/s)\n", n, size >> 10, - sdomain, ddomain, time, i, i * 1000, (i * 1000) / 1024); } + start_jiffies = jiffies; for (i = 0; i < n; i++) { r = radeon_fence_create(rdev, &fence); diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c index 812f24d..73c4405 100644 --- a/drivers/gpu/drm/radeon/radeon_clocks.c +++ b/drivers/gpu/drm/radeon/radeon_clocks.c @@ -56,7 +56,7 @@ uint32_t radeon_legacy_get_engine_clock(struct radeon_device *rdev) else if (post_div == 3) sclk >>= 2; else if (post_div == 4) - sclk >>= 4; + sclk >>= 3; return sclk; } @@ -86,7 +86,7 @@ uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev) else if (post_div == 3) mclk >>= 2; else if (post_div == 4) - mclk >>= 4; + mclk >>= 3; return mclk; } diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index fd94dbc..e7b1944 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -595,6 +595,48 @@ bool radeon_combios_get_clock_info(struct drm_device *dev) return false; } +bool radeon_combios_sideport_present(struct radeon_device *rdev) +{ + struct drm_device *dev = rdev->ddev; + u16 igp_info; + + igp_info = combios_get_table_offset(dev, COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE); + + if (igp_info) { + if (RBIOS16(igp_info + 0x4)) + return true; + } + return false; +} + +static const uint32_t default_primarydac_adj[CHIP_LAST] = { + 0x00000808, /* r100 */ + 0x00000808, /* rv100 */ + 0x00000808, /* rs100 */ + 0x00000808, /* rv200 */ + 0x00000808, /* rs200 */ + 0x00000808, /* r200 */ + 0x00000808, /* rv250 */ + 0x00000000, /* rs300 */ + 0x00000808, /* rv280 */ + 0x00000808, /* r300 */ + 0x00000808, /* r350 */ + 0x00000808, /* rv350 */ + 0x00000808, /* rv380 */ + 0x00000808, /* r420 */ + 0x00000808, /* r423 */ + 0x00000808, /* rv410 */ + 0x00000000, /* rs400 */ + 0x00000000, /* rs480 */ +}; + +static void radeon_legacy_get_primary_dac_info_from_table(struct radeon_device *rdev, + struct radeon_encoder_primary_dac *p_dac) +{ + p_dac->ps2_pdac_adj = default_primarydac_adj[rdev->family]; + return; +} + struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct radeon_encoder *encoder) @@ -604,20 +646,20 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct uint16_t dac_info; uint8_t rev, bg, dac; struct radeon_encoder_primary_dac *p_dac = NULL; + int found = 0; - if (rdev->bios == NULL) + p_dac = kzalloc(sizeof(struct radeon_encoder_primary_dac), + GFP_KERNEL); + + if (!p_dac) return NULL; + if (rdev->bios == NULL) + goto out; + /* 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 = RBIOS8(dac_info) & 0x3; if (rev < 2) { bg = RBIOS8(dac_info + 0x2) & 0xf; @@ -628,9 +670,13 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct dac = RBIOS8(dac_info + 0x3) & 0xf; p_dac->ps2_pdac_adj = (bg << 8) | (dac); } - + found = 1; } +out: + if (!found) /* fallback to defaults */ + radeon_legacy_get_primary_dac_info_from_table(rdev, p_dac); + return p_dac; } @@ -641,6 +687,9 @@ radeon_combios_get_tv_info(struct radeon_device *rdev) uint16_t tv_info; enum radeon_tv_std tv_std = TV_STD_NTSC; + if (rdev->bios == NULL) + return tv_std; + tv_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); if (tv_info) { if (RBIOS8(tv_info + 6) == 'T') { @@ -922,8 +971,7 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder lvds->native_mode.vdisplay); lvds->panel_vcc_delay = RBIOS16(lcd_info + 0x2c); - if (lvds->panel_vcc_delay > 2000 || lvds->panel_vcc_delay < 0) - lvds->panel_vcc_delay = 2000; + lvds->panel_vcc_delay = min_t(u16, lvds->panel_vcc_delay, 2000); lvds->panel_pwr_delay = RBIOS8(lcd_info + 0x24); lvds->panel_digon_delay = RBIOS16(lcd_info + 0x38) & 0xf; diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 2016156..65f8194 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -49,8 +49,10 @@ void radeon_connector_hotplug(struct drm_connector *connector) if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); - if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { - if (radeon_dp_getsinktype(radeon_connector) == CONNECTOR_OBJECT_ID_DISPLAYPORT) { + if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) || + (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { + if ((radeon_dp_getsinktype(radeon_connector) == CONNECTOR_OBJECT_ID_DISPLAYPORT) || + (radeon_dp_getsinktype(radeon_connector) == CONNECTOR_OBJECT_ID_eDP)) { if (radeon_dp_needs_link_train(radeon_connector)) { if (connector->encoder) dp_link_train(connector->encoder, connector); @@ -578,16 +580,18 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder; struct drm_encoder_helper_funcs *encoder_funcs; - bool dret; + bool dret = false; enum drm_connector_status ret = connector_status_disconnected; encoder = radeon_best_single_encoder(connector); if (!encoder) ret = connector_status_disconnected; - radeon_i2c_do_lock(radeon_connector->ddc_bus, 1); - dret = radeon_ddc_probe(radeon_connector); - radeon_i2c_do_lock(radeon_connector->ddc_bus, 0); + if (radeon_connector->ddc_bus) { + radeon_i2c_do_lock(radeon_connector->ddc_bus, 1); + dret = radeon_ddc_probe(radeon_connector); + radeon_i2c_do_lock(radeon_connector->ddc_bus, 0); + } if (dret) { if (radeon_connector->edid) { kfree(radeon_connector->edid); @@ -615,7 +619,7 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect ret = connector_status_connected; } } else { - if (radeon_connector->dac_load_detect) { + if (radeon_connector->dac_load_detect && encoder) { encoder_funcs = encoder->helper_private; ret = encoder_funcs->detect(encoder, connector); } @@ -738,11 +742,13 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect struct drm_mode_object *obj; int i; enum drm_connector_status ret = connector_status_disconnected; - bool dret; + bool dret = false; - radeon_i2c_do_lock(radeon_connector->ddc_bus, 1); - dret = radeon_ddc_probe(radeon_connector); - radeon_i2c_do_lock(radeon_connector->ddc_bus, 0); + if (radeon_connector->ddc_bus) { + radeon_i2c_do_lock(radeon_connector->ddc_bus, 1); + dret = radeon_ddc_probe(radeon_connector); + radeon_i2c_do_lock(radeon_connector->ddc_bus, 0); + } if (dret) { if (radeon_connector->edid) { kfree(radeon_connector->edid); @@ -774,7 +780,7 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect * connected and the DVI port disconnected. If the edid doesn't * say HDMI, vice versa. */ - if (radeon_connector->shared_ddc && connector_status_connected) { + if (radeon_connector->shared_ddc && (ret == connector_status_connected)) { struct drm_device *dev = connector->dev; struct drm_connector *list_connector; struct radeon_connector *list_radeon_connector; @@ -898,10 +904,18 @@ static void radeon_dvi_force(struct drm_connector *connector) static int radeon_dvi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; struct radeon_connector *radeon_connector = to_radeon_connector(connector); /* XXX check mode bandwidth */ + /* clocks over 135 MHz have heat issues with DVI on RV100 */ + if (radeon_connector->use_digital && + (rdev->family == CHIP_RV100) && + (mode->clock > 135000)) + return MODE_CLOCK_HIGH; + if (radeon_connector->use_digital && (mode->clock > 165000)) { if ((radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I) || (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) || @@ -967,7 +981,8 @@ static enum drm_connector_status radeon_dp_detect(struct drm_connector *connecto } sink_type = radeon_dp_getsinktype(radeon_connector); - if (sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { + if ((sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || + (sink_type == CONNECTOR_OBJECT_ID_eDP)) { if (radeon_dp_getdpcd(radeon_connector)) { radeon_dig_connector->dp_sink_type = sink_type; ret = connector_status_connected; @@ -992,7 +1007,8 @@ static int radeon_dp_mode_valid(struct drm_connector *connector, /* XXX check mode bandwidth */ - if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) + if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || + (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) return radeon_dp_mode_valid_helper(radeon_connector, mode); else return MODE_OK; @@ -1044,8 +1060,7 @@ radeon_add_atom_connector(struct drm_device *dev, return; } if (radeon_connector->ddc_bus && i2c_bus->valid) { - if (memcmp(&radeon_connector->ddc_bus->rec, i2c_bus, - sizeof(struct radeon_i2c_bus_rec)) == 0) { + if (radeon_connector->ddc_bus->rec.i2c_id == i2c_bus->i2c_id) { radeon_connector->shared_ddc = true; shared_ddc = true; } @@ -1145,6 +1160,7 @@ radeon_add_atom_connector(struct drm_device *dev, subpixel_order = SubPixelHorizontalRGB; break; case DRM_MODE_CONNECTOR_DisplayPort: + case DRM_MODE_CONNECTOR_eDP: radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); if (!radeon_dig_connector) goto failed; @@ -1157,10 +1173,16 @@ radeon_add_atom_connector(struct drm_device *dev, goto failed; if (i2c_bus->valid) { /* add DP i2c bus */ - radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); + if (connector_type == DRM_MODE_CONNECTOR_eDP) + radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); + else + radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); if (!radeon_dig_connector->dp_i2c_bus) goto failed; - radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DP"); + if (connector_type == DRM_MODE_CONNECTOR_eDP) + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "eDP"); + else + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DP"); if (!radeon_connector->ddc_bus) goto failed; } @@ -1324,7 +1346,7 @@ radeon_add_legacy_connector(struct drm_device *dev, radeon_connector->dac_load_detect = false; drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.load_detect_property, - 1); + radeon_connector->dac_load_detect); drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.tv_std_property, radeon_combios_get_tv_info(rdev)); diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index 0b2f9c2..06123ba 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -2145,6 +2145,7 @@ int radeon_master_create(struct drm_device *dev, struct drm_master *master) &master_priv->sarea); if (ret) { DRM_ERROR("SAREA setup failed\n"); + kfree(master_priv); return ret; } master_priv->sarea_priv = master_priv->sarea->handle + sizeof(struct drm_sarea); diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 65590a0..e9d0850 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -86,7 +86,7 @@ int radeon_cs_parser_relocs(struct radeon_cs_parser *p) &p->validated); } } - return radeon_bo_list_validate(&p->validated, p->ib->fence); + return radeon_bo_list_validate(&p->validated); } int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) @@ -189,12 +189,10 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error) { unsigned i; - if (error) { - radeon_bo_list_unvalidate(&parser->validated, - parser->ib->fence); - } else { - radeon_bo_list_unreserve(&parser->validated); + if (!error && parser->ib) { + radeon_bo_list_fence(&parser->validated, parser->ib->fence); } + radeon_bo_list_unreserve(&parser->validated); for (i = 0; i < parser->nrelocs; i++) { if (parser->relocs[i].gobj) { mutex_lock(&parser->rdev->ddev->struct_mutex); @@ -231,6 +229,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) memset(&parser, 0, sizeof(struct radeon_cs_parser)); parser.filp = filp; parser.rdev = rdev; + parser.dev = rdev->dev; r = radeon_cs_parser_init(&parser, data); if (r) { DRM_ERROR("Failed to initialize parser !\n"); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 7c68480..768b150 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -544,6 +544,7 @@ void radeon_agp_disable(struct radeon_device *rdev) rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush; rdev->asic->gart_set_page = &r100_pci_gart_set_page; } + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; } void radeon_check_arguments(struct radeon_device *rdev) @@ -733,16 +734,18 @@ void radeon_device_fini(struct radeon_device *rdev) */ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) { - struct radeon_device *rdev = dev->dev_private; + struct radeon_device *rdev; struct drm_crtc *crtc; int r; - if (dev == NULL || rdev == NULL) { + if (dev == NULL || dev->dev_private == NULL) { return -ENODEV; } if (state.event == PM_EVENT_PRETHAW) { return 0; } + rdev = dev->dev_private; + /* unpin the front buffers */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 91d72b7..7e17a36 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -234,7 +234,7 @@ static const char *encoder_names[34] = { "INTERNAL_UNIPHY2", }; -static const char *connector_names[13] = { +static const char *connector_names[15] = { "Unknown", "VGA", "DVI-I", @@ -248,6 +248,8 @@ static const char *connector_names[13] = { "DisplayPort", "HDMI-A", "HDMI-B", + "TV", + "eDP", }; static const char *hpd_names[7] = { @@ -276,7 +278,7 @@ static void radeon_print_display_setup(struct drm_device *dev) DRM_INFO(" %s\n", connector_names[connector->connector_type]); if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) DRM_INFO(" %s\n", hpd_names[radeon_connector->hpd.hpd]); - if (radeon_connector->ddc_bus) + if (radeon_connector->ddc_bus) { DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", radeon_connector->ddc_bus->rec.mask_clk_reg, radeon_connector->ddc_bus->rec.mask_data_reg, @@ -286,6 +288,15 @@ static void radeon_print_display_setup(struct drm_device *dev) radeon_connector->ddc_bus->rec.en_data_reg, radeon_connector->ddc_bus->rec.y_clk_reg, radeon_connector->ddc_bus->rec.y_data_reg); + } else { + if (connector->connector_type == DRM_MODE_CONNECTOR_VGA || + connector->connector_type == DRM_MODE_CONNECTOR_DVII || + connector->connector_type == DRM_MODE_CONNECTOR_DVID || + connector->connector_type == DRM_MODE_CONNECTOR_DVIA || + connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) + DRM_INFO(" DDC: no ddc bus - possible BIOS bug - please report to xorg-driver-ati@lists.x.org\n"); + } DRM_INFO(" Encoders:\n"); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { radeon_encoder = to_radeon_encoder(encoder); @@ -329,8 +340,11 @@ static bool radeon_setup_enc_conn(struct drm_device *dev) ret = radeon_get_atom_connector_info_from_object_table(dev); else ret = radeon_get_atom_connector_info_from_supported_devices_table(dev); - } else + } else { ret = radeon_get_legacy_connector_info_from_bios(dev); + if (ret == false) + ret = radeon_get_legacy_connector_info_from_table(dev); + } } else { if (!ASIC_IS_AVIVO(rdev)) ret = radeon_get_legacy_connector_info_from_table(dev); @@ -349,9 +363,11 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) { int ret = 0; - if (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) { + if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || + (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; - if (dig->dp_i2c_bus) + if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || + dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus) radeon_connector->edid = drm_get_edid(&radeon_connector->base, &dig->dp_i2c_bus->adapter); } if (!radeon_connector->ddc_bus) @@ -404,11 +420,12 @@ void radeon_compute_pll(struct radeon_pll *pll, uint32_t *fb_div_p, uint32_t *frac_fb_div_p, uint32_t *ref_div_p, - uint32_t *post_div_p, - int flags) + uint32_t *post_div_p) { uint32_t min_ref_div = pll->min_ref_div; uint32_t max_ref_div = pll->max_ref_div; + uint32_t min_post_div = pll->min_post_div; + uint32_t max_post_div = pll->max_post_div; uint32_t min_fractional_feed_div = 0; uint32_t max_fractional_feed_div = 0; uint32_t best_vco = pll->best_vco; @@ -424,7 +441,7 @@ void radeon_compute_pll(struct radeon_pll *pll, DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div); freq = freq * 1000; - if (flags & RADEON_PLL_USE_REF_DIV) + if (pll->flags & RADEON_PLL_USE_REF_DIV) min_ref_div = max_ref_div = pll->reference_div; else { while (min_ref_div < max_ref_div-1) { @@ -439,19 +456,22 @@ void radeon_compute_pll(struct radeon_pll *pll, } } - if (flags & RADEON_PLL_USE_FRAC_FB_DIV) { + if (pll->flags & RADEON_PLL_USE_POST_DIV) + min_post_div = max_post_div = pll->post_div; + + if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { min_fractional_feed_div = pll->min_frac_feedback_div; max_fractional_feed_div = pll->max_frac_feedback_div; } - for (post_div = pll->min_post_div; post_div <= pll->max_post_div; ++post_div) { + for (post_div = min_post_div; post_div <= max_post_div; ++post_div) { uint32_t ref_div; - if ((flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1)) + if ((pll->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 (pll->flags & RADEON_PLL_LEGACY) { if ((post_div == 5) || (post_div == 7) || (post_div == 9) || @@ -498,7 +518,7 @@ void radeon_compute_pll(struct radeon_pll *pll, tmp += (uint64_t)pll->reference_freq * 1000 * frac_feedback_div; current_freq = radeon_div(tmp, ref_div * post_div); - if (flags & RADEON_PLL_PREFER_CLOSEST_LOWER) { + if (pll->flags & RADEON_PLL_PREFER_CLOSEST_LOWER) { error = freq - current_freq; error = error < 0 ? 0xffffffff : error; } else @@ -525,12 +545,12 @@ void radeon_compute_pll(struct radeon_pll *pll, best_freq = current_freq; best_error = error; best_vco_diff = vco_diff; - } else if (((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) || - ((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))) { + } else if (((pll->flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) || + ((pll->flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) || + ((pll->flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) || + ((pll->flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) || + ((pll->flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) || + ((pll->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; @@ -566,8 +586,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, uint32_t *fb_div_p, uint32_t *frac_fb_div_p, uint32_t *ref_div_p, - uint32_t *post_div_p, - int flags) + uint32_t *post_div_p) { fixed20_12 m, n, frac_n, p, f_vco, f_pclk, best_freq; fixed20_12 pll_out_max, pll_out_min; @@ -661,7 +680,6 @@ static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) radeonfb_remove(dev, fb); if (radeon_fb->obj) { - radeon_gem_object_unpin(radeon_fb->obj); mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(radeon_fb->obj); mutex_unlock(&dev->struct_mutex); @@ -709,7 +727,11 @@ radeon_user_framebuffer_create(struct drm_device *dev, struct drm_gem_object *obj; obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); - + if (obj == NULL) { + dev_err(&dev->pdev->dev, "No GEM object associated to handle 0x%08X, " + "can't create framebuffer\n", mode_cmd->handle); + return NULL; + } return radeon_framebuffer_create(dev, mode_cmd, obj); } diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index e137852..c57ad60 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -106,9 +106,10 @@ * 1.29- R500 3D cmd buffer support * 1.30- Add support for occlusion queries * 1.31- Add support for num Z pipes from GET_PARAM + * 1.32- fixes for rv740 setup */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 31 +#define DRIVER_MINOR 32 #define DRIVER_PATCHLEVEL 0 enum radeon_cp_microcode_version { diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index ccba95f..3c91724 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -156,6 +156,26 @@ radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t return ret; } +static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + 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: + 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: + return true; + default: + return false; + } +} void radeon_link_encoder_connector(struct drm_device *dev) { @@ -202,7 +222,7 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { radeon_connector = to_radeon_connector(connector); - if (radeon_encoder->devices & radeon_connector->devices) + if (radeon_encoder->active_device & radeon_connector->devices) return connector; } return NULL; @@ -596,21 +616,23 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) return ATOM_ENCODER_MODE_LVDS; break; case DRM_MODE_CONNECTOR_DisplayPort: + case DRM_MODE_CONNECTOR_eDP: radeon_dig_connector = radeon_connector->con_priv; - if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) + if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || + (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) return ATOM_ENCODER_MODE_DP; else if (drm_detect_hdmi_monitor(radeon_connector->edid)) return ATOM_ENCODER_MODE_HDMI; else return ATOM_ENCODER_MODE_DVI; break; - case CONNECTOR_DVI_A: - case CONNECTOR_VGA: + case DRM_MODE_CONNECTOR_DVIA: + case DRM_MODE_CONNECTOR_VGA: return ATOM_ENCODER_MODE_CRT; break; - case CONNECTOR_STV: - case CONNECTOR_CTV: - case CONNECTOR_DIN: + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_9PinDIN: /* fix me */ return ATOM_ENCODER_MODE_TV; /*return ATOM_ENCODER_MODE_CV;*/ @@ -674,31 +696,11 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) memset(&args, 0, sizeof(args)); - if (ASIC_IS_DCE32(rdev)) { - 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: - /* XXX doesn't really matter which dig encoder we pick as long as it's - * not already in use - */ - if (dig_connector->linkb) - index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); - else - index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); - num = 1; - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - /* Only dig2 encoder can drive LVTMA */ - index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); - num = 2; - break; - } - } + if (dig->dig_encoder) + index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); + else + index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); + num = dig->dig_encoder + 1; atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); @@ -820,7 +822,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); } if (ASIC_IS_DCE32(rdev)) { - if (dig->dig_block) + if (dig->dig_encoder == 1) args.v2.acConfig.ucEncoderSel = 1; if (dig_connector->linkb) args.v2.acConfig.ucLinkSel = 1; @@ -847,17 +849,16 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v2.acConfig.fCoherentMode = 1; } } else { + args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; + if (dig->dig_encoder) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; + else + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; + switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - /* XXX doesn't really matter which dig encoder we pick as long as it's - * not already in use - */ - if (dig_connector->linkb) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; - else - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; if (rdev->flags & RADEON_IS_IGP) { if (radeon_encoder->pixel_clock > 165000) { if (dig_connector->igp_lane_info & 0x3) @@ -876,10 +877,6 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t } } break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - /* Only dig2 encoder can drive LVTMA */ - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; - break; } if (radeon_encoder->pixel_clock > 165000) @@ -1044,6 +1041,7 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) union crtc_sourc_param args; int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); uint8_t frev, crev; + struct radeon_encoder_atom_dig *dig; memset(&args, 0, sizeof(args)); @@ -1107,40 +1105,16 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - if (ASIC_IS_DCE32(rdev)) { - if (radeon_crtc->crtc_id) - args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; - else - args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; - } else { - 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; - - /* XXX doesn't really matter which dig encoder we pick as long as it's - * not already in use - */ - if (dig_connector->linkb) - args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; - else - args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; - } + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + dig = radeon_encoder->enc_priv; + if (dig->dig_encoder) + args.v2.ucEncoderID = ASIC_INT_DIG2_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: - /* Only dig2 encoder can drive LVTMA */ - args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; - break; case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; @@ -1200,6 +1174,47 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder, } } +static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *test_encoder; + struct radeon_encoder_atom_dig *dig; + uint32_t dig_enc_in_use = 0; + /* on DCE32 and encoder can driver any block so just crtc id */ + if (ASIC_IS_DCE32(rdev)) { + return radeon_crtc->crtc_id; + } + + /* on DCE3 - LVTMA can only be driven by DIGB */ + list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { + struct radeon_encoder *radeon_test_encoder; + + if (encoder == test_encoder) + continue; + + if (!radeon_encoder_is_digital(test_encoder)) + continue; + + radeon_test_encoder = to_radeon_encoder(test_encoder); + dig = radeon_test_encoder->enc_priv; + + if (dig->dig_encoder >= 0) + dig_enc_in_use |= (1 << dig->dig_encoder); + } + + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) { + if (dig_enc_in_use & 0x2) + DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n"); + return 1; + } + if (!(dig_enc_in_use & 1)) + return 0; + return 1; +} + static void radeon_atom_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, @@ -1212,12 +1227,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, if (radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) { - if (radeon_encoder->enc_priv) { - struct radeon_encoder_atom_dig *dig; - - dig = radeon_encoder->enc_priv; - dig->dig_block = radeon_crtc->crtc_id; - } + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + if (dig) + dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder); } radeon_encoder->pixel_clock = adjusted_mode->clock; @@ -1377,7 +1389,13 @@ static void radeon_atom_encoder_commit(struct drm_encoder *encoder) static void radeon_atom_encoder_disable(struct drm_encoder *encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig; radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + + if (radeon_encoder_is_digital(encoder)) { + dig = radeon_encoder->enc_priv; + dig->dig_encoder = -1; + } radeon_encoder->active_device = 0; } @@ -1434,6 +1452,7 @@ radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) /* coherent mode by default */ dig->coherent_mode = true; + dig->dig_encoder = -1; return dig; } diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 3ba213d..d71e346 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -248,7 +248,7 @@ int radeonfb_create(struct drm_device *dev, if (ret) goto out_unref; - memset_io(fbptr, 0xff, aligned_size); + memset_io(fbptr, 0x0, aligned_size); strcpy(info->fix.id, "radeondrmfb"); diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 4cdd8b4..8495d4e 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -140,16 +140,15 @@ int radeon_fence_create(struct radeon_device *rdev, struct radeon_fence **fence) bool radeon_fence_signaled(struct radeon_fence *fence) { - struct radeon_device *rdev = fence->rdev; unsigned long irq_flags; bool signaled = false; - if (rdev->gpu_lockup) { + if (!fence) return true; - } - if (fence == NULL) { + + if (fence->rdev->gpu_lockup) return true; - } + write_lock_irqsave(&fence->rdev->fence_drv.lock, irq_flags); signaled = fence->signaled; /* if we are shuting down report all fence as signaled */ diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 60df2d7..db8e9a3 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -131,7 +131,6 @@ int radeon_gem_set_domain(struct drm_gem_object *gobj, printk(KERN_ERR "Failed to wait for object !\n"); return r; } - radeon_hdp_flush(robj->rdev); } return 0; } @@ -309,10 +308,12 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data, } robj = gobj->driver_private; r = radeon_bo_wait(robj, NULL, false); + /* callback hw specific functions if any */ + if (robj->rdev->asic->ioctl_wait_idle) + robj->rdev->asic->ioctl_wait_idle(robj->rdev, robj); mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(gobj); mutex_unlock(&dev->struct_mutex); - radeon_hdp_flush(robj->rdev); return r; } diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c index b79ecc4..2f349a3 100644 --- a/drivers/gpu/drm/radeon/radeon_irq.c +++ b/drivers/gpu/drm/radeon/radeon_irq.c @@ -289,16 +289,16 @@ int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_pr drm_radeon_irq_emit_t *emit = data; int result; - if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) - return -EINVAL; - - LOCK_TEST_WITH_RETURN(dev, file_priv); - if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) + return -EINVAL; + + LOCK_TEST_WITH_RETURN(dev, file_priv); + result = radeon_emit_irq(dev); if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 9223296..3cfd60f 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -97,6 +97,7 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) rdev->irq.sw_int = false; for (i = 0; i < 2; i++) { rdev->irq.crtc_vblank_int[i] = false; + rdev->irq.hpd[i] = false; } radeon_irq_set(rdev); } @@ -128,17 +129,22 @@ int radeon_irq_kms_init(struct radeon_device *rdev) DRM_INFO("radeon: using MSI.\n"); } } - drm_irq_install(rdev->ddev); rdev->irq.installed = true; + r = drm_irq_install(rdev->ddev); + if (r) { + rdev->irq.installed = false; + return r; + } DRM_INFO("radeon: irq initialized.\n"); return 0; } void radeon_irq_kms_fini(struct radeon_device *rdev) { + drm_vblank_cleanup(rdev->ddev); if (rdev->irq.installed) { - rdev->irq.installed = false; drm_irq_uninstall(rdev->ddev); + rdev->irq.installed = false; if (rdev->msi_enabled) pci_disable_msi(rdev->pdev); } diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index cc27485..b6d8081 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -339,69 +339,6 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) } } -/* properly set crtc bpp when using atombios */ -void radeon_legacy_atom_set_surface(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct radeon_device *rdev = 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 8: - format = 2; - break; - 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; - - WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); - - switch (radeon_crtc->crtc_id) { - case 0: - disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); - disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; - WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); - - crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL) & 0xfffff0ff; - crtc_gen_cntl |= (format << 8); - crtc_gen_cntl |= RADEON_CRTC_EXT_DISP_EN; - WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); - break; - case 1: - disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); - disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; - WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); - - crtc_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL) & 0xfffff0ff; - crtc_gen_cntl |= (format << 8); - WREG32(RADEON_CRTC2_GEN_CNTL, crtc_gen_cntl); - WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); - WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); - break; - } -} - int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { @@ -755,7 +692,6 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) uint32_t post_divider = 0; uint32_t freq = 0; uint8_t pll_gain; - int pll_flags = RADEON_PLL_LEGACY; bool use_bios_divs = false; /* PLL registers */ uint32_t pll_ref_div = 0; @@ -789,10 +725,12 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) else pll = &rdev->clock.p1pll; + pll->flags = RADEON_PLL_LEGACY; + if (mode->clock > 200000) /* range limits??? */ - pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else - pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { @@ -804,7 +742,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) } if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) - pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; + pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) { if (!rdev->is_atom_bios) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -819,7 +757,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) } } } - pll_flags |= RADEON_PLL_USE_REF_DIV; + pll->flags |= RADEON_PLL_USE_REF_DIV; } } } @@ -829,8 +767,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) if (!use_bios_divs) { radeon_compute_pll(pll, mode->clock, &freq, &feedback_div, &frac_fb_div, - &reference_div, &post_divider, - pll_flags); + &reference_div, &post_divider); for (post_div = &post_divs[0]; post_div->divider; ++post_div) { if (post_div->divider == post_divider) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 981508f..38e45e2 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -46,6 +46,7 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man; int panel_pwr_delay = 2000; + bool is_mac = false; DRM_DEBUG("\n"); if (radeon_encoder->enc_priv) { @@ -58,6 +59,15 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) } } + /* macs (and possibly some x86 oem systems?) wire up LVDS strangely + * Taken from radeonfb. + */ + if ((rdev->mode_info.connector_table == CT_IBOOK) || + (rdev->mode_info.connector_table == CT_POWERBOOK_EXTERNAL) || + (rdev->mode_info.connector_table == CT_POWERBOOK_INTERNAL) || + (rdev->mode_info.connector_table == CT_POWERBOOK_VGA)) + is_mac = true; + switch (mode) { case DRM_MODE_DPMS_ON: disp_pwr_man = RREG32(RADEON_DISP_PWR_MAN); @@ -74,6 +84,8 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON); + if (is_mac) + lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN; lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS); udelay(panel_pwr_delay * 1000); WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); @@ -85,7 +97,14 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); lvds_gen_cntl = RREG32(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); + if (is_mac) { + lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_EN; + WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_EN); + } else { + WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); + } udelay(panel_pwr_delay * 1000); WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); diff --git a/drivers/gpu/drm/radeon/radeon_legacy_tv.c b/drivers/gpu/drm/radeon/radeon_legacy_tv.c index 3a12bb0..417684d 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_tv.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_tv.c @@ -77,7 +77,7 @@ struct radeon_tv_mode_constants { unsigned pix_to_tv; }; -static const uint16_t hor_timing_NTSC[] = { +static const uint16_t hor_timing_NTSC[MAX_H_CODE_TIMING_LEN] = { 0x0007, 0x003f, 0x0263, @@ -98,7 +98,7 @@ static const uint16_t hor_timing_NTSC[] = { 0 }; -static const uint16_t vert_timing_NTSC[] = { +static const uint16_t vert_timing_NTSC[MAX_V_CODE_TIMING_LEN] = { 0x2001, 0x200d, 0x1006, @@ -115,7 +115,7 @@ static const uint16_t vert_timing_NTSC[] = { 0 }; -static const uint16_t hor_timing_PAL[] = { +static const uint16_t hor_timing_PAL[MAX_H_CODE_TIMING_LEN] = { 0x0007, 0x0058, 0x027c, @@ -136,7 +136,7 @@ static const uint16_t hor_timing_PAL[] = { 0 }; -static const uint16_t vert_timing_PAL[] = { +static const uint16_t vert_timing_PAL[MAX_V_CODE_TIMING_LEN] = { 0x2001, 0x200c, 0x1005, @@ -623,9 +623,9 @@ void radeon_legacy_tv_mode_set(struct drm_encoder *encoder, } flicker_removal = (tmp + 500) / 1000; - if (flicker_removal < 3) - flicker_removal = 3; - for (i = 0; i < 6; ++i) { + if (flicker_removal < 2) + flicker_removal = 2; + for (i = 0; i < ARRAY_SIZE(SLOPE_limit); ++i) { if (flicker_removal == SLOPE_limit[i]) break; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 402369d..e81b2ae 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -46,32 +46,6 @@ struct radeon_device; #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_dvi_type { - DVI_AUTO, - DVI_DIGITAL, - DVI_ANALOG -}; - enum radeon_rmx_type { RMX_OFF, RMX_FULL, @@ -151,16 +125,24 @@ struct radeon_tmds_pll { #define RADEON_PLL_PREFER_HIGH_POST_DIV (1 << 9) #define RADEON_PLL_USE_FRAC_FB_DIV (1 << 10) #define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11) +#define RADEON_PLL_USE_POST_DIV (1 << 12) struct radeon_pll { - uint16_t reference_freq; - uint16_t reference_div; + /* reference frequency */ + uint32_t reference_freq; + + /* fixed dividers */ + uint32_t reference_div; + uint32_t post_div; + + /* pll in/out limits */ 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 best_vco; + /* divider limits */ uint32_t min_ref_div; uint32_t max_ref_div; uint32_t min_post_div; @@ -169,7 +151,12 @@ struct radeon_pll { uint32_t max_feedback_div; uint32_t min_frac_feedback_div; uint32_t max_frac_feedback_div; - uint32_t best_vco; + + /* flags for the current clock */ + uint32_t flags; + + /* pll id */ + uint32_t id; }; struct radeon_i2c_chan { @@ -312,7 +299,7 @@ struct radeon_atom_ss { struct radeon_encoder_atom_dig { /* atom dig */ bool coherent_mode; - int dig_block; + int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB */ /* atom lvds */ uint32_t lvds_misc; uint16_t panel_pwr_delay; @@ -443,8 +430,7 @@ extern void radeon_compute_pll(struct radeon_pll *pll, uint32_t *fb_div_p, uint32_t *frac_fb_div_p, uint32_t *ref_div_p, - uint32_t *post_div_p, - int flags); + uint32_t *post_div_p); extern void radeon_compute_pll_avivo(struct radeon_pll *pll, uint64_t freq, @@ -452,8 +438,7 @@ extern void radeon_compute_pll_avivo(struct radeon_pll *pll, uint32_t *fb_div_p, uint32_t *frac_fb_div_p, uint32_t *ref_div_p, - uint32_t *post_div_p, - int flags); + uint32_t *post_div_p); extern void radeon_setup_encoder_clones(struct drm_device *dev); @@ -479,7 +464,6 @@ 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, diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index d9ffe1f..f1da370 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -220,9 +220,11 @@ int radeon_bo_unpin(struct radeon_bo *bo) int radeon_bo_evict_vram(struct radeon_device *rdev) { - if (rdev->flags & RADEON_IS_IGP) { - /* Useless to evict on IGP chips */ - return 0; + /* late 2.6.33 fix IGP hibernate - we need pm ops to do this correct */ + if (0 && (rdev->flags & RADEON_IS_IGP)) { + if (rdev->mc.igp_sideport_enabled == false) + /* Useless to evict on IGP chips */ + return 0; } return ttm_bo_evict_mm(&rdev->mman.bdev, TTM_PL_VRAM); } @@ -304,11 +306,10 @@ void radeon_bo_list_unreserve(struct list_head *head) } } -int radeon_bo_list_validate(struct list_head *head, void *fence) +int radeon_bo_list_validate(struct list_head *head) { struct radeon_bo_list *lobj; struct radeon_bo *bo; - struct radeon_fence *old_fence = NULL; int r; r = radeon_bo_list_reserve(head); @@ -332,32 +333,27 @@ int radeon_bo_list_validate(struct list_head *head, void *fence) } lobj->gpu_offset = radeon_bo_gpu_offset(bo); lobj->tiling_flags = bo->tiling_flags; - if (fence) { - old_fence = (struct radeon_fence *)bo->tbo.sync_obj; - bo->tbo.sync_obj = radeon_fence_ref(fence); - bo->tbo.sync_obj_arg = NULL; - } - if (old_fence) { - radeon_fence_unref(&old_fence); - } } return 0; } -void radeon_bo_list_unvalidate(struct list_head *head, void *fence) +void radeon_bo_list_fence(struct list_head *head, void *fence) { struct radeon_bo_list *lobj; - struct radeon_fence *old_fence; - - if (fence) - list_for_each_entry(lobj, head, list) { - old_fence = to_radeon_fence(lobj->bo->tbo.sync_obj); - if (old_fence == fence) { - lobj->bo->tbo.sync_obj = NULL; - radeon_fence_unref(&old_fence); - } + struct radeon_bo *bo; + struct radeon_fence *old_fence = NULL; + + list_for_each_entry(lobj, head, list) { + bo = lobj->bo; + spin_lock(&bo->tbo.lock); + old_fence = (struct radeon_fence *)bo->tbo.sync_obj; + bo->tbo.sync_obj = radeon_fence_ref(fence); + bo->tbo.sync_obj_arg = NULL; + spin_unlock(&bo->tbo.lock); + if (old_fence) { + radeon_fence_unref(&old_fence); } - radeon_bo_list_unreserve(head); + } } int radeon_bo_fbdev_mmap(struct radeon_bo *bo, diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index a02f180..7ab43de 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -156,8 +156,8 @@ extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj, struct list_head *head); extern int radeon_bo_list_reserve(struct list_head *head); extern void radeon_bo_list_unreserve(struct list_head *head); -extern int radeon_bo_list_validate(struct list_head *head, void *fence); -extern void radeon_bo_list_unvalidate(struct list_head *head, void *fence); +extern int radeon_bo_list_validate(struct list_head *head); +extern void radeon_bo_list_fence(struct list_head *head, void *fence); extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo, struct vm_area_struct *vma); extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo, diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 4d12b2d..6579eb4 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -41,68 +41,55 @@ int radeon_ib_get(struct radeon_device *rdev, struct radeon_ib **ib) { struct radeon_fence *fence; struct radeon_ib *nib; - unsigned long i; - int r = 0; + int r = 0, i, c; *ib = NULL; r = radeon_fence_create(rdev, &fence); if (r) { - DRM_ERROR("failed to create fence for new IB\n"); + dev_err(rdev->dev, "failed to create fence for new IB\n"); return r; } mutex_lock(&rdev->ib_pool.mutex); - i = find_first_zero_bit(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE); - if (i < RADEON_IB_POOL_SIZE) { - set_bit(i, rdev->ib_pool.alloc_bm); - rdev->ib_pool.ibs[i].length_dw = 0; - *ib = &rdev->ib_pool.ibs[i]; - mutex_unlock(&rdev->ib_pool.mutex); - goto out; + for (i = rdev->ib_pool.head_id, c = 0, nib = NULL; c < RADEON_IB_POOL_SIZE; c++, i++) { + i &= (RADEON_IB_POOL_SIZE - 1); + if (rdev->ib_pool.ibs[i].free) { + nib = &rdev->ib_pool.ibs[i]; + break; + } } - if (list_empty(&rdev->ib_pool.scheduled_ibs)) { - /* we go do nothings here */ + if (nib == NULL) { + /* This should never happen, it means we allocated all + * IB and haven't scheduled one yet, return EBUSY to + * userspace hoping that on ioctl recall we get better + * luck + */ + dev_err(rdev->dev, "no free indirect buffer !\n"); mutex_unlock(&rdev->ib_pool.mutex); - DRM_ERROR("all IB allocated none scheduled.\n"); - r = -EINVAL; - goto out; + radeon_fence_unref(&fence); + return -EBUSY; } - /* get the first ib on the scheduled list */ - nib = list_entry(rdev->ib_pool.scheduled_ibs.next, - struct radeon_ib, list); - if (nib->fence == NULL) { - /* we go do nothings here */ + rdev->ib_pool.head_id = (nib->idx + 1) & (RADEON_IB_POOL_SIZE - 1); + nib->free = false; + if (nib->fence) { mutex_unlock(&rdev->ib_pool.mutex); - DRM_ERROR("IB %lu scheduled without a fence.\n", nib->idx); - r = -EINVAL; - goto out; - } - mutex_unlock(&rdev->ib_pool.mutex); - - r = radeon_fence_wait(nib->fence, false); - if (r) { - DRM_ERROR("radeon: IB(%lu:0x%016lX:%u)\n", nib->idx, - (unsigned long)nib->gpu_addr, nib->length_dw); - DRM_ERROR("radeon: GPU lockup detected, fail to get a IB\n"); - goto out; + r = radeon_fence_wait(nib->fence, false); + if (r) { + dev_err(rdev->dev, "error waiting fence of IB(%u:0x%016lX:%u)\n", + nib->idx, (unsigned long)nib->gpu_addr, nib->length_dw); + mutex_lock(&rdev->ib_pool.mutex); + nib->free = true; + mutex_unlock(&rdev->ib_pool.mutex); + radeon_fence_unref(&fence); + return r; + } + mutex_lock(&rdev->ib_pool.mutex); } radeon_fence_unref(&nib->fence); - + nib->fence = fence; nib->length_dw = 0; - - /* scheduled list is accessed here */ - mutex_lock(&rdev->ib_pool.mutex); - list_del(&nib->list); - INIT_LIST_HEAD(&nib->list); mutex_unlock(&rdev->ib_pool.mutex); - *ib = nib; -out: - if (r) { - radeon_fence_unref(&fence); - } else { - (*ib)->fence = fence; - } - return r; + return 0; } void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib) @@ -113,19 +100,10 @@ void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib) if (tmp == NULL) { return; } - mutex_lock(&rdev->ib_pool.mutex); - if (!list_empty(&tmp->list) && !radeon_fence_signaled(tmp->fence)) { - /* IB is scheduled & not signaled don't do anythings */ - mutex_unlock(&rdev->ib_pool.mutex); - return; - } - list_del(&tmp->list); - INIT_LIST_HEAD(&tmp->list); - if (tmp->fence) + if (!tmp->fence->emited) radeon_fence_unref(&tmp->fence); - - tmp->length_dw = 0; - clear_bit(tmp->idx, rdev->ib_pool.alloc_bm); + mutex_lock(&rdev->ib_pool.mutex); + tmp->free = true; mutex_unlock(&rdev->ib_pool.mutex); } @@ -135,7 +113,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib) if (!ib->length_dw || !rdev->cp.ready) { /* TODO: Nothings in the ib we should report. */ - DRM_ERROR("radeon: couldn't schedule IB(%lu).\n", ib->idx); + DRM_ERROR("radeon: couldn't schedule IB(%u).\n", ib->idx); return -EINVAL; } @@ -148,7 +126,8 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib) radeon_ring_ib_execute(rdev, ib); radeon_fence_emit(rdev, ib->fence); mutex_lock(&rdev->ib_pool.mutex); - list_add_tail(&ib->list, &rdev->ib_pool.scheduled_ibs); + /* once scheduled IB is considered free and protected by the fence */ + ib->free = true; mutex_unlock(&rdev->ib_pool.mutex); radeon_ring_unlock_commit(rdev); return 0; @@ -164,7 +143,6 @@ int radeon_ib_pool_init(struct radeon_device *rdev) if (rdev->ib_pool.robj) return 0; /* Allocate 1M object buffer */ - INIT_LIST_HEAD(&rdev->ib_pool.scheduled_ibs); r = radeon_bo_create(rdev, NULL, RADEON_IB_POOL_SIZE*64*1024, true, RADEON_GEM_DOMAIN_GTT, &rdev->ib_pool.robj); @@ -195,9 +173,9 @@ int radeon_ib_pool_init(struct radeon_device *rdev) rdev->ib_pool.ibs[i].ptr = ptr + offset; rdev->ib_pool.ibs[i].idx = i; rdev->ib_pool.ibs[i].length_dw = 0; - INIT_LIST_HEAD(&rdev->ib_pool.ibs[i].list); + rdev->ib_pool.ibs[i].free = true; } - bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE); + rdev->ib_pool.head_id = 0; rdev->ib_pool.ready = true; DRM_INFO("radeon: ib pool ready.\n"); if (radeon_debugfs_ib_init(rdev)) { @@ -214,7 +192,6 @@ void radeon_ib_pool_fini(struct radeon_device *rdev) return; } mutex_lock(&rdev->ib_pool.mutex); - bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE); if (rdev->ib_pool.robj) { r = radeon_bo_reserve(rdev->ib_pool.robj, false); if (likely(r == 0)) { @@ -363,7 +340,7 @@ static int radeon_debugfs_ib_info(struct seq_file *m, void *data) if (ib == NULL) { return 0; } - seq_printf(m, "IB %04lu\n", ib->idx); + seq_printf(m, "IB %04u\n", ib->idx); seq_printf(m, "IB fence %p\n", ib->fence); seq_printf(m, "IB size %05u dwords\n", ib->length_dw); for (i = 0; i < ib->length_dw; i++) { diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 3b0c07b..58b5adf 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -215,7 +215,10 @@ static void radeon_evict_flags(struct ttm_buffer_object *bo, rbo = container_of(bo, struct radeon_bo, tbo); switch (bo->mem.mem_type) { case TTM_PL_VRAM: - radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT); + if (rbo->rdev->cp.ready == false) + radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_CPU); + else + radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT); break; case TTM_PL_TT: default: diff --git a/drivers/gpu/drm/radeon/reg_srcs/r200 b/drivers/gpu/drm/radeon/reg_srcs/r200 index 6021c88..c29ac43 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r200 +++ b/drivers/gpu/drm/radeon/reg_srcs/r200 @@ -91,6 +91,8 @@ r200 0x3294 0x22b8 SE_TCL_TEX_CYL_WRAP_CTL 0x22c0 SE_TCL_UCP_VERT_BLEND_CNTL 0x22c4 SE_TCL_POINT_SPRITE_CNTL +0x22d0 SE_PVS_CNTL +0x22d4 SE_PVS_CONST_CNTL 0x2648 RE_POINTSIZE 0x26c0 RE_TOP_LEFT 0x26c4 RE_MISC diff --git a/drivers/gpu/drm/radeon/reg_srcs/r420 b/drivers/gpu/drm/radeon/reg_srcs/r420 new file mode 100644 index 0000000..989f7a0 --- /dev/null +++ b/drivers/gpu/drm/radeon/reg_srcs/r420 @@ -0,0 +1,795 @@ +r420 0x4f60 +0x1434 SRC_Y_X +0x1438 DST_Y_X +0x143C DST_HEIGHT_WIDTH +0x146C DP_GUI_MASTER_CNTL +0x1474 BRUSH_Y_X +0x1478 DP_BRUSH_BKGD_CLR +0x147C DP_BRUSH_FRGD_CLR +0x1480 BRUSH_DATA0 +0x1484 BRUSH_DATA1 +0x1598 DST_WIDTH_HEIGHT +0x15C0 CLR_CMP_CNTL +0x15C4 CLR_CMP_CLR_SRC +0x15C8 CLR_CMP_CLR_DST +0x15CC CLR_CMP_MSK +0x15D8 DP_SRC_FRGD_CLR +0x15DC DP_SRC_BKGD_CLR +0x1600 DST_LINE_START +0x1604 DST_LINE_END +0x1608 DST_LINE_PATCOUNT +0x16C0 DP_CNTL +0x16CC DP_WRITE_MSK +0x16D0 DP_CNTL_XDIR_YDIR_YMAJOR +0x16E8 DEFAULT_SC_BOTTOM_RIGHT +0x16EC SC_TOP_LEFT +0x16F0 SC_BOTTOM_RIGHT +0x16F4 SRC_SC_BOTTOM_RIGHT +0x1714 DSTCACHE_CTLSTAT +0x1720 WAIT_UNTIL +0x172C RBBM_GUICNTL +0x1D98 VAP_VPORT_XSCALE +0x1D9C VAP_VPORT_XOFFSET +0x1DA0 VAP_VPORT_YSCALE +0x1DA4 VAP_VPORT_YOFFSET +0x1DA8 VAP_VPORT_ZSCALE +0x1DAC VAP_VPORT_ZOFFSET +0x2080 VAP_CNTL +0x2090 VAP_OUT_VTX_FMT_0 +0x2094 VAP_OUT_VTX_FMT_1 +0x20B0 VAP_VTE_CNTL +0x2138 VAP_VF_MIN_VTX_INDX +0x2140 VAP_CNTL_STATUS +0x2150 VAP_PROG_STREAM_CNTL_0 +0x2154 VAP_PROG_STREAM_CNTL_1 +0x2158 VAP_PROG_STREAM_CNTL_2 +0x215C VAP_PROG_STREAM_CNTL_3 +0x2160 VAP_PROG_STREAM_CNTL_4 +0x2164 VAP_PROG_STREAM_CNTL_5 +0x2168 VAP_PROG_STREAM_CNTL_6 +0x216C VAP_PROG_STREAM_CNTL_7 +0x2180 VAP_VTX_STATE_CNTL +0x2184 VAP_VSM_VTX_ASSM +0x2188 VAP_VTX_STATE_IND_REG_0 +0x218C VAP_VTX_STATE_IND_REG_1 +0x2190 VAP_VTX_STATE_IND_REG_2 +0x2194 VAP_VTX_STATE_IND_REG_3 +0x2198 VAP_VTX_STATE_IND_REG_4 +0x219C VAP_VTX_STATE_IND_REG_5 +0x21A0 VAP_VTX_STATE_IND_REG_6 +0x21A4 VAP_VTX_STATE_IND_REG_7 +0x21A8 VAP_VTX_STATE_IND_REG_8 +0x21AC VAP_VTX_STATE_IND_REG_9 +0x21B0 VAP_VTX_STATE_IND_REG_10 +0x21B4 VAP_VTX_STATE_IND_REG_11 +0x21B8 VAP_VTX_STATE_IND_REG_12 +0x21BC VAP_VTX_STATE_IND_REG_13 +0x21C0 VAP_VTX_STATE_IND_REG_14 +0x21C4 VAP_VTX_STATE_IND_REG_15 +0x21DC VAP_PSC_SGN_NORM_CNTL +0x21E0 VAP_PROG_STREAM_CNTL_EXT_0 +0x21E4 VAP_PROG_STREAM_CNTL_EXT_1 +0x21E8 VAP_PROG_STREAM_CNTL_EXT_2 +0x21EC VAP_PROG_STREAM_CNTL_EXT_3 +0x21F0 VAP_PROG_STREAM_CNTL_EXT_4 +0x21F4 VAP_PROG_STREAM_CNTL_EXT_5 +0x21F8 VAP_PROG_STREAM_CNTL_EXT_6 +0x21FC VAP_PROG_STREAM_CNTL_EXT_7 +0x2200 VAP_PVS_VECTOR_INDX_REG +0x2204 VAP_PVS_VECTOR_DATA_REG +0x2208 VAP_PVS_VECTOR_DATA_REG_128 +0x221C VAP_CLIP_CNTL +0x2220 VAP_GB_VERT_CLIP_ADJ +0x2224 VAP_GB_VERT_DISC_ADJ +0x2228 VAP_GB_HORZ_CLIP_ADJ +0x222C VAP_GB_HORZ_DISC_ADJ +0x2230 VAP_PVS_FLOW_CNTL_ADDRS_0 +0x2234 VAP_PVS_FLOW_CNTL_ADDRS_1 +0x2238 VAP_PVS_FLOW_CNTL_ADDRS_2 +0x223C VAP_PVS_FLOW_CNTL_ADDRS_3 +0x2240 VAP_PVS_FLOW_CNTL_ADDRS_4 +0x2244 VAP_PVS_FLOW_CNTL_ADDRS_5 +0x2248 VAP_PVS_FLOW_CNTL_ADDRS_6 +0x224C VAP_PVS_FLOW_CNTL_ADDRS_7 +0x2250 VAP_PVS_FLOW_CNTL_ADDRS_8 +0x2254 VAP_PVS_FLOW_CNTL_ADDRS_9 +0x2258 VAP_PVS_FLOW_CNTL_ADDRS_10 +0x225C VAP_PVS_FLOW_CNTL_ADDRS_11 +0x2260 VAP_PVS_FLOW_CNTL_ADDRS_12 +0x2264 VAP_PVS_FLOW_CNTL_ADDRS_13 +0x2268 VAP_PVS_FLOW_CNTL_ADDRS_14 +0x226C VAP_PVS_FLOW_CNTL_ADDRS_15 +0x2284 VAP_PVS_STATE_FLUSH_REG +0x2288 VAP_PVS_VTX_TIMEOUT_REG +0x2290 VAP_PVS_FLOW_CNTL_LOOP_INDEX_0 +0x2294 VAP_PVS_FLOW_CNTL_LOOP_INDEX_1 +0x2298 VAP_PVS_FLOW_CNTL_LOOP_INDEX_2 +0x229C VAP_PVS_FLOW_CNTL_LOOP_INDEX_3 +0x22A0 VAP_PVS_FLOW_CNTL_LOOP_INDEX_4 +0x22A4 VAP_PVS_FLOW_CNTL_LOOP_INDEX_5 +0x22A8 VAP_PVS_FLOW_CNTL_LOOP_INDEX_6 +0x22AC VAP_PVS_FLOW_CNTL_LOOP_INDEX_7 +0x22B0 VAP_PVS_FLOW_CNTL_LOOP_INDEX_8 +0x22B4 VAP_PVS_FLOW_CNTL_LOOP_INDEX_9 +0x22B8 VAP_PVS_FLOW_CNTL_LOOP_INDEX_10 +0x22BC VAP_PVS_FLOW_CNTL_LOOP_INDEX_11 +0x22C0 VAP_PVS_FLOW_CNTL_LOOP_INDEX_12 +0x22C4 VAP_PVS_FLOW_CNTL_LOOP_INDEX_13 +0x22C8 VAP_PVS_FLOW_CNTL_LOOP_INDEX_14 +0x22CC VAP_PVS_FLOW_CNTL_LOOP_INDEX_15 +0x22D0 VAP_PVS_CODE_CNTL_0 +0x22D4 VAP_PVS_CONST_CNTL +0x22D8 VAP_PVS_CODE_CNTL_1 +0x22DC VAP_PVS_FLOW_CNTL_OPC +0x342C RB2D_DSTCACHE_CTLSTAT +0x4000 GB_VAP_RASTER_VTX_FMT_0 +0x4004 GB_VAP_RASTER_VTX_FMT_1 +0x4008 GB_ENABLE +0x401C GB_SELECT +0x4020 GB_AA_CONFIG +0x4024 GB_FIFO_SIZE +0x4100 TX_INVALTAGS +0x4200 GA_POINT_S0 +0x4204 GA_POINT_T0 +0x4208 GA_POINT_S1 +0x420C GA_POINT_T1 +0x4214 GA_TRIANGLE_STIPPLE +0x421C GA_POINT_SIZE +0x4230 GA_POINT_MINMAX +0x4234 GA_LINE_CNTL +0x4238 GA_LINE_STIPPLE_CONFIG +0x4260 GA_LINE_STIPPLE_VALUE +0x4264 GA_LINE_S0 +0x4268 GA_LINE_S1 +0x4278 GA_COLOR_CONTROL +0x427C GA_SOLID_RG +0x4280 GA_SOLID_BA +0x4288 GA_POLY_MODE +0x428C GA_ROUND_MODE +0x4290 GA_OFFSET +0x4294 GA_FOG_SCALE +0x4298 GA_FOG_OFFSET +0x42A0 SU_TEX_WRAP +0x42A4 SU_POLY_OFFSET_FRONT_SCALE +0x42A8 SU_POLY_OFFSET_FRONT_OFFSET +0x42AC SU_POLY_OFFSET_BACK_SCALE +0x42B0 SU_POLY_OFFSET_BACK_OFFSET +0x42B4 SU_POLY_OFFSET_ENABLE +0x42B8 SU_CULL_MODE +0x42C0 SU_DEPTH_SCALE +0x42C4 SU_DEPTH_OFFSET +0x42C8 SU_REG_DEST +0x4300 RS_COUNT +0x4304 RS_INST_COUNT +0x4310 RS_IP_0 +0x4314 RS_IP_1 +0x4318 RS_IP_2 +0x431C RS_IP_3 +0x4320 RS_IP_4 +0x4324 RS_IP_5 +0x4328 RS_IP_6 +0x432C RS_IP_7 +0x4330 RS_INST_0 +0x4334 RS_INST_1 +0x4338 RS_INST_2 +0x433C RS_INST_3 +0x4340 RS_INST_4 +0x4344 RS_INST_5 +0x4348 RS_INST_6 +0x434C RS_INST_7 +0x4350 RS_INST_8 +0x4354 RS_INST_9 +0x4358 RS_INST_10 +0x435C RS_INST_11 +0x4360 RS_INST_12 +0x4364 RS_INST_13 +0x4368 RS_INST_14 +0x436C RS_INST_15 +0x43A4 SC_HYPERZ_EN +0x43A8 SC_EDGERULE +0x43B0 SC_CLIP_0_A +0x43B4 SC_CLIP_0_B +0x43B8 SC_CLIP_1_A +0x43BC SC_CLIP_1_B +0x43C0 SC_CLIP_2_A +0x43C4 SC_CLIP_2_B +0x43C8 SC_CLIP_3_A +0x43CC SC_CLIP_3_B +0x43D0 SC_CLIP_RULE +0x43E0 SC_SCISSOR0 +0x43E8 SC_SCREENDOOR +0x4440 TX_FILTER1_0 +0x4444 TX_FILTER1_1 +0x4448 TX_FILTER1_2 +0x444C TX_FILTER1_3 +0x4450 TX_FILTER1_4 +0x4454 TX_FILTER1_5 +0x4458 TX_FILTER1_6 +0x445C TX_FILTER1_7 +0x4460 TX_FILTER1_8 +0x4464 TX_FILTER1_9 +0x4468 TX_FILTER1_10 +0x446C TX_FILTER1_11 +0x4470 TX_FILTER1_12 +0x4474 TX_FILTER1_13 +0x4478 TX_FILTER1_14 +0x447C TX_FILTER1_15 +0x4580 TX_CHROMA_KEY_0 +0x4584 TX_CHROMA_KEY_1 +0x4588 TX_CHROMA_KEY_2 +0x458C TX_CHROMA_KEY_3 +0x4590 TX_CHROMA_KEY_4 +0x4594 TX_CHROMA_KEY_5 +0x4598 TX_CHROMA_KEY_6 +0x459C TX_CHROMA_KEY_7 +0x45A0 TX_CHROMA_KEY_8 +0x45A4 TX_CHROMA_KEY_9 +0x45A8 TX_CHROMA_KEY_10 +0x45AC TX_CHROMA_KEY_11 +0x45B0 TX_CHROMA_KEY_12 +0x45B4 TX_CHROMA_KEY_13 +0x45B8 TX_CHROMA_KEY_14 +0x45BC TX_CHROMA_KEY_15 +0x45C0 TX_BORDER_COLOR_0 +0x45C4 TX_BORDER_COLOR_1 +0x45C8 TX_BORDER_COLOR_2 +0x45CC TX_BORDER_COLOR_3 +0x45D0 TX_BORDER_COLOR_4 +0x45D4 TX_BORDER_COLOR_5 +0x45D8 TX_BORDER_COLOR_6 +0x45DC TX_BORDER_COLOR_7 +0x45E0 TX_BORDER_COLOR_8 +0x45E4 TX_BORDER_COLOR_9 +0x45E8 TX_BORDER_COLOR_10 +0x45EC TX_BORDER_COLOR_11 +0x45F0 TX_BORDER_COLOR_12 +0x45F4 TX_BORDER_COLOR_13 +0x45F8 TX_BORDER_COLOR_14 +0x45FC TX_BORDER_COLOR_15 +0x4600 US_CONFIG +0x4604 US_PIXSIZE +0x4608 US_CODE_OFFSET +0x460C US_RESET +0x4610 US_CODE_ADDR_0 +0x4614 US_CODE_ADDR_1 +0x4618 US_CODE_ADDR_2 +0x461C US_CODE_ADDR_3 +0x4620 US_TEX_INST_0 +0x4624 US_TEX_INST_1 +0x4628 US_TEX_INST_2 +0x462C US_TEX_INST_3 +0x4630 US_TEX_INST_4 +0x4634 US_TEX_INST_5 +0x4638 US_TEX_INST_6 +0x463C US_TEX_INST_7 +0x4640 US_TEX_INST_8 +0x4644 US_TEX_INST_9 +0x4648 US_TEX_INST_10 +0x464C US_TEX_INST_11 +0x4650 US_TEX_INST_12 +0x4654 US_TEX_INST_13 +0x4658 US_TEX_INST_14 +0x465C US_TEX_INST_15 +0x4660 US_TEX_INST_16 +0x4664 US_TEX_INST_17 +0x4668 US_TEX_INST_18 +0x466C US_TEX_INST_19 +0x4670 US_TEX_INST_20 +0x4674 US_TEX_INST_21 +0x4678 US_TEX_INST_22 +0x467C US_TEX_INST_23 +0x4680 US_TEX_INST_24 +0x4684 US_TEX_INST_25 +0x4688 US_TEX_INST_26 +0x468C US_TEX_INST_27 +0x4690 US_TEX_INST_28 +0x4694 US_TEX_INST_29 +0x4698 US_TEX_INST_30 +0x469C US_TEX_INST_31 +0x46A4 US_OUT_FMT_0 +0x46A8 US_OUT_FMT_1 +0x46AC US_OUT_FMT_2 +0x46B0 US_OUT_FMT_3 +0x46B4 US_W_FMT +0x46B8 US_CODE_BANK +0x46BC US_CODE_EXT +0x46C0 US_ALU_RGB_ADDR_0 +0x46C4 US_ALU_RGB_ADDR_1 +0x46C8 US_ALU_RGB_ADDR_2 +0x46CC US_ALU_RGB_ADDR_3 +0x46D0 US_ALU_RGB_ADDR_4 +0x46D4 US_ALU_RGB_ADDR_5 +0x46D8 US_ALU_RGB_ADDR_6 +0x46DC US_ALU_RGB_ADDR_7 +0x46E0 US_ALU_RGB_ADDR_8 +0x46E4 US_ALU_RGB_ADDR_9 +0x46E8 US_ALU_RGB_ADDR_10 +0x46EC US_ALU_RGB_ADDR_11 +0x46F0 US_ALU_RGB_ADDR_12 +0x46F4 US_ALU_RGB_ADDR_13 +0x46F8 US_ALU_RGB_ADDR_14 +0x46FC US_ALU_RGB_ADDR_15 +0x4700 US_ALU_RGB_ADDR_16 +0x4704 US_ALU_RGB_ADDR_17 +0x4708 US_ALU_RGB_ADDR_18 +0x470C US_ALU_RGB_ADDR_19 +0x4710 US_ALU_RGB_ADDR_20 +0x4714 US_ALU_RGB_ADDR_21 +0x4718 US_ALU_RGB_ADDR_22 +0x471C US_ALU_RGB_ADDR_23 +0x4720 US_ALU_RGB_ADDR_24 +0x4724 US_ALU_RGB_ADDR_25 +0x4728 US_ALU_RGB_ADDR_26 +0x472C US_ALU_RGB_ADDR_27 +0x4730 US_ALU_RGB_ADDR_28 +0x4734 US_ALU_RGB_ADDR_29 +0x4738 US_ALU_RGB_ADDR_30 +0x473C US_ALU_RGB_ADDR_31 +0x4740 US_ALU_RGB_ADDR_32 +0x4744 US_ALU_RGB_ADDR_33 +0x4748 US_ALU_RGB_ADDR_34 +0x474C US_ALU_RGB_ADDR_35 +0x4750 US_ALU_RGB_ADDR_36 +0x4754 US_ALU_RGB_ADDR_37 +0x4758 US_ALU_RGB_ADDR_38 +0x475C US_ALU_RGB_ADDR_39 +0x4760 US_ALU_RGB_ADDR_40 +0x4764 US_ALU_RGB_ADDR_41 +0x4768 US_ALU_RGB_ADDR_42 +0x476C US_ALU_RGB_ADDR_43 +0x4770 US_ALU_RGB_ADDR_44 +0x4774 US_ALU_RGB_ADDR_45 +0x4778 US_ALU_RGB_ADDR_46 +0x477C US_ALU_RGB_ADDR_47 +0x4780 US_ALU_RGB_ADDR_48 +0x4784 US_ALU_RGB_ADDR_49 +0x4788 US_ALU_RGB_ADDR_50 +0x478C US_ALU_RGB_ADDR_51 +0x4790 US_ALU_RGB_ADDR_52 +0x4794 US_ALU_RGB_ADDR_53 +0x4798 US_ALU_RGB_ADDR_54 +0x479C US_ALU_RGB_ADDR_55 +0x47A0 US_ALU_RGB_ADDR_56 +0x47A4 US_ALU_RGB_ADDR_57 +0x47A8 US_ALU_RGB_ADDR_58 +0x47AC US_ALU_RGB_ADDR_59 +0x47B0 US_ALU_RGB_ADDR_60 +0x47B4 US_ALU_RGB_ADDR_61 +0x47B8 US_ALU_RGB_ADDR_62 +0x47BC US_ALU_RGB_ADDR_63 +0x47C0 US_ALU_ALPHA_ADDR_0 +0x47C4 US_ALU_ALPHA_ADDR_1 +0x47C8 US_ALU_ALPHA_ADDR_2 +0x47CC US_ALU_ALPHA_ADDR_3 +0x47D0 US_ALU_ALPHA_ADDR_4 +0x47D4 US_ALU_ALPHA_ADDR_5 +0x47D8 US_ALU_ALPHA_ADDR_6 +0x47DC US_ALU_ALPHA_ADDR_7 +0x47E0 US_ALU_ALPHA_ADDR_8 +0x47E4 US_ALU_ALPHA_ADDR_9 +0x47E8 US_ALU_ALPHA_ADDR_10 +0x47EC US_ALU_ALPHA_ADDR_11 +0x47F0 US_ALU_ALPHA_ADDR_12 +0x47F4 US_ALU_ALPHA_ADDR_13 +0x47F8 US_ALU_ALPHA_ADDR_14 +0x47FC US_ALU_ALPHA_ADDR_15 +0x4800 US_ALU_ALPHA_ADDR_16 +0x4804 US_ALU_ALPHA_ADDR_17 +0x4808 US_ALU_ALPHA_ADDR_18 +0x480C US_ALU_ALPHA_ADDR_19 +0x4810 US_ALU_ALPHA_ADDR_20 +0x4814 US_ALU_ALPHA_ADDR_21 +0x4818 US_ALU_ALPHA_ADDR_22 +0x481C US_ALU_ALPHA_ADDR_23 +0x4820 US_ALU_ALPHA_ADDR_24 +0x4824 US_ALU_ALPHA_ADDR_25 +0x4828 US_ALU_ALPHA_ADDR_26 +0x482C US_ALU_ALPHA_ADDR_27 +0x4830 US_ALU_ALPHA_ADDR_28 +0x4834 US_ALU_ALPHA_ADDR_29 +0x4838 US_ALU_ALPHA_ADDR_30 +0x483C US_ALU_ALPHA_ADDR_31 +0x4840 US_ALU_ALPHA_ADDR_32 +0x4844 US_ALU_ALPHA_ADDR_33 +0x4848 US_ALU_ALPHA_ADDR_34 +0x484C US_ALU_ALPHA_ADDR_35 +0x4850 US_ALU_ALPHA_ADDR_36 +0x4854 US_ALU_ALPHA_ADDR_37 +0x4858 US_ALU_ALPHA_ADDR_38 +0x485C US_ALU_ALPHA_ADDR_39 +0x4860 US_ALU_ALPHA_ADDR_40 +0x4864 US_ALU_ALPHA_ADDR_41 +0x4868 US_ALU_ALPHA_ADDR_42 +0x486C US_ALU_ALPHA_ADDR_43 +0x4870 US_ALU_ALPHA_ADDR_44 +0x4874 US_ALU_ALPHA_ADDR_45 +0x4878 US_ALU_ALPHA_ADDR_46 +0x487C US_ALU_ALPHA_ADDR_47 +0x4880 US_ALU_ALPHA_ADDR_48 +0x4884 US_ALU_ALPHA_ADDR_49 +0x4888 US_ALU_ALPHA_ADDR_50 +0x488C US_ALU_ALPHA_ADDR_51 +0x4890 US_ALU_ALPHA_ADDR_52 +0x4894 US_ALU_ALPHA_ADDR_53 +0x4898 US_ALU_ALPHA_ADDR_54 +0x489C US_ALU_ALPHA_ADDR_55 +0x48A0 US_ALU_ALPHA_ADDR_56 +0x48A4 US_ALU_ALPHA_ADDR_57 +0x48A8 US_ALU_ALPHA_ADDR_58 +0x48AC US_ALU_ALPHA_ADDR_59 +0x48B0 US_ALU_ALPHA_ADDR_60 +0x48B4 US_ALU_ALPHA_ADDR_61 +0x48B8 US_ALU_ALPHA_ADDR_62 +0x48BC US_ALU_ALPHA_ADDR_63 +0x48C0 US_ALU_RGB_INST_0 +0x48C4 US_ALU_RGB_INST_1 +0x48C8 US_ALU_RGB_INST_2 +0x48CC US_ALU_RGB_INST_3 +0x48D0 US_ALU_RGB_INST_4 +0x48D4 US_ALU_RGB_INST_5 +0x48D8 US_ALU_RGB_INST_6 +0x48DC US_ALU_RGB_INST_7 +0x48E0 US_ALU_RGB_INST_8 +0x48E4 US_ALU_RGB_INST_9 +0x48E8 US_ALU_RGB_INST_10 +0x48EC US_ALU_RGB_INST_11 +0x48F0 US_ALU_RGB_INST_12 +0x48F4 US_ALU_RGB_INST_13 +0x48F8 US_ALU_RGB_INST_14 +0x48FC US_ALU_RGB_INST_15 +0x4900 US_ALU_RGB_INST_16 +0x4904 US_ALU_RGB_INST_17 +0x4908 US_ALU_RGB_INST_18 +0x490C US_ALU_RGB_INST_19 +0x4910 US_ALU_RGB_INST_20 +0x4914 US_ALU_RGB_INST_21 +0x4918 US_ALU_RGB_INST_22 +0x491C US_ALU_RGB_INST_23 +0x4920 US_ALU_RGB_INST_24 +0x4924 US_ALU_RGB_INST_25 +0x4928 US_ALU_RGB_INST_26 +0x492C US_ALU_RGB_INST_27 +0x4930 US_ALU_RGB_INST_28 +0x4934 US_ALU_RGB_INST_29 +0x4938 US_ALU_RGB_INST_30 +0x493C US_ALU_RGB_INST_31 +0x4940 US_ALU_RGB_INST_32 +0x4944 US_ALU_RGB_INST_33 +0x4948 US_ALU_RGB_INST_34 +0x494C US_ALU_RGB_INST_35 +0x4950 US_ALU_RGB_INST_36 +0x4954 US_ALU_RGB_INST_37 +0x4958 US_ALU_RGB_INST_38 +0x495C US_ALU_RGB_INST_39 +0x4960 US_ALU_RGB_INST_40 +0x4964 US_ALU_RGB_INST_41 +0x4968 US_ALU_RGB_INST_42 +0x496C US_ALU_RGB_INST_43 +0x4970 US_ALU_RGB_INST_44 +0x4974 US_ALU_RGB_INST_45 +0x4978 US_ALU_RGB_INST_46 +0x497C US_ALU_RGB_INST_47 +0x4980 US_ALU_RGB_INST_48 +0x4984 US_ALU_RGB_INST_49 +0x4988 US_ALU_RGB_INST_50 +0x498C US_ALU_RGB_INST_51 +0x4990 US_ALU_RGB_INST_52 +0x4994 US_ALU_RGB_INST_53 +0x4998 US_ALU_RGB_INST_54 +0x499C US_ALU_RGB_INST_55 +0x49A0 US_ALU_RGB_INST_56 +0x49A4 US_ALU_RGB_INST_57 +0x49A8 US_ALU_RGB_INST_58 +0x49AC US_ALU_RGB_INST_59 +0x49B0 US_ALU_RGB_INST_60 +0x49B4 US_ALU_RGB_INST_61 +0x49B8 US_ALU_RGB_INST_62 +0x49BC US_ALU_RGB_INST_63 +0x49C0 US_ALU_ALPHA_INST_0 +0x49C4 US_ALU_ALPHA_INST_1 +0x49C8 US_ALU_ALPHA_INST_2 +0x49CC US_ALU_ALPHA_INST_3 +0x49D0 US_ALU_ALPHA_INST_4 +0x49D4 US_ALU_ALPHA_INST_5 +0x49D8 US_ALU_ALPHA_INST_6 +0x49DC US_ALU_ALPHA_INST_7 +0x49E0 US_ALU_ALPHA_INST_8 +0x49E4 US_ALU_ALPHA_INST_9 +0x49E8 US_ALU_ALPHA_INST_10 +0x49EC US_ALU_ALPHA_INST_11 +0x49F0 US_ALU_ALPHA_INST_12 +0x49F4 US_ALU_ALPHA_INST_13 +0x49F8 US_ALU_ALPHA_INST_14 +0x49FC US_ALU_ALPHA_INST_15 +0x4A00 US_ALU_ALPHA_INST_16 +0x4A04 US_ALU_ALPHA_INST_17 +0x4A08 US_ALU_ALPHA_INST_18 +0x4A0C US_ALU_ALPHA_INST_19 +0x4A10 US_ALU_ALPHA_INST_20 +0x4A14 US_ALU_ALPHA_INST_21 +0x4A18 US_ALU_ALPHA_INST_22 +0x4A1C US_ALU_ALPHA_INST_23 +0x4A20 US_ALU_ALPHA_INST_24 +0x4A24 US_ALU_ALPHA_INST_25 +0x4A28 US_ALU_ALPHA_INST_26 +0x4A2C US_ALU_ALPHA_INST_27 +0x4A30 US_ALU_ALPHA_INST_28 +0x4A34 US_ALU_ALPHA_INST_29 +0x4A38 US_ALU_ALPHA_INST_30 +0x4A3C US_ALU_ALPHA_INST_31 +0x4A40 US_ALU_ALPHA_INST_32 +0x4A44 US_ALU_ALPHA_INST_33 +0x4A48 US_ALU_ALPHA_INST_34 +0x4A4C US_ALU_ALPHA_INST_35 +0x4A50 US_ALU_ALPHA_INST_36 +0x4A54 US_ALU_ALPHA_INST_37 +0x4A58 US_ALU_ALPHA_INST_38 +0x4A5C US_ALU_ALPHA_INST_39 +0x4A60 US_ALU_ALPHA_INST_40 +0x4A64 US_ALU_ALPHA_INST_41 +0x4A68 US_ALU_ALPHA_INST_42 +0x4A6C US_ALU_ALPHA_INST_43 +0x4A70 US_ALU_ALPHA_INST_44 +0x4A74 US_ALU_ALPHA_INST_45 +0x4A78 US_ALU_ALPHA_INST_46 +0x4A7C US_ALU_ALPHA_INST_47 +0x4A80 US_ALU_ALPHA_INST_48 +0x4A84 US_ALU_ALPHA_INST_49 +0x4A88 US_ALU_ALPHA_INST_50 +0x4A8C US_ALU_ALPHA_INST_51 +0x4A90 US_ALU_ALPHA_INST_52 +0x4A94 US_ALU_ALPHA_INST_53 +0x4A98 US_ALU_ALPHA_INST_54 +0x4A9C US_ALU_ALPHA_INST_55 +0x4AA0 US_ALU_ALPHA_INST_56 +0x4AA4 US_ALU_ALPHA_INST_57 +0x4AA8 US_ALU_ALPHA_INST_58 +0x4AAC US_ALU_ALPHA_INST_59 +0x4AB0 US_ALU_ALPHA_INST_60 +0x4AB4 US_ALU_ALPHA_INST_61 +0x4AB8 US_ALU_ALPHA_INST_62 +0x4ABC US_ALU_ALPHA_INST_63 +0x4AC0 US_ALU_EXT_ADDR_0 +0x4AC4 US_ALU_EXT_ADDR_1 +0x4AC8 US_ALU_EXT_ADDR_2 +0x4ACC US_ALU_EXT_ADDR_3 +0x4AD0 US_ALU_EXT_ADDR_4 +0x4AD4 US_ALU_EXT_ADDR_5 +0x4AD8 US_ALU_EXT_ADDR_6 +0x4ADC US_ALU_EXT_ADDR_7 +0x4AE0 US_ALU_EXT_ADDR_8 +0x4AE4 US_ALU_EXT_ADDR_9 +0x4AE8 US_ALU_EXT_ADDR_10 +0x4AEC US_ALU_EXT_ADDR_11 +0x4AF0 US_ALU_EXT_ADDR_12 +0x4AF4 US_ALU_EXT_ADDR_13 +0x4AF8 US_ALU_EXT_ADDR_14 +0x4AFC US_ALU_EXT_ADDR_15 +0x4B00 US_ALU_EXT_ADDR_16 +0x4B04 US_ALU_EXT_ADDR_17 +0x4B08 US_ALU_EXT_ADDR_18 +0x4B0C US_ALU_EXT_ADDR_19 +0x4B10 US_ALU_EXT_ADDR_20 +0x4B14 US_ALU_EXT_ADDR_21 +0x4B18 US_ALU_EXT_ADDR_22 +0x4B1C US_ALU_EXT_ADDR_23 +0x4B20 US_ALU_EXT_ADDR_24 +0x4B24 US_ALU_EXT_ADDR_25 +0x4B28 US_ALU_EXT_ADDR_26 +0x4B2C US_ALU_EXT_ADDR_27 +0x4B30 US_ALU_EXT_ADDR_28 +0x4B34 US_ALU_EXT_ADDR_29 +0x4B38 US_ALU_EXT_ADDR_30 +0x4B3C US_ALU_EXT_ADDR_31 +0x4B40 US_ALU_EXT_ADDR_32 +0x4B44 US_ALU_EXT_ADDR_33 +0x4B48 US_ALU_EXT_ADDR_34 +0x4B4C US_ALU_EXT_ADDR_35 +0x4B50 US_ALU_EXT_ADDR_36 +0x4B54 US_ALU_EXT_ADDR_37 +0x4B58 US_ALU_EXT_ADDR_38 +0x4B5C US_ALU_EXT_ADDR_39 +0x4B60 US_ALU_EXT_ADDR_40 +0x4B64 US_ALU_EXT_ADDR_41 +0x4B68 US_ALU_EXT_ADDR_42 +0x4B6C US_ALU_EXT_ADDR_43 +0x4B70 US_ALU_EXT_ADDR_44 +0x4B74 US_ALU_EXT_ADDR_45 +0x4B78 US_ALU_EXT_ADDR_46 +0x4B7C US_ALU_EXT_ADDR_47 +0x4B80 US_ALU_EXT_ADDR_48 +0x4B84 US_ALU_EXT_ADDR_49 +0x4B88 US_ALU_EXT_ADDR_50 +0x4B8C US_ALU_EXT_ADDR_51 +0x4B90 US_ALU_EXT_ADDR_52 +0x4B94 US_ALU_EXT_ADDR_53 +0x4B98 US_ALU_EXT_ADDR_54 +0x4B9C US_ALU_EXT_ADDR_55 +0x4BA0 US_ALU_EXT_ADDR_56 +0x4BA4 US_ALU_EXT_ADDR_57 +0x4BA8 US_ALU_EXT_ADDR_58 +0x4BAC US_ALU_EXT_ADDR_59 +0x4BB0 US_ALU_EXT_ADDR_60 +0x4BB4 US_ALU_EXT_ADDR_61 +0x4BB8 US_ALU_EXT_ADDR_62 +0x4BBC US_ALU_EXT_ADDR_63 +0x4BC0 FG_FOG_BLEND +0x4BC4 FG_FOG_FACTOR +0x4BC8 FG_FOG_COLOR_R +0x4BCC FG_FOG_COLOR_G +0x4BD0 FG_FOG_COLOR_B +0x4BD4 FG_ALPHA_FUNC +0x4BD8 FG_DEPTH_SRC +0x4C00 US_ALU_CONST_R_0 +0x4C04 US_ALU_CONST_G_0 +0x4C08 US_ALU_CONST_B_0 +0x4C0C US_ALU_CONST_A_0 +0x4C10 US_ALU_CONST_R_1 +0x4C14 US_ALU_CONST_G_1 +0x4C18 US_ALU_CONST_B_1 +0x4C1C US_ALU_CONST_A_1 +0x4C20 US_ALU_CONST_R_2 +0x4C24 US_ALU_CONST_G_2 +0x4C28 US_ALU_CONST_B_2 +0x4C2C US_ALU_CONST_A_2 +0x4C30 US_ALU_CONST_R_3 +0x4C34 US_ALU_CONST_G_3 +0x4C38 US_ALU_CONST_B_3 +0x4C3C US_ALU_CONST_A_3 +0x4C40 US_ALU_CONST_R_4 +0x4C44 US_ALU_CONST_G_4 +0x4C48 US_ALU_CONST_B_4 +0x4C4C US_ALU_CONST_A_4 +0x4C50 US_ALU_CONST_R_5 +0x4C54 US_ALU_CONST_G_5 +0x4C58 US_ALU_CONST_B_5 +0x4C5C US_ALU_CONST_A_5 +0x4C60 US_ALU_CONST_R_6 +0x4C64 US_ALU_CONST_G_6 +0x4C68 US_ALU_CONST_B_6 +0x4C6C US_ALU_CONST_A_6 +0x4C70 US_ALU_CONST_R_7 +0x4C74 US_ALU_CONST_G_7 +0x4C78 US_ALU_CONST_B_7 +0x4C7C US_ALU_CONST_A_7 +0x4C80 US_ALU_CONST_R_8 +0x4C84 US_ALU_CONST_G_8 +0x4C88 US_ALU_CONST_B_8 +0x4C8C US_ALU_CONST_A_8 +0x4C90 US_ALU_CONST_R_9 +0x4C94 US_ALU_CONST_G_9 +0x4C98 US_ALU_CONST_B_9 +0x4C9C US_ALU_CONST_A_9 +0x4CA0 US_ALU_CONST_R_10 +0x4CA4 US_ALU_CONST_G_10 +0x4CA8 US_ALU_CONST_B_10 +0x4CAC US_ALU_CONST_A_10 +0x4CB0 US_ALU_CONST_R_11 +0x4CB4 US_ALU_CONST_G_11 +0x4CB8 US_ALU_CONST_B_11 +0x4CBC US_ALU_CONST_A_11 +0x4CC0 US_ALU_CONST_R_12 +0x4CC4 US_ALU_CONST_G_12 +0x4CC8 US_ALU_CONST_B_12 +0x4CCC US_ALU_CONST_A_12 +0x4CD0 US_ALU_CONST_R_13 +0x4CD4 US_ALU_CONST_G_13 +0x4CD8 US_ALU_CONST_B_13 +0x4CDC US_ALU_CONST_A_13 +0x4CE0 US_ALU_CONST_R_14 +0x4CE4 US_ALU_CONST_G_14 +0x4CE8 US_ALU_CONST_B_14 +0x4CEC US_ALU_CONST_A_14 +0x4CF0 US_ALU_CONST_R_15 +0x4CF4 US_ALU_CONST_G_15 +0x4CF8 US_ALU_CONST_B_15 +0x4CFC US_ALU_CONST_A_15 +0x4D00 US_ALU_CONST_R_16 +0x4D04 US_ALU_CONST_G_16 +0x4D08 US_ALU_CONST_B_16 +0x4D0C US_ALU_CONST_A_16 +0x4D10 US_ALU_CONST_R_17 +0x4D14 US_ALU_CONST_G_17 +0x4D18 US_ALU_CONST_B_17 +0x4D1C US_ALU_CONST_A_17 +0x4D20 US_ALU_CONST_R_18 +0x4D24 US_ALU_CONST_G_18 +0x4D28 US_ALU_CONST_B_18 +0x4D2C US_ALU_CONST_A_18 +0x4D30 US_ALU_CONST_R_19 +0x4D34 US_ALU_CONST_G_19 +0x4D38 US_ALU_CONST_B_19 +0x4D3C US_ALU_CONST_A_19 +0x4D40 US_ALU_CONST_R_20 +0x4D44 US_ALU_CONST_G_20 +0x4D48 US_ALU_CONST_B_20 +0x4D4C US_ALU_CONST_A_20 +0x4D50 US_ALU_CONST_R_21 +0x4D54 US_ALU_CONST_G_21 +0x4D58 US_ALU_CONST_B_21 +0x4D5C US_ALU_CONST_A_21 +0x4D60 US_ALU_CONST_R_22 +0x4D64 US_ALU_CONST_G_22 +0x4D68 US_ALU_CONST_B_22 +0x4D6C US_ALU_CONST_A_22 +0x4D70 US_ALU_CONST_R_23 +0x4D74 US_ALU_CONST_G_23 +0x4D78 US_ALU_CONST_B_23 +0x4D7C US_ALU_CONST_A_23 +0x4D80 US_ALU_CONST_R_24 +0x4D84 US_ALU_CONST_G_24 +0x4D88 US_ALU_CONST_B_24 +0x4D8C US_ALU_CONST_A_24 +0x4D90 US_ALU_CONST_R_25 +0x4D94 US_ALU_CONST_G_25 +0x4D98 US_ALU_CONST_B_25 +0x4D9C US_ALU_CONST_A_25 +0x4DA0 US_ALU_CONST_R_26 +0x4DA4 US_ALU_CONST_G_26 +0x4DA8 US_ALU_CONST_B_26 +0x4DAC US_ALU_CONST_A_26 +0x4DB0 US_ALU_CONST_R_27 +0x4DB4 US_ALU_CONST_G_27 +0x4DB8 US_ALU_CONST_B_27 +0x4DBC US_ALU_CONST_A_27 +0x4DC0 US_ALU_CONST_R_28 +0x4DC4 US_ALU_CONST_G_28 +0x4DC8 US_ALU_CONST_B_28 +0x4DCC US_ALU_CONST_A_28 +0x4DD0 US_ALU_CONST_R_29 +0x4DD4 US_ALU_CONST_G_29 +0x4DD8 US_ALU_CONST_B_29 +0x4DDC US_ALU_CONST_A_29 +0x4DE0 US_ALU_CONST_R_30 +0x4DE4 US_ALU_CONST_G_30 +0x4DE8 US_ALU_CONST_B_30 +0x4DEC US_ALU_CONST_A_30 +0x4DF0 US_ALU_CONST_R_31 +0x4DF4 US_ALU_CONST_G_31 +0x4DF8 US_ALU_CONST_B_31 +0x4DFC US_ALU_CONST_A_31 +0x4E04 RB3D_BLENDCNTL_R3 +0x4E08 RB3D_ABLENDCNTL_R3 +0x4E0C RB3D_COLOR_CHANNEL_MASK +0x4E10 RB3D_CONSTANT_COLOR +0x4E14 RB3D_COLOR_CLEAR_VALUE +0x4E18 RB3D_ROPCNTL_R3 +0x4E1C RB3D_CLRCMP_FLIPE_R3 +0x4E20 RB3D_CLRCMP_CLR_R3 +0x4E24 RB3D_CLRCMP_MSK_R3 +0x4E48 RB3D_DEBUG_CTL +0x4E4C RB3D_DSTCACHE_CTLSTAT_R3 +0x4E50 RB3D_DITHER_CTL +0x4E54 RB3D_CMASK_OFFSET0 +0x4E58 RB3D_CMASK_OFFSET1 +0x4E5C RB3D_CMASK_OFFSET2 +0x4E60 RB3D_CMASK_OFFSET3 +0x4E64 RB3D_CMASK_PITCH0 +0x4E68 RB3D_CMASK_PITCH1 +0x4E6C RB3D_CMASK_PITCH2 +0x4E70 RB3D_CMASK_PITCH3 +0x4E74 RB3D_CMASK_WRINDEX +0x4E78 RB3D_CMASK_DWORD +0x4E7C RB3D_CMASK_RDINDEX +0x4E80 RB3D_AARESOLVE_OFFSET +0x4E84 RB3D_AARESOLVE_PITCH +0x4E88 RB3D_AARESOLVE_CTL +0x4EA0 RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD +0x4EA4 RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD +0x4F04 ZB_ZSTENCILCNTL +0x4F08 ZB_STENCILREFMASK +0x4F14 ZB_ZTOP +0x4F18 ZB_ZCACHE_CTLSTAT +0x4F1C ZB_BW_CNTL +0x4F28 ZB_DEPTHCLEARVALUE +0x4F30 ZB_ZMASK_OFFSET +0x4F34 ZB_ZMASK_PITCH +0x4F38 ZB_ZMASK_WRINDEX +0x4F3C ZB_ZMASK_DWORD +0x4F40 ZB_ZMASK_RDINDEX +0x4F44 ZB_HIZ_OFFSET +0x4F48 ZB_HIZ_WRINDEX +0x4F4C ZB_HIZ_DWORD +0x4F50 ZB_HIZ_RDINDEX +0x4F54 ZB_HIZ_PITCH +0x4F58 ZB_ZPASS_DATA diff --git a/drivers/gpu/drm/radeon/reg_srcs/rs600 b/drivers/gpu/drm/radeon/reg_srcs/rs600 index 8e3c0b8..6801b86 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/rs600 +++ b/drivers/gpu/drm/radeon/reg_srcs/rs600 @@ -153,7 +153,7 @@ rs600 0x6d40 0x42A4 SU_POLY_OFFSET_FRONT_SCALE 0x42A8 SU_POLY_OFFSET_FRONT_OFFSET 0x42AC SU_POLY_OFFSET_BACK_SCALE -0x42B0 SU_POLY_OFFSET_BACK_OFFSET +0x42B0 SU_POLY_OFFSET_BACK_OFFSET 0x42B4 SU_POLY_OFFSET_ENABLE 0x42B8 SU_CULL_MODE 0x42C0 SU_DEPTH_SCALE @@ -291,6 +291,8 @@ rs600 0x6d40 0x46AC US_OUT_FMT_2 0x46B0 US_OUT_FMT_3 0x46B4 US_W_FMT +0x46B8 US_CODE_BANK +0x46BC US_CODE_EXT 0x46C0 US_ALU_RGB_ADDR_0 0x46C4 US_ALU_RGB_ADDR_1 0x46C8 US_ALU_RGB_ADDR_2 @@ -547,6 +549,70 @@ rs600 0x6d40 0x4AB4 US_ALU_ALPHA_INST_61 0x4AB8 US_ALU_ALPHA_INST_62 0x4ABC US_ALU_ALPHA_INST_63 +0x4AC0 US_ALU_EXT_ADDR_0 +0x4AC4 US_ALU_EXT_ADDR_1 +0x4AC8 US_ALU_EXT_ADDR_2 +0x4ACC US_ALU_EXT_ADDR_3 +0x4AD0 US_ALU_EXT_ADDR_4 +0x4AD4 US_ALU_EXT_ADDR_5 +0x4AD8 US_ALU_EXT_ADDR_6 +0x4ADC US_ALU_EXT_ADDR_7 +0x4AE0 US_ALU_EXT_ADDR_8 +0x4AE4 US_ALU_EXT_ADDR_9 +0x4AE8 US_ALU_EXT_ADDR_10 +0x4AEC US_ALU_EXT_ADDR_11 +0x4AF0 US_ALU_EXT_ADDR_12 +0x4AF4 US_ALU_EXT_ADDR_13 +0x4AF8 US_ALU_EXT_ADDR_14 +0x4AFC US_ALU_EXT_ADDR_15 +0x4B00 US_ALU_EXT_ADDR_16 +0x4B04 US_ALU_EXT_ADDR_17 +0x4B08 US_ALU_EXT_ADDR_18 +0x4B0C US_ALU_EXT_ADDR_19 +0x4B10 US_ALU_EXT_ADDR_20 +0x4B14 US_ALU_EXT_ADDR_21 +0x4B18 US_ALU_EXT_ADDR_22 +0x4B1C US_ALU_EXT_ADDR_23 +0x4B20 US_ALU_EXT_ADDR_24 +0x4B24 US_ALU_EXT_ADDR_25 +0x4B28 US_ALU_EXT_ADDR_26 +0x4B2C US_ALU_EXT_ADDR_27 +0x4B30 US_ALU_EXT_ADDR_28 +0x4B34 US_ALU_EXT_ADDR_29 +0x4B38 US_ALU_EXT_ADDR_30 +0x4B3C US_ALU_EXT_ADDR_31 +0x4B40 US_ALU_EXT_ADDR_32 +0x4B44 US_ALU_EXT_ADDR_33 +0x4B48 US_ALU_EXT_ADDR_34 +0x4B4C US_ALU_EXT_ADDR_35 +0x4B50 US_ALU_EXT_ADDR_36 +0x4B54 US_ALU_EXT_ADDR_37 +0x4B58 US_ALU_EXT_ADDR_38 +0x4B5C US_ALU_EXT_ADDR_39 +0x4B60 US_ALU_EXT_ADDR_40 +0x4B64 US_ALU_EXT_ADDR_41 +0x4B68 US_ALU_EXT_ADDR_42 +0x4B6C US_ALU_EXT_ADDR_43 +0x4B70 US_ALU_EXT_ADDR_44 +0x4B74 US_ALU_EXT_ADDR_45 +0x4B78 US_ALU_EXT_ADDR_46 +0x4B7C US_ALU_EXT_ADDR_47 +0x4B80 US_ALU_EXT_ADDR_48 +0x4B84 US_ALU_EXT_ADDR_49 +0x4B88 US_ALU_EXT_ADDR_50 +0x4B8C US_ALU_EXT_ADDR_51 +0x4B90 US_ALU_EXT_ADDR_52 +0x4B94 US_ALU_EXT_ADDR_53 +0x4B98 US_ALU_EXT_ADDR_54 +0x4B9C US_ALU_EXT_ADDR_55 +0x4BA0 US_ALU_EXT_ADDR_56 +0x4BA4 US_ALU_EXT_ADDR_57 +0x4BA8 US_ALU_EXT_ADDR_58 +0x4BAC US_ALU_EXT_ADDR_59 +0x4BB0 US_ALU_EXT_ADDR_60 +0x4BB4 US_ALU_EXT_ADDR_61 +0x4BB8 US_ALU_EXT_ADDR_62 +0x4BBC US_ALU_EXT_ADDR_63 0x4BC0 FG_FOG_BLEND 0x4BC4 FG_FOG_FACTOR 0x4BC8 FG_FOG_COLOR_R diff --git a/drivers/gpu/drm/radeon/reg_srcs/rv515 b/drivers/gpu/drm/radeon/reg_srcs/rv515 index 0102a0d..38abf63 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/rv515 +++ b/drivers/gpu/drm/radeon/reg_srcs/rv515 @@ -161,7 +161,12 @@ rv515 0x6d40 0x401C GB_SELECT 0x4020 GB_AA_CONFIG 0x4024 GB_FIFO_SIZE +0x4028 GB_Z_PEQ_CONFIG 0x4100 TX_INVALTAGS +0x4114 SU_TEX_WRAP_PS3 +0x4118 PS3_ENABLE +0x411c PS3_VTX_FMT +0x4120 PS3_TEX_SOURCE 0x4200 GA_POINT_S0 0x4204 GA_POINT_T0 0x4208 GA_POINT_S1 @@ -171,6 +176,7 @@ rv515 0x6d40 0x4230 GA_POINT_MINMAX 0x4234 GA_LINE_CNTL 0x4238 GA_LINE_STIPPLE_CONFIG +0x4258 GA_COLOR_CONTROL_PS3 0x4260 GA_LINE_STIPPLE_VALUE 0x4264 GA_LINE_S0 0x4268 GA_LINE_S1 diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 368415d..287fceb 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -223,15 +223,31 @@ int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) return 0; } +int rs400_mc_wait_for_idle(struct radeon_device *rdev) +{ + unsigned i; + uint32_t tmp; + + for (i = 0; i < rdev->usec_timeout; i++) { + /* read MC_STATUS */ + tmp = RREG32(0x0150); + if (tmp & (1 << 2)) { + return 0; + } + DRM_UDELAY(1); + } + return -1; +} + void rs400_gpu_init(struct radeon_device *rdev) { /* FIXME: HDP same place on rs400 ? */ r100_hdp_reset(rdev); /* FIXME: is this correct ? */ r420_pipes_init(rdev); - if (r300_mc_wait_for_idle(rdev)) { - printk(KERN_WARNING "Failed to wait MC idle while " - "programming pipes. Bad things might happen.\n"); + if (rs400_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "rs400: Failed to wait MC idle while " + "programming pipes. Bad things might happen. %08x\n", RREG32(0x150)); } } @@ -356,6 +372,7 @@ static int rs400_mc_init(struct radeon_device *rdev) rdev->mc.vram_location = G_00015C_MC_FB_START(tmp) << 16; rdev->mc.gtt_location = 0xFFFFFFFFUL; r = radeon_mc_setup(rdev); + rdev->mc.igp_sideport_enabled = radeon_combios_sideport_present(rdev); if (r) return r; return 0; @@ -369,8 +386,8 @@ void rs400_mc_program(struct radeon_device *rdev) r100_mc_stop(rdev, &save); /* Wait for mc idle */ - if (r300_mc_wait_for_idle(rdev)) - dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n"); + if (rs400_mc_wait_for_idle(rdev)) + dev_warn(rdev->dev, "rs400: Wait MC idle timeout before updating MC.\n"); WREG32(R_000148_MC_FB_LOCATION, S_000148_MC_FB_START(rdev->mc.vram_start >> 16) | S_000148_MC_FB_TOP(rdev->mc.vram_end >> 16)); @@ -395,6 +412,7 @@ static int rs400_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ r100_irq_set(rdev); + rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ r = r100_cp_init(rdev, 1024 * 1024); if (r) { @@ -446,7 +464,6 @@ int rs400_suspend(struct radeon_device *rdev) void rs400_fini(struct radeon_device *rdev) { - rs400_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -525,7 +542,6 @@ int rs400_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - rs400_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 4f8ea42..c381856 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -56,6 +56,7 @@ int rs600_mc_init(struct radeon_device *rdev) rdev->mc.vram_location = G_000004_MC_FB_START(tmp) << 16; rdev->mc.gtt_location = 0xffffffffUL; r = radeon_mc_setup(rdev); + rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); if (r) return r; return 0; @@ -134,7 +135,8 @@ void rs600_hpd_init(struct radeon_device *rdev) break; } } - rs600_irq_set(rdev); + if (rdev->irq.installed) + rs600_irq_set(rdev); } void rs600_hpd_fini(struct radeon_device *rdev) @@ -315,6 +317,11 @@ int rs600_irq_set(struct radeon_device *rdev) u32 hpd2 = RREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL) & ~S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1); + if (!rdev->irq.installed) { + WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); + WREG32(R_000040_GEN_INT_CNTL, 0); + return -EINVAL; + } if (rdev->irq.sw_int) { tmp |= S_000040_SW_INT_EN(1); } @@ -396,7 +403,7 @@ int rs600_irq_process(struct radeon_device *rdev) } while (status || r500_disp_int) { /* SW interrupt */ - if (G_000040_SW_INT_EN(status)) + if (G_000044_SW_INT(status)) radeon_fence_process(rdev); /* Vertical blank interrupts */ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) @@ -553,6 +560,7 @@ static int rs600_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ rs600_irq_set(rdev); + rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ r = r100_cp_init(rdev, 1024 * 1024); if (r) { @@ -602,7 +610,6 @@ int rs600_suspend(struct radeon_device *rdev) void rs600_fini(struct radeon_device *rdev) { - rs600_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -681,7 +688,6 @@ int rs600_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - rs600_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index 1e22f52..06e2771 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -172,6 +172,7 @@ static int rs690_mc_init(struct radeon_device *rdev) rdev->mc.vram_location = G_000100_MC_FB_START(tmp) << 16; rdev->mc.gtt_location = 0xFFFFFFFFUL; r = radeon_mc_setup(rdev); + rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); if (r) return r; return 0; @@ -625,6 +626,7 @@ static int rs690_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ rs600_irq_set(rdev); + rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ r = r100_cp_init(rdev, 1024 * 1024); if (r) { @@ -674,7 +676,6 @@ int rs690_suspend(struct radeon_device *rdev) void rs690_fini(struct radeon_device *rdev) { - rs690_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -754,7 +755,6 @@ int rs690_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - rs690_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 59632a5..0e1e6b8 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -479,6 +479,7 @@ static int rv515_startup(struct radeon_device *rdev) } /* Enable IRQ */ rs600_irq_set(rdev); + rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ r = r100_cp_init(rdev, 1024 * 1024); if (r) { @@ -536,7 +537,6 @@ void rv515_set_safe_registers(struct radeon_device *rdev) void rv515_fini(struct radeon_device *rdev) { - rv515_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -614,13 +614,12 @@ int rv515_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - rv515_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); + radeon_irq_kms_fini(rdev); rv370_pcie_gart_fini(rdev); radeon_agp_fini(rdev); - radeon_irq_kms_fini(rdev); rdev->accel_working = false; } return 0; diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 3bcb66e..0302167 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -549,9 +549,12 @@ static void rv770_gpu_init(struct radeon_device *rdev) gb_tiling_config |= BANK_SWAPS(1); - backend_map = r700_get_tile_pipe_to_backend_map(rdev->config.rv770.max_tile_pipes, - rdev->config.rv770.max_backends, - (0xff << rdev->config.rv770.max_backends) & 0xff); + if (rdev->family == CHIP_RV740) + backend_map = 0x28; + else + backend_map = r700_get_tile_pipe_to_backend_map(rdev->config.rv770.max_tile_pipes, + rdev->config.rv770.max_backends, + (0xff << rdev->config.rv770.max_backends) & 0xff); gb_tiling_config |= BACKEND_MAP(backend_map); cc_gc_shader_pipe_config = @@ -779,7 +782,6 @@ int rv770_mc_init(struct radeon_device *rdev) fixed20_12 a; u32 tmp; int chansize, numchan; - int r; /* Get VRAM informations */ rdev->mc.vram_is_ddr = true; @@ -822,9 +824,6 @@ int rv770_mc_init(struct radeon_device *rdev) rdev->mc.real_vram_size = rdev->mc.aper_size; if (rdev->flags & RADEON_IS_AGP) { - r = radeon_agp_init(rdev); - if (r) - return r; /* gtt_size is setup by radeon_agp_init */ rdev->mc.gtt_location = rdev->mc.agp_base; tmp = 0xFFFFFFFFUL - rdev->mc.agp_base - rdev->mc.gtt_size; @@ -891,26 +890,25 @@ static int rv770_startup(struct radeon_device *rdev) return r; } rv770_gpu_init(rdev); - - if (!rdev->r600_blit.shader_obj) { - r = r600_blit_init(rdev); + r = r600_blit_init(rdev); + if (r) { + r600_blit_fini(rdev); + rdev->asic->copy = NULL; + dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); + } + /* pin copy shader into vram */ + if (rdev->r600_blit.shader_obj) { + r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); + if (unlikely(r != 0)) + return r; + r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM, + &rdev->r600_blit.shader_gpu_addr); + radeon_bo_unreserve(rdev->r600_blit.shader_obj); if (r) { - DRM_ERROR("radeon: failed blitter (%d).\n", r); + DRM_ERROR("failed to pin blit object %d\n", r); return r; } } - - r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); - if (unlikely(r != 0)) - return r; - r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM, - &rdev->r600_blit.shader_gpu_addr); - radeon_bo_unreserve(rdev->r600_blit.shader_obj); - if (r) { - DRM_ERROR("failed to pin blit object %d\n", r); - return r; - } - /* Enable IRQ */ r = r600_irq_init(rdev); if (r) { @@ -972,13 +970,16 @@ int rv770_suspend(struct radeon_device *rdev) /* FIXME: we should wait for ring to be empty */ r700_cp_stop(rdev); rdev->cp.ready = false; + r600_irq_suspend(rdev); r600_wb_disable(rdev); rv770_pcie_gart_disable(rdev); /* unpin shaders bo */ - r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); - if (likely(r == 0)) { - radeon_bo_unpin(rdev->r600_blit.shader_obj); - radeon_bo_unreserve(rdev->r600_blit.shader_obj); + if (rdev->r600_blit.shader_obj) { + r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); + if (likely(r == 0)) { + radeon_bo_unpin(rdev->r600_blit.shader_obj); + radeon_bo_unreserve(rdev->r600_blit.shader_obj); + } } return 0; } @@ -1037,6 +1038,11 @@ int rv770_init(struct radeon_device *rdev) r = radeon_fence_driver_init(rdev); if (r) return r; + if (rdev->flags & RADEON_IS_AGP) { + r = radeon_agp_init(rdev); + if (r) + radeon_agp_disable(rdev); + } r = rv770_mc_init(rdev); if (r) return r; @@ -1062,22 +1068,25 @@ int rv770_init(struct radeon_device *rdev) rdev->accel_working = true; r = rv770_startup(rdev); if (r) { - rv770_suspend(rdev); + dev_err(rdev->dev, "disabling GPU acceleration\n"); + r600_cp_fini(rdev); r600_wb_fini(rdev); - radeon_ring_fini(rdev); + r600_irq_fini(rdev); + radeon_irq_kms_fini(rdev); rv770_pcie_gart_fini(rdev); rdev->accel_working = false; } if (rdev->accel_working) { r = radeon_ib_pool_init(rdev); if (r) { - DRM_ERROR("radeon: failed initializing IB pool (%d).\n", r); - rdev->accel_working = false; - } - r = r600_ib_test(rdev); - if (r) { - DRM_ERROR("radeon: failed testing IB (%d).\n", r); + dev_err(rdev->dev, "IB initialization failed (%d).\n", r); rdev->accel_working = false; + } else { + r = r600_ib_test(rdev); + if (r) { + dev_err(rdev->dev, "IB test failed (%d).\n", r); + rdev->accel_working = false; + } } } return 0; @@ -1085,19 +1094,16 @@ int rv770_init(struct radeon_device *rdev) void rv770_fini(struct radeon_device *rdev) { - rv770_suspend(rdev); - r600_blit_fini(rdev); + r600_cp_fini(rdev); + r600_wb_fini(rdev); r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); - radeon_ring_fini(rdev); - r600_wb_fini(rdev); rv770_pcie_gart_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); radeon_clocks_fini(rdev); - if (rdev->flags & RADEON_IS_AGP) - radeon_agp_fini(rdev); + radeon_agp_fini(rdev); radeon_bo_fini(rdev); radeon_atombios_fini(rdev); kfree(rdev->bios); diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 2920f9a..c7320ce 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -426,7 +426,8 @@ moved: bdev->man[bo->mem.mem_type].gpu_offset; bo->cur_placement = bo->mem.placement; spin_unlock(&bo->lock); - } + } else + bo->offset = 0; return 0; @@ -523,52 +524,44 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all) static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all) { struct ttm_bo_global *glob = bdev->glob; - struct ttm_buffer_object *entry, *nentry; - struct list_head *list, *next; - int ret; + struct ttm_buffer_object *entry = NULL; + int ret = 0; spin_lock(&glob->lru_lock); - list_for_each_safe(list, next, &bdev->ddestroy) { - entry = list_entry(list, struct ttm_buffer_object, ddestroy); - nentry = NULL; + if (list_empty(&bdev->ddestroy)) + goto out_unlock; - /* - * Protect the next list entry from destruction while we - * unlock the lru_lock. - */ + entry = list_first_entry(&bdev->ddestroy, + struct ttm_buffer_object, ddestroy); + kref_get(&entry->list_kref); - if (next != &bdev->ddestroy) { - nentry = list_entry(next, struct ttm_buffer_object, - ddestroy); + for (;;) { + struct ttm_buffer_object *nentry = NULL; + + if (entry->ddestroy.next != &bdev->ddestroy) { + nentry = list_first_entry(&entry->ddestroy, + struct ttm_buffer_object, ddestroy); kref_get(&nentry->list_kref); } - kref_get(&entry->list_kref); spin_unlock(&glob->lru_lock); ret = ttm_bo_cleanup_refs(entry, remove_all); kref_put(&entry->list_kref, ttm_bo_release_list); + entry = nentry; + + if (ret || !entry) + goto out; spin_lock(&glob->lru_lock); - if (nentry) { - bool next_onlist = !list_empty(next); - spin_unlock(&glob->lru_lock); - kref_put(&nentry->list_kref, ttm_bo_release_list); - spin_lock(&glob->lru_lock); - /* - * Someone might have raced us and removed the - * next entry from the list. We don't bother restarting - * list traversal. - */ - - if (!next_onlist) - break; - } - if (ret) + if (list_empty(&entry->ddestroy)) break; } - ret = !list_empty(&bdev->ddestroy); - spin_unlock(&glob->lru_lock); +out_unlock: + spin_unlock(&glob->lru_lock); +out: + if (entry) + kref_put(&entry->list_kref, ttm_bo_release_list); return ret; } @@ -950,6 +943,14 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, ttm_flag_masked(&cur_flags, placement->busy_placement[i], ~TTM_PL_MASK_MEMTYPE); + + if (mem_type == TTM_PL_SYSTEM) { + mem->mem_type = mem_type; + mem->placement = cur_flags; + mem->mm_node = NULL; + return 0; + } + ret = ttm_bo_mem_force_space(bo, mem_type, placement, mem, interruptible, no_wait); if (ret == 0 && mem->mm_node) { @@ -1019,6 +1020,12 @@ static int ttm_bo_mem_compat(struct ttm_placement *placement, struct ttm_mem_reg *mem) { int i; + struct drm_mm_node *node = mem->mm_node; + + if (node && placement->lpfn != 0 && + (node->start < placement->fpfn || + node->start + node->size > placement->lpfn)) + return -1; for (i = 0; i < placement->num_placement; i++) { if ((placement->placement[i] & mem->placement & @@ -1844,6 +1851,9 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) * anyone tries to access a ttm page. */ + if (bo->bdev->driver->swap_notify) + bo->bdev->driver->swap_notify(bo); + ret = ttm_tt_swapout(bo->ttm, bo->persistant_swap_storage); out: @@ -1864,3 +1874,4 @@ void ttm_bo_swapout_all(struct ttm_bo_device *bdev) while (ttm_bo_swapout(&bdev->glob->shrink) == 0) ; } +EXPORT_SYMBOL(ttm_bo_swapout_all); diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 2ecf7d0..5ca37a5 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -53,7 +53,6 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo, { struct ttm_tt *ttm = bo->ttm; struct ttm_mem_reg *old_mem = &bo->mem; - uint32_t save_flags = old_mem->placement; int ret; if (old_mem->mem_type != TTM_PL_SYSTEM) { @@ -62,7 +61,6 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo, ttm_flag_masked(&old_mem->placement, TTM_PL_FLAG_SYSTEM, TTM_PL_MASK_MEM); old_mem->mem_type = TTM_PL_SYSTEM; - save_flags = old_mem->placement; } ret = ttm_tt_set_placement_caching(ttm, new_mem->placement); @@ -77,7 +75,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo, *old_mem = *new_mem; new_mem->mm_node = NULL; - ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE); + return 0; } EXPORT_SYMBOL(ttm_bo_move_ttm); @@ -219,7 +217,6 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, void *old_iomap; void *new_iomap; int ret; - uint32_t save_flags = old_mem->placement; unsigned long i; unsigned long page; unsigned long add = 0; @@ -270,7 +267,6 @@ out2: *old_mem = *new_mem; new_mem->mm_node = NULL; - ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE); if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) && (ttm != NULL)) { ttm_tt_unbind(ttm); @@ -537,7 +533,6 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type]; struct ttm_mem_reg *old_mem = &bo->mem; int ret; - uint32_t save_flags = old_mem->placement; struct ttm_buffer_object *ghost_obj; void *tmp_obj = NULL; @@ -598,7 +593,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, *old_mem = *new_mem; new_mem->mm_node = NULL; - ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE); + return 0; } EXPORT_SYMBOL(ttm_bo_move_accel_cleanup); diff --git a/drivers/gpu/drm/ttm/ttm_lock.c b/drivers/gpu/drm/ttm/ttm_lock.c index f619ebc..3d172ef 100644 --- a/drivers/gpu/drm/ttm/ttm_lock.c +++ b/drivers/gpu/drm/ttm/ttm_lock.c @@ -288,6 +288,7 @@ void ttm_suspend_unlock(struct ttm_lock *lock) wake_up_all(&lock->queue); spin_unlock(&lock->lock); } +EXPORT_SYMBOL(ttm_suspend_unlock); static bool __ttm_suspend_lock(struct ttm_lock *lock) { @@ -309,3 +310,4 @@ void ttm_suspend_lock(struct ttm_lock *lock) { wait_event(lock->queue, __ttm_suspend_lock(lock)); } +EXPORT_SYMBOL(ttm_suspend_lock); diff --git a/drivers/gpu/drm/ttm/ttm_object.c b/drivers/gpu/drm/ttm/ttm_object.c index 1099aba..75e9d6f 100644 --- a/drivers/gpu/drm/ttm/ttm_object.c +++ b/drivers/gpu/drm/ttm/ttm_object.c @@ -109,8 +109,8 @@ struct ttm_ref_object { struct drm_hash_item hash; struct list_head head; struct kref kref; - struct ttm_base_object *obj; enum ttm_ref_type ref_type; + struct ttm_base_object *obj; struct ttm_object_file *tfile; }; diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 9c2b1cc..3d47a2c 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -196,23 +196,34 @@ EXPORT_SYMBOL(ttm_tt_populate); #ifdef CONFIG_X86 static inline int ttm_tt_set_page_caching(struct page *p, - enum ttm_caching_state c_state) + enum ttm_caching_state c_old, + enum ttm_caching_state c_new) { + int ret = 0; + if (PageHighMem(p)) return 0; - switch (c_state) { - case tt_cached: - return set_pages_wb(p, 1); - case tt_wc: - return set_memory_wc((unsigned long) page_address(p), 1); - default: - return set_pages_uc(p, 1); + if (c_old != tt_cached) { + /* p isn't in the default caching state, set it to + * writeback first to free its current memtype. */ + + ret = set_pages_wb(p, 1); + if (ret) + return ret; } + + if (c_new == tt_wc) + ret = set_memory_wc((unsigned long) page_address(p), 1); + else if (c_new == tt_uncached) + ret = set_pages_uc(p, 1); + + return ret; } #else /* CONFIG_X86 */ static inline int ttm_tt_set_page_caching(struct page *p, - enum ttm_caching_state c_state) + enum ttm_caching_state c_old, + enum ttm_caching_state c_new) { return 0; } @@ -245,7 +256,9 @@ static int ttm_tt_set_caching(struct ttm_tt *ttm, for (i = 0; i < ttm->num_pages; ++i) { cur_page = ttm->pages[i]; if (likely(cur_page != NULL)) { - ret = ttm_tt_set_page_caching(cur_page, c_state); + ret = ttm_tt_set_page_caching(cur_page, + ttm->caching_state, + c_state); if (unlikely(ret != 0)) goto out_err; } @@ -259,7 +272,7 @@ out_err: for (j = 0; j < i; ++j) { cur_page = ttm->pages[j]; if (likely(cur_page != NULL)) { - (void)ttm_tt_set_page_caching(cur_page, + (void)ttm_tt_set_page_caching(cur_page, c_state, ttm->caching_state); } } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index d6f2d2b..825ebe3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -48,6 +48,15 @@ struct ttm_placement vmw_vram_placement = { .busy_placement = &vram_placement_flags }; +struct ttm_placement vmw_vram_sys_placement = { + .fpfn = 0, + .lpfn = 0, + .num_placement = 1, + .placement = &vram_placement_flags, + .num_busy_placement = 1, + .busy_placement = &sys_placement_flags +}; + struct ttm_placement vmw_vram_ne_placement = { .fpfn = 0, .lpfn = 0, @@ -172,6 +181,18 @@ static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp) return 0; } +static void vmw_move_notify(struct ttm_buffer_object *bo, + struct ttm_mem_reg *new_mem) +{ + if (new_mem->mem_type != TTM_PL_SYSTEM) + vmw_dmabuf_gmr_unbind(bo); +} + +static void vmw_swap_notify(struct ttm_buffer_object *bo) +{ + vmw_dmabuf_gmr_unbind(bo); +} + /** * FIXME: We're using the old vmware polling method to sync. * Do this with fences instead. @@ -225,5 +246,7 @@ struct ttm_bo_driver vmw_bo_driver = { .sync_obj_wait = vmw_sync_obj_wait, .sync_obj_flush = vmw_sync_obj_flush, .sync_obj_unref = vmw_sync_obj_unref, - .sync_obj_ref = vmw_sync_obj_ref + .sync_obj_ref = vmw_sync_obj_ref, + .move_notify = vmw_move_notify, + .swap_notify = vmw_swap_notify }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 1db1ef3..0c9c081 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -147,6 +147,8 @@ static char *vmw_devname = "vmwgfx"; static int vmw_probe(struct pci_dev *, const struct pci_device_id *); static void vmw_master_init(struct vmw_master *); +static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, + void *ptr); static void vmw_print_capabilities(uint32_t capabilities) { @@ -207,6 +209,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) { struct vmw_private *dev_priv; int ret; + uint32_t svga_id; dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); if (unlikely(dev_priv == NULL)) { @@ -217,6 +220,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->dev = dev; dev_priv->vmw_chipset = chipset; + dev_priv->last_read_sequence = (uint32_t) -100; mutex_init(&dev_priv->hw_mutex); mutex_init(&dev_priv->cmdbuf_mutex); rwlock_init(&dev_priv->resource_lock); @@ -236,6 +240,16 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->mmio_start = pci_resource_start(dev->pdev, 2); mutex_lock(&dev_priv->hw_mutex); + + vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2); + svga_id = vmw_read(dev_priv, SVGA_REG_ID); + if (svga_id != SVGA_ID_2) { + ret = -ENOSYS; + DRM_ERROR("Unsuported SVGA ID 0x%x\n", svga_id); + mutex_unlock(&dev_priv->hw_mutex); + goto out_err0; + } + dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); if (dev_priv->capabilities & SVGA_CAP_GMR) { @@ -334,22 +348,24 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) */ DRM_INFO("It appears like vesafb is loaded. " - "Ignore above error if any. Entering stealth mode.\n"); + "Ignore above error if any.\n"); ret = pci_request_region(dev->pdev, 2, "vmwgfx stealth probe"); if (unlikely(ret != 0)) { DRM_ERROR("Failed reserving the SVGA MMIO resource.\n"); goto out_no_device; } - vmw_kms_init(dev_priv); - vmw_overlay_init(dev_priv); - } else { - ret = vmw_request_device(dev_priv); - if (unlikely(ret != 0)) - goto out_no_device; - vmw_kms_init(dev_priv); - vmw_overlay_init(dev_priv); - vmw_fb_init(dev_priv); } + ret = vmw_request_device(dev_priv); + if (unlikely(ret != 0)) + goto out_no_device; + vmw_kms_init(dev_priv); + vmw_overlay_init(dev_priv); + vmw_fb_init(dev_priv); + + dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier; + register_pm_notifier(&dev_priv->pm_nb); + + DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ? "Have 3D\n" : "No 3D\n"); return 0; @@ -385,17 +401,17 @@ static int vmw_driver_unload(struct drm_device *dev) DRM_INFO(VMWGFX_DRIVER_NAME " unload.\n"); - if (!dev_priv->stealth) { - vmw_fb_close(dev_priv); - vmw_kms_close(dev_priv); - vmw_overlay_close(dev_priv); - vmw_release_device(dev_priv); - pci_release_regions(dev->pdev); - } else { - vmw_kms_close(dev_priv); - vmw_overlay_close(dev_priv); + unregister_pm_notifier(&dev_priv->pm_nb); + + vmw_fb_close(dev_priv); + vmw_kms_close(dev_priv); + vmw_overlay_close(dev_priv); + vmw_release_device(dev_priv); + if (dev_priv->stealth) pci_release_region(dev->pdev, 2); - } + else + pci_release_regions(dev->pdev); + if (dev_priv->capabilities & SVGA_CAP_IRQMASK) drm_irq_uninstall(dev_priv->dev); if (dev->devname == vmw_devname) @@ -564,11 +580,6 @@ static int vmw_master_set(struct drm_device *dev, int ret = 0; DRM_INFO("Master set.\n"); - if (dev_priv->stealth) { - ret = vmw_request_device(dev_priv); - if (unlikely(ret != 0)) - return ret; - } if (active) { BUG_ON(active != &dev_priv->fbdev_master); @@ -628,18 +639,11 @@ static void vmw_master_drop(struct drm_device *dev, ttm_lock_set_kill(&vmaster->lock, true, SIGTERM); - if (dev_priv->stealth) { - ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM); - if (unlikely(ret != 0)) - DRM_ERROR("Unable to clean VRAM on master drop.\n"); - vmw_release_device(dev_priv); - } dev_priv->active_master = &dev_priv->fbdev_master; ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM); ttm_vt_unlock(&dev_priv->fbdev_master.lock); - if (!dev_priv->stealth) - vmw_fb_on(dev_priv); + vmw_fb_on(dev_priv); } @@ -650,6 +654,57 @@ static void vmw_remove(struct pci_dev *pdev) drm_put_dev(dev); } +static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, + void *ptr) +{ + struct vmw_private *dev_priv = + container_of(nb, struct vmw_private, pm_nb); + struct vmw_master *vmaster = dev_priv->active_master; + + switch (val) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + ttm_suspend_lock(&vmaster->lock); + + /** + * This empties VRAM and unbinds all GMR bindings. + * Buffer contents is moved to swappable memory. + */ + ttm_bo_swapout_all(&dev_priv->bdev); + break; + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + ttm_suspend_unlock(&vmaster->lock); + break; + case PM_RESTORE_PREPARE: + break; + case PM_POST_RESTORE: + break; + default: + break; + } + return 0; +} + +/** + * These might not be needed with the virtual SVGA device. + */ + +int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + return 0; +} + +int vmw_pci_resume(struct pci_dev *pdev) +{ + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + return pci_enable_device(pdev); +} + static struct drm_driver driver = { .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_MODESET, @@ -689,7 +744,9 @@ static struct drm_driver driver = { .name = VMWGFX_DRIVER_NAME, .id_table = vmw_pci_id_list, .probe = vmw_probe, - .remove = vmw_remove + .remove = vmw_remove, + .suspend = vmw_pci_suspend, + .resume = vmw_pci_resume }, .name = VMWGFX_DRIVER_NAME, .desc = VMWGFX_DRIVER_DESC, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index e61bd85..356dc93 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -32,16 +32,17 @@ #include "drmP.h" #include "vmwgfx_drm.h" #include "drm_hashtab.h" +#include "linux/suspend.h" #include "ttm/ttm_bo_driver.h" #include "ttm/ttm_object.h" #include "ttm/ttm_lock.h" #include "ttm/ttm_execbuf_util.h" #include "ttm/ttm_module.h" -#define VMWGFX_DRIVER_DATE "20090724" -#define VMWGFX_DRIVER_MAJOR 0 -#define VMWGFX_DRIVER_MINOR 1 -#define VMWGFX_DRIVER_PATCHLEVEL 2 +#define VMWGFX_DRIVER_DATE "20100209" +#define VMWGFX_DRIVER_MAJOR 1 +#define VMWGFX_DRIVER_MINOR 0 +#define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_MAX_RELOCATIONS 2048 @@ -95,6 +96,8 @@ struct vmw_surface { struct drm_vmw_size *sizes; uint32_t num_sizes; + bool scanout; + /* TODO so far just a extra pointer */ struct vmw_cursor_snooper snooper; }; @@ -110,6 +113,7 @@ struct vmw_fifo_state { unsigned long static_buffer_size; bool using_bounce_buffer; uint32_t capabilities; + struct mutex fifo_mutex; struct rw_semaphore rwsem; }; @@ -210,7 +214,7 @@ struct vmw_private { * Fencing and IRQs. */ - uint32_t fence_seq; + atomic_t fence_seq; wait_queue_head_t fence_queue; wait_queue_head_t fifo_queue; atomic_t fence_queue_waiters; @@ -258,6 +262,7 @@ struct vmw_private { struct vmw_master *active_master; struct vmw_master fbdev_master; + struct notifier_block pm_nb; }; static inline struct vmw_private *vmw_priv(struct drm_device *dev) @@ -353,6 +358,7 @@ extern int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv, struct vmw_dma_buffer *bo); extern int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv, struct vmw_dma_buffer *bo); +extern void vmw_dmabuf_gmr_unbind(struct ttm_buffer_object *bo); extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data, @@ -386,6 +392,7 @@ extern int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence); extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason); extern int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma); +extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv); /** * TTM glue - vmwgfx_ttm_glue.c @@ -401,6 +408,7 @@ extern int vmw_mmap(struct file *filp, struct vm_area_struct *vma); extern struct ttm_placement vmw_vram_placement; extern struct ttm_placement vmw_vram_ne_placement; +extern struct ttm_placement vmw_vram_sys_placement; extern struct ttm_placement vmw_sys_placement; extern struct ttm_bo_driver vmw_bo_driver; extern int vmw_dma_quiescent(struct drm_device *dev); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 2e92da5..d69caf9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -490,10 +490,29 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv, if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL) return 0; + /** + * Put BO in VRAM, only if there is space. + */ + + ret = ttm_bo_validate(bo, &vmw_vram_sys_placement, true, false); + if (unlikely(ret == -ERESTARTSYS)) + return ret; + + /** + * Otherwise, set it up as GMR. + */ + + if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL) + return 0; + ret = vmw_gmr_bind(dev_priv, bo); if (likely(ret == 0 || ret == -ERESTARTSYS)) return ret; + /** + * If that failed, try VRAM again, this time evicting + * previous contents. + */ ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false); return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 641dde7..a933670 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -559,6 +559,9 @@ int vmw_fb_init(struct vmw_private *vmw_priv) info->pixmap.scan_align = 1; #endif + info->aperture_base = vmw_priv->vram_start; + info->aperture_size = vmw_priv->vram_size; + /* * Dirty & Deferred IO */ @@ -649,14 +652,6 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv, if (unlikely(ret != 0)) goto err_unlock; - if (vmw_bo->gmr_bound) { - vmw_gmr_unbind(vmw_priv, vmw_bo->gmr_id); - spin_lock(&bo->glob->lru_lock); - ida_remove(&vmw_priv->gmr_ida, vmw_bo->gmr_id); - spin_unlock(&bo->glob->lru_lock); - vmw_bo->gmr_bound = NULL; - } - ret = ttm_bo_validate(bo, &ne_placement, false, false); ttm_bo_unreserve(bo); err_unlock: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 01feb48..39d43a0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -29,6 +29,25 @@ #include "drmP.h" #include "ttm/ttm_placement.h" +bool vmw_fifo_have_3d(struct vmw_private *dev_priv) +{ + __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + uint32_t fifo_min, hwversion; + + fifo_min = ioread32(fifo_mem + SVGA_FIFO_MIN); + if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int)) + return false; + + hwversion = ioread32(fifo_mem + SVGA_FIFO_3D_HWVERSION); + if (hwversion == 0) + return false; + + if (hwversion < SVGA3D_HWVERSION_WS65_B1) + return false; + + return true; +} + int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) { __le32 __iomem *fifo_mem = dev_priv->mmio_virt; @@ -55,6 +74,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) fifo->reserved_size = 0; fifo->using_bounce_buffer = false; + mutex_init(&fifo->fifo_mutex); init_rwsem(&fifo->rwsem); /* @@ -98,8 +118,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) (unsigned int) min, (unsigned int) fifo->capabilities); - dev_priv->fence_seq = (uint32_t) -100; - dev_priv->last_read_sequence = (uint32_t) -100; + atomic_set(&dev_priv->fence_seq, dev_priv->last_read_sequence); iowrite32(dev_priv->last_read_sequence, fifo_mem + SVGA_FIFO_FENCE); return vmw_fifo_send_fence(dev_priv, &dummy); @@ -265,7 +284,7 @@ void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes) uint32_t reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE; int ret; - down_write(&fifo_state->rwsem); + mutex_lock(&fifo_state->fifo_mutex); max = ioread32(fifo_mem + SVGA_FIFO_MAX); min = ioread32(fifo_mem + SVGA_FIFO_MIN); next_cmd = ioread32(fifo_mem + SVGA_FIFO_NEXT_CMD); @@ -333,7 +352,7 @@ void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes) } out_err: fifo_state->reserved_size = 0; - up_write(&fifo_state->rwsem); + mutex_unlock(&fifo_state->fifo_mutex); return NULL; } @@ -408,6 +427,7 @@ void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) } + down_write(&fifo_state->rwsem); if (fifo_state->using_bounce_buffer || reserveable) { next_cmd += bytes; if (next_cmd >= max) @@ -419,8 +439,9 @@ void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) if (reserveable) iowrite32(0, fifo_mem + SVGA_FIFO_RESERVED); mb(); - vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); up_write(&fifo_state->rwsem); + vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); + mutex_unlock(&fifo_state->fifo_mutex); } int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence) @@ -433,9 +454,7 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence) fm = vmw_fifo_reserve(dev_priv, bytes); if (unlikely(fm == NULL)) { - down_write(&fifo_state->rwsem); - *sequence = dev_priv->fence_seq; - up_write(&fifo_state->rwsem); + *sequence = atomic_read(&dev_priv->fence_seq); ret = -ENOMEM; (void)vmw_fallback_wait(dev_priv, false, true, *sequence, false, 3*HZ); @@ -443,7 +462,7 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence) } do { - *sequence = dev_priv->fence_seq++; + *sequence = atomic_add_return(1, &dev_priv->fence_seq); } while (*sequence == 0); if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE)) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 5fa6a4e..1c7a316 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -43,11 +43,17 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, param->value = vmw_overlay_num_free_overlays(dev_priv); break; case DRM_VMW_PARAM_3D: - param->value = dev_priv->capabilities & SVGA_CAP_3D ? 1 : 0; + param->value = vmw_fifo_have_3d(dev_priv) ? 1 : 0; break; case DRM_VMW_PARAM_FIFO_OFFSET: param->value = dev_priv->mmio_start; break; + case DRM_VMW_PARAM_HW_CAPS: + param->value = dev_priv->capabilities; + break; + case DRM_VMW_PARAM_FIFO_CAPS: + param->value = dev_priv->fifo.capabilities; + break; default: DRM_ERROR("Illegal vmwgfx get param request: %d\n", param->param); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index d40086f..4d7cb53 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -85,19 +85,12 @@ bool vmw_fence_signaled(struct vmw_private *dev_priv, return true; /** - * Below is to signal stale fences that have wrapped. - * First, block fence submission. - */ - - down_read(&fifo_state->rwsem); - - /** * Then check if the sequence is higher than what we've actually * emitted. Then the fence is stale and signaled. */ - ret = ((dev_priv->fence_seq - sequence) > VMW_FENCE_WRAP); - up_read(&fifo_state->rwsem); + ret = ((atomic_read(&dev_priv->fence_seq) - sequence) + > VMW_FENCE_WRAP); return ret; } @@ -127,7 +120,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, if (fifo_idle) down_read(&fifo_state->rwsem); - signal_seq = dev_priv->fence_seq; + signal_seq = atomic_read(&dev_priv->fence_seq); ret = 0; for (;;) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index b1af76e..31f9afe 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -553,9 +553,7 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, } *cmd; int i, increment = 1; - if (!num_clips || - !(dev_priv->fifo.capabilities & - SVGA_FIFO_CAP_SCREEN_OBJECT)) { + if (!num_clips) { num_clips = 1; clips = &norect; norect.x1 = norect.y1 = 0; @@ -574,10 +572,10 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, for (i = 0; i < num_clips; i++, clips += increment) { cmd[i].header = cpu_to_le32(SVGA_CMD_UPDATE); - cmd[i].body.x = cpu_to_le32(clips[i].x1); - cmd[i].body.y = cpu_to_le32(clips[i].y1); - cmd[i].body.width = cpu_to_le32(clips[i].x2 - clips[i].x1); - cmd[i].body.height = cpu_to_le32(clips[i].y2 - clips[i].y1); + cmd[i].body.x = cpu_to_le32(clips->x1); + cmd[i].body.y = cpu_to_le32(clips->y1); + cmd[i].body.width = cpu_to_le32(clips->x2 - clips->x1); + cmd[i].body.height = cpu_to_le32(clips->y2 - clips->y1); } vmw_fifo_commit(dev_priv, sizeof(*cmd) * num_clips); @@ -709,6 +707,9 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, if (ret) goto try_dmabuf; + if (!surface->scanout) + goto err_not_scanout; + ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb, mode_cmd->width, mode_cmd->height); @@ -742,6 +743,13 @@ try_dmabuf: } return &vfb->base; + +err_not_scanout: + DRM_ERROR("surface not marked as scanout\n"); + /* vmw_user_surface_lookup takes one ref */ + vmw_surface_unreference(&surface); + + return NULL; } static int vmw_kms_fb_changed(struct drm_device *dev) @@ -761,10 +769,10 @@ int vmw_kms_init(struct vmw_private *dev_priv) drm_mode_config_init(dev); dev->mode_config.funcs = &vmw_kms_funcs; - dev->mode_config.min_width = 640; - dev->mode_config.min_height = 480; - dev->mode_config.max_width = 2048; - dev->mode_config.max_height = 2048; + dev->mode_config.min_width = 1; + dev->mode_config.min_height = 1; + dev->mode_config.max_width = dev_priv->fb_max_width; + dev->mode_config.max_height = dev_priv->fb_max_height; ret = vmw_kms_init_legacy_display_system(dev_priv); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index bb6e6a0..5b6eabe 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -104,7 +104,6 @@ static int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, bool pin, bool interruptible) { struct ttm_buffer_object *bo = &buf->base; - struct ttm_bo_global *glob = bo->glob; struct ttm_placement *overlay_placement = &vmw_vram_placement; int ret; @@ -116,14 +115,6 @@ static int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, if (unlikely(ret != 0)) goto err; - if (buf->gmr_bound) { - vmw_gmr_unbind(dev_priv, buf->gmr_id); - spin_lock(&glob->lru_lock); - ida_remove(&dev_priv->gmr_ida, buf->gmr_id); - spin_unlock(&glob->lru_lock); - buf->gmr_bound = NULL; - } - if (pin) overlay_placement = &vmw_vram_ne_placement; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index c012d59..f8fbbc6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -574,6 +574,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, srf->flags = req->flags; srf->format = req->format; + srf->scanout = req->scanout; memcpy(srf->mip_levels, req->mip_levels, sizeof(srf->mip_levels)); srf->num_sizes = 0; for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) @@ -599,6 +600,26 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, if (unlikely(ret != 0)) goto out_err1; + if (srf->scanout && + srf->num_sizes == 1 && + srf->sizes[0].width == 64 && + srf->sizes[0].height == 64 && + srf->format == SVGA3D_A8R8G8B8) { + + srf->snooper.image = kmalloc(64 * 64 * 4, GFP_KERNEL); + /* clear the image */ + if (srf->snooper.image) { + memset(srf->snooper.image, 0x00, 64 * 64 * 4); + } else { + DRM_ERROR("Failed to allocate cursor_image\n"); + ret = -ENOMEM; + goto out_err1; + } + } else { + srf->snooper.image = NULL; + } + srf->snooper.crtc = NULL; + user_srf->base.shareable = false; user_srf->base.tfile = NULL; @@ -622,24 +643,6 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, return ret; } - if (srf->flags & (1 << 9) && - srf->num_sizes == 1 && - srf->sizes[0].width == 64 && - srf->sizes[0].height == 64 && - srf->format == SVGA3D_A8R8G8B8) { - - srf->snooper.image = kmalloc(64 * 64 * 4, GFP_KERNEL); - /* clear the image */ - if (srf->snooper.image) - memset(srf->snooper.image, 0x00, 64 * 64 * 4); - else - DRM_ERROR("Failed to allocate cursor_image\n"); - - } else { - srf->snooper.image = NULL; - } - srf->snooper.crtc = NULL; - rep->sid = user_srf->base.hash.key; if (rep->sid == SVGA3D_INVALID_ID) DRM_ERROR("Created bad Surface ID.\n"); @@ -754,20 +757,29 @@ static size_t vmw_dmabuf_acc_size(struct ttm_bo_global *glob, return bo_user_size + page_array_size; } -void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo) +void vmw_dmabuf_gmr_unbind(struct ttm_buffer_object *bo) { struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo); struct ttm_bo_global *glob = bo->glob; struct vmw_private *dev_priv = container_of(bo->bdev, struct vmw_private, bdev); - ttm_mem_global_free(glob->mem_glob, bo->acc_size); if (vmw_bo->gmr_bound) { vmw_gmr_unbind(dev_priv, vmw_bo->gmr_id); spin_lock(&glob->lru_lock); ida_remove(&dev_priv->gmr_ida, vmw_bo->gmr_id); spin_unlock(&glob->lru_lock); + vmw_bo->gmr_bound = false; } +} + +void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo) +{ + struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo); + struct ttm_bo_global *glob = bo->glob; + + vmw_dmabuf_gmr_unbind(bo); + ttm_mem_global_free(glob->mem_glob, bo->acc_size); kfree(vmw_bo); } @@ -813,18 +825,10 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv, static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo) { struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo); - struct vmw_dma_buffer *vmw_bo = &vmw_user_bo->dma; struct ttm_bo_global *glob = bo->glob; - struct vmw_private *dev_priv = - container_of(bo->bdev, struct vmw_private, bdev); + vmw_dmabuf_gmr_unbind(bo); ttm_mem_global_free(glob->mem_glob, bo->acc_size); - if (vmw_bo->gmr_bound) { - vmw_gmr_unbind(dev_priv, vmw_bo->gmr_id); - spin_lock(&glob->lru_lock); - ida_remove(&dev_priv->gmr_ida, vmw_bo->gmr_id); - spin_unlock(&glob->lru_lock); - } kfree(vmw_user_bo); } @@ -868,7 +872,7 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, } ret = vmw_dmabuf_init(dev_priv, &vmw_user_bo->dma, req->size, - &vmw_vram_placement, true, + &vmw_vram_sys_placement, true, &vmw_user_dmabuf_destroy); if (unlikely(ret != 0)) return ret; diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 1ac0c93..2f6cf69 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -961,7 +961,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, remaining -= 7; pr_devel("client 0x%p called 'target'\n", priv); /* if target is default */ - if (!strncmp(buf, "default", 7)) + if (!strncmp(curr_pos, "default", 7)) pdev = pci_dev_get(vga_default_device()); else { if (!vga_pci_str_to_vars(curr_pos, remaining, |