OSDN Git Service

Merge branch 'drm-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 12 Aug 2010 16:21:39 +0000 (09:21 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 12 Aug 2010 16:21:39 +0000 (09:21 -0700)
* 'drm-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (55 commits)
  io-mapping: move asm include inside the config option
  vgaarb: drop vga.h include
  drm/radeon: Add probing of clocks from device-tree
  drm/radeon: drop old and broken mesa warning
  drm/radeon: Fix pci_map_page() error checking
  drm: Remove count_lock for calling lastclose() after 58474713 (v2)
  drm/radeon/kms: allow FG_ALPHA_VALUE on r5xx
  drm/radeon/kms: another r6xx/r7xx CS checker fix
  DRM: Replace kmalloc/memset combos with kzalloc
  drm: expand gamma_set
  drm/edid: Split mode lists out to their own header for readability
  drm/edid: Rewrite mode parse to use the generic detailed block walk
  drm/edid: Add detailed block walk for VTB extensions
  drm/edid: Add detailed block walk for CEA extensions
  drm: Remove unused fields from drm_display_info
  drm: Use ENOENT consistently for the error return for an unmatched handle.
  drm/radeon/kms: mark 3D power states as performance
  drm: Only set DPMS once on the CRTC not after every encoder.
  drm/radeon/kms: add additional quirk for Acer rv620 laptop
  drm: Propagate error code from fb_create()
  ...

Fix up trivial conflicts in drivers/gpu/drm/drm_edid.c

70 files changed:
drivers/gpu/drm/ati_pcigart.c
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_edid_modes.h [new file with mode: 0644]
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/i2c/ch7006_drv.c
drivers/gpu/drm/i2c/ch7006_mode.c
drivers/gpu/drm/i2c/ch7006_priv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_fb.c
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bios.h
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_dp.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_encoder.h
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_hw.c
drivers/gpu/drm/nouveau/nouveau_i2c.c
drivers/gpu/drm/nouveau/nouveau_i2c.h
drivers/gpu/drm/nouveau/nouveau_irq.c
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_reg.h
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv04_crtc.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv04_tv.c
drivers/gpu/drm/nouveau/nv10_graph.c
drivers/gpu/drm/nouveau/nv30_fb.c
drivers/gpu/drm/nouveau/nv50_crtc.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nvc0_fb.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvc0_fifo.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvc0_graph.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvc0_instmem.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r600_cp.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_clocks.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_cursor.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_i2c.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/reg_srcs/rv515
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
include/drm/drmP.h
include/drm/drm_core.h
include/drm/drm_crtc.h
include/drm/drm_edid.h
include/linux/io-mapping.h
include/linux/vgaarb.h

index 17be051..1c36492 100644 (file)
@@ -152,7 +152,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
                /* we need to support large memory configurations */
                entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i],
                                                 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-               if (entry->busaddr[i] == 0) {
+               if (pci_dma_mapping_error(dev->pdev, entry->busaddr[i])) {
                        DRM_ERROR("unable to map PCIGART pages!\n");
                        drm_ati_pcigart_cleanup(dev, gart_info);
                        address = NULL;
index a5c9ce9..3e257a5 100644 (file)
@@ -328,14 +328,13 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
                return -EINVAL;
        }
 
-       list = kmalloc(sizeof(*list), GFP_KERNEL);
+       list = kzalloc(sizeof(*list), GFP_KERNEL);
        if (!list) {
                if (map->type == _DRM_REGISTERS)
                        iounmap(map->handle);
                kfree(map);
                return -EINVAL;
        }
-       memset(list, 0, sizeof(*list));
        list->map = map;
 
        mutex_lock(&dev->struct_mutex);
@@ -678,13 +677,12 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
                return -EINVAL;
        }
 
-       entry->buflist = kmalloc(count * sizeof(*entry->buflist), GFP_KERNEL);
+       entry->buflist = kzalloc(count * sizeof(*entry->buflist), GFP_KERNEL);
        if (!entry->buflist) {
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
-       memset(entry->buflist, 0, count * sizeof(*entry->buflist));
 
        entry->buf_size = size;
        entry->page_order = page_order;
@@ -708,7 +706,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
                buf->file_priv = NULL;
 
                buf->dev_priv_size = dev->driver->dev_priv_size;
-               buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL);
+               buf->dev_private = kzalloc(buf->dev_priv_size, GFP_KERNEL);
                if (!buf->dev_private) {
                        /* Set count correctly so we free the proper amount. */
                        entry->buf_count = count;
@@ -717,7 +715,6 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
                        atomic_dec(&dev->buf_alloc);
                        return -ENOMEM;
                }
-               memset(buf->dev_private, 0, buf->dev_priv_size);
 
                DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address);
 
@@ -832,22 +829,20 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
                return -EINVAL;
        }
 
-       entry->buflist = kmalloc(count * sizeof(*entry->buflist), GFP_KERNEL);
+       entry->buflist = kzalloc(count * sizeof(*entry->buflist), GFP_KERNEL);
        if (!entry->buflist) {
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
-       memset(entry->buflist, 0, count * sizeof(*entry->buflist));
 
-       entry->seglist = kmalloc(count * sizeof(*entry->seglist), GFP_KERNEL);
+       entry->seglist = kzalloc(count * sizeof(*entry->seglist), GFP_KERNEL);
        if (!entry->seglist) {
                kfree(entry->buflist);
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
-       memset(entry->seglist, 0, count * sizeof(*entry->seglist));
 
        /* Keep the original pagelist until we know all the allocations
         * have succeeded
@@ -911,8 +906,8 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
                        buf->file_priv = NULL;
 
                        buf->dev_priv_size = dev->driver->dev_priv_size;
-                       buf->dev_private = kmalloc(buf->dev_priv_size,
-                                                 GFP_KERNEL);
+                       buf->dev_private = kzalloc(buf->dev_priv_size,
+                                               GFP_KERNEL);
                        if (!buf->dev_private) {
                                /* Set count correctly so we free the proper amount. */
                                entry->buf_count = count;
@@ -923,7 +918,6 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
                                atomic_dec(&dev->buf_alloc);
                                return -ENOMEM;
                        }
-                       memset(buf->dev_private, 0, buf->dev_priv_size);
 
                        DRM_DEBUG("buffer %d @ %p\n",
                                  entry->buf_count, buf->address);
@@ -1048,14 +1042,13 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
                return -EINVAL;
        }
 
-       entry->buflist = kmalloc(count * sizeof(*entry->buflist),
+       entry->buflist = kzalloc(count * sizeof(*entry->buflist),
                                GFP_KERNEL);
        if (!entry->buflist) {
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
-       memset(entry->buflist, 0, count * sizeof(*entry->buflist));
 
        entry->buf_size = size;
        entry->page_order = page_order;
@@ -1080,7 +1073,7 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
                buf->file_priv = NULL;
 
                buf->dev_priv_size = dev->driver->dev_priv_size;
-               buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL);
+               buf->dev_private = kzalloc(buf->dev_priv_size, GFP_KERNEL);
                if (!buf->dev_private) {
                        /* Set count correctly so we free the proper amount. */
                        entry->buf_count = count;
@@ -1090,8 +1083,6 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
                        return -ENOMEM;
                }
 
-               memset(buf->dev_private, 0, buf->dev_priv_size);
-
                DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address);
 
                offset += alignment;
@@ -1209,14 +1200,13 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
                return -EINVAL;
        }
 
-       entry->buflist = kmalloc(count * sizeof(*entry->buflist),
+       entry->buflist = kzalloc(count * sizeof(*entry->buflist),
                                GFP_KERNEL);
        if (!entry->buflist) {
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
-       memset(entry->buflist, 0, count * sizeof(*entry->buflist));
 
        entry->buf_size = size;
        entry->page_order = page_order;
@@ -1240,7 +1230,7 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
                buf->file_priv = NULL;
 
                buf->dev_priv_size = dev->driver->dev_priv_size;
-               buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL);
+               buf->dev_private = kzalloc(buf->dev_priv_size, GFP_KERNEL);
                if (!buf->dev_private) {
                        /* Set count correctly so we free the proper amount. */
                        entry->buf_count = count;
@@ -1249,7 +1239,6 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
                        atomic_dec(&dev->buf_alloc);
                        return -ENOMEM;
                }
-               memset(buf->dev_private, 0, buf->dev_priv_size);
 
                DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address);
 
index 4c68f76..37e0b4f 100644 (file)
@@ -1682,9 +1682,9 @@ int drm_mode_addfb(struct drm_device *dev,
        /* TODO setup destructor callback */
 
        fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
-       if (!fb) {
+       if (IS_ERR(fb)) {
                DRM_ERROR("could not create framebuffer\n");
-               ret = -EINVAL;
+               ret = PTR_ERR(fb);
                goto out;
        }
 
@@ -2541,7 +2541,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
                goto out;
        }
 
-       crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size);
+       crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
 
 out:
        mutex_unlock(&dev->mode_config.mutex);
index b9e4dbf..7e31d43 100644 (file)
@@ -817,12 +817,12 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
                                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));
                        }
+
+                       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 */
index dce5c4a..96e9631 100644 (file)
 #include <linux/i2c-algo-bit.h>
 #include "drmP.h"
 #include "drm_edid.h"
+#include "drm_edid_modes.h"
+
+#define version_greater(edid, maj, min) \
+       (((edid)->version > (maj)) || \
+        ((edid)->version == (maj) && (edid)->revision > (min)))
 
 #define EDID_EST_TIMINGS 16
 #define EDID_STD_TIMINGS 8
 /* use +hsync +vsync for detailed mode */
 #define EDID_QUIRK_DETAILED_SYNC_PP            (1 << 6)
 
+struct detailed_mode_closure {
+       struct drm_connector *connector;
+       struct edid *edid;
+       bool preferred;
+       u32 quirks;
+       int modes;
+};
 
 #define LEVEL_DMT      0
 #define LEVEL_GTF      1
@@ -375,7 +387,6 @@ static u32 edid_get_quirks(struct edid *edid)
 #define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay)
 #define MODE_REFRESH_DIFF(m,r) (abs((m)->vrefresh - target_refresh))
 
-
 /**
  * edid_fixup_preferred - set preferred modes based on quirk list
  * @connector: has mode list to fix up
@@ -422,245 +433,6 @@ static void edid_fixup_preferred(struct drm_connector *connector,
        preferred_mode->type |= DRM_MODE_TYPE_PREFERRED;
 }
 
-/*
- * Add the Autogenerated from the DMT spec.
- * This table is copied from xfree86/modes/xf86EdidModes.c.
- * But the mode with Reduced blank feature is deleted.
- */
-static struct drm_display_mode drm_dmt_modes[] = {
-       /* 640x350@85Hz */
-       { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
-                  736, 832, 0, 350, 382, 385, 445, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 640x400@85Hz */
-       { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
-                  736, 832, 0, 400, 401, 404, 445, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 720x400@85Hz */
-       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 756,
-                  828, 936, 0, 400, 401, 404, 446, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 640x480@60Hz */
-       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
-                  752, 800, 0, 480, 489, 492, 525, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 640x480@72Hz */
-       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
-                  704, 832, 0, 480, 489, 492, 520, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 640x480@75Hz */
-       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
-                  720, 840, 0, 480, 481, 484, 500, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 640x480@85Hz */
-       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 36000, 640, 696,
-                  752, 832, 0, 480, 481, 484, 509, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 800x600@56Hz */
-       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
-                  896, 1024, 0, 600, 601, 603, 625, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 800x600@60Hz */
-       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
-                  968, 1056, 0, 600, 601, 605, 628, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 800x600@72Hz */
-       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
-                  976, 1040, 0, 600, 637, 643, 666, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 800x600@75Hz */
-       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
-                  896, 1056, 0, 600, 601, 604, 625, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 800x600@85Hz */
-       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832,
-                  896, 1048, 0, 600, 601, 604, 631, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 848x480@60Hz */
-       { DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864,
-                  976, 1088, 0, 480, 486, 494, 517, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1024x768@43Hz, interlace */
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032,
-                  1208, 1264, 0, 768, 768, 772, 817, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
-                       DRM_MODE_FLAG_INTERLACE) },
-       /* 1024x768@60Hz */
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
-                  1184, 1344, 0, 768, 771, 777, 806, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1024x768@70Hz */
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
-                  1184, 1328, 0, 768, 771, 777, 806, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1024x768@75Hz */
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040,
-                  1136, 1312, 0, 768, 769, 772, 800, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1024x768@85Hz */
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
-                  1168, 1376, 0, 768, 769, 772, 808, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1152x864@75Hz */
-       { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
-                  1344, 1600, 0, 864, 865, 868, 900, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1280x768@60Hz */
-       { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
-                  1472, 1664, 0, 768, 771, 778, 798, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1280x768@75Hz */
-       { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 102250, 1280, 1360,
-                  1488, 1696, 0, 768, 771, 778, 805, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1280x768@85Hz */
-       { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360,
-                  1496, 1712, 0, 768, 771, 778, 809, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1280x800@60Hz */
-       { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
-                  1480, 1680, 0, 800, 803, 809, 831, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1280x800@75Hz */
-       { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 106500, 1280, 1360,
-                  1488, 1696, 0, 800, 803, 809, 838, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1280x800@85Hz */
-       { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360,
-                  1496, 1712, 0, 800, 803, 809, 843, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1280x960@60Hz */
-       { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
-                  1488, 1800, 0, 960, 961, 964, 1000, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1280x960@85Hz */
-       { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344,
-                  1504, 1728, 0, 960, 961, 964, 1011, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1280x1024@60Hz */
-       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
-                  1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1280x1024@75Hz */
-       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
-                  1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1280x1024@85Hz */
-       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344,
-                  1504, 1728, 0, 1024, 1025, 1028, 1072, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1360x768@60Hz */
-       { DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
-                  1536, 1792, 0, 768, 771, 777, 795, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1440x1050@60Hz */
-       { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
-                  1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1440x1050@75Hz */
-       { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504,
-                  1648, 1896, 0, 1050, 1053, 1057, 1099, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1440x1050@85Hz */
-       { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504,
-                  1656, 1912, 0, 1050, 1053, 1057, 1105, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1440x900@60Hz */
-       { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
-                  1672, 1904, 0, 900, 903, 909, 934, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1440x900@75Hz */
-       { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 136750, 1440, 1536,
-                  1688, 1936, 0, 900, 903, 909, 942, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1440x900@85Hz */
-       { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544,
-                  1696, 1952, 0, 900, 903, 909, 948, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1600x1200@60Hz */
-       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
-                  1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1600x1200@65Hz */
-       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 175500, 1600, 1664,
-                  1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1600x1200@70Hz */
-       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 189000, 1600, 1664,
-                  1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1600x1200@75Hz */
-       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 202500, 1600, 1664,
-                  1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1600x1200@85Hz */
-       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664,
-                  1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1680x1050@60Hz */
-       { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
-                  1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1680x1050@75Hz */
-       { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 187000, 1680, 1800,
-                  1976, 2272, 0, 1050, 1053, 1059, 1099, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1680x1050@85Hz */
-       { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808,
-                  1984, 2288, 0, 1050, 1053, 1059, 1105, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1792x1344@60Hz */
-       { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
-                  2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1729x1344@75Hz */
-       { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888,
-                  2104, 2456, 0, 1344, 1345, 1348, 1417, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1853x1392@60Hz */
-       { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
-                  2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1856x1392@75Hz */
-       { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984,
-                  2208, 2560, 0, 1392, 1395, 1399, 1500, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1920x1200@60Hz */
-       { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
-                  2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1920x1200@75Hz */
-       { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 245250, 1920, 2056,
-                  2264, 2608, 0, 1200, 1203, 1209, 1255, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1920x1200@85Hz */
-       { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064,
-                  2272, 2624, 0, 1200, 1203, 1209, 1262, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1920x1440@60Hz */
-       { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048,
-                  2256, 2600, 0, 1440, 1441, 1444, 1500, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1920x1440@75Hz */
-       { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064,
-                  2288, 2640, 0, 1440, 1441, 1444, 1500, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 2560x1600@60Hz */
-       { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
-                  3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 2560x1600@75HZ */
-       { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 443250, 2560, 2768,
-                  3048, 3536, 0, 1600, 1603, 1609, 1672, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 2560x1600@85HZ */
-       { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768,
-                  3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-};
-static const int drm_num_dmt_modes =
-       sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
-
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
                                           int hsize, int vsize, int fresh)
 {
@@ -685,6 +457,46 @@ EXPORT_SYMBOL(drm_mode_find_dmt);
 typedef void detailed_cb(struct detailed_timing *timing, void *closure);
 
 static void
+cea_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure)
+{
+       int i, n = 0;
+       u8 rev = ext[0x01], d = ext[0x02];
+       u8 *det_base = ext + d;
+
+       switch (rev) {
+       case 0:
+               /* can't happen */
+               return;
+       case 1:
+               /* have to infer how many blocks we have, check pixel clock */
+               for (i = 0; i < 6; i++)
+                       if (det_base[18*i] || det_base[18*i+1])
+                               n++;
+               break;
+       default:
+               /* explicit count */
+               n = min(ext[0x03] & 0x0f, 6);
+               break;
+       }
+
+       for (i = 0; i < n; i++)
+               cb((struct detailed_timing *)(det_base + 18 * i), closure);
+}
+
+static void
+vtb_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure)
+{
+       unsigned int i, n = min((int)ext[0x02], 6);
+       u8 *det_base = ext + 5;
+
+       if (ext[0x01] != 1)
+               return; /* unknown version */
+
+       for (i = 0; i < n; i++)
+               cb((struct detailed_timing *)(det_base + 18 * i), closure);
+}
+
+static void
 drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure)
 {
        int i;
@@ -696,7 +508,19 @@ drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure)
        for (i = 0; i < EDID_DETAILED_TIMINGS; i++)
                cb(&(edid->detailed_timings[i]), closure);
 
-       /* XXX extension block walk */
+       for (i = 1; i <= raw_edid[0x7e]; i++) {
+               u8 *ext = raw_edid + (i * EDID_LENGTH);
+               switch (*ext) {
+               case CEA_EXT:
+                       cea_for_each_detailed_block(ext, cb, closure);
+                       break;
+               case VTB_EXT:
+                       vtb_for_each_detailed_block(ext, cb, closure);
+                       break;
+               default:
+                       break;
+               }
+       }
 }
 
 static void
@@ -1047,117 +871,6 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
        return mode;
 }
 
-/*
- * Detailed mode info for the EDID "established modes" data to use.
- */
-static struct drm_display_mode edid_est_modes[] = {
-       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
-                  968, 1056, 0, 600, 601, 605, 628, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */
-       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
-                  896, 1024, 0, 600, 601, 603,  625, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */
-       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
-                  720, 840, 0, 480, 481, 484, 500, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */
-       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
-                  704,  832, 0, 480, 489, 491, 520, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */
-       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
-                  768,  864, 0, 480, 483, 486, 525, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */
-       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
-                  752, 800, 0, 480, 490, 492, 525, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */
-       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
-                  846, 900, 0, 400, 421, 423,  449, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */
-       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
-                  846,  900, 0, 400, 412, 414, 449, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */
-       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
-                  1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
-                  1136, 1312, 0,  768, 769, 772, 800, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
-                  1184, 1328, 0,  768, 771, 777, 806, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
-                  1184, 1344, 0,  768, 771, 777, 806, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
-                  1208, 1264, 0, 768, 768, 776, 817, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
-       { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
-                  928, 1152, 0, 624, 625, 628, 667, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */
-       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
-                  896, 1056, 0, 600, 601, 604,  625, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */
-       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
-                  976, 1040, 0, 600, 637, 643, 666, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */
-       { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
-                  1344, 1600, 0,  864, 865, 868, 900, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
-};
-
-/**
- * add_established_modes - get est. modes from EDID and add them
- * @edid: EDID block to scan
- *
- * Each EDID block contains a bitmap of the supported "established modes" list
- * (defined above).  Tease them out and add them to the global modes list.
- */
-static int add_established_modes(struct drm_connector *connector, struct edid *edid)
-{
-       struct drm_device *dev = connector->dev;
-       unsigned long est_bits = edid->established_timings.t1 |
-               (edid->established_timings.t2 << 8) |
-               ((edid->established_timings.mfg_rsvd & 0x80) << 9);
-       int i, modes = 0;
-
-       for (i = 0; i <= EDID_EST_TIMINGS; i++)
-               if (est_bits & (1<<i)) {
-                       struct drm_display_mode *newmode;
-                       newmode = drm_mode_duplicate(dev, &edid_est_modes[i]);
-                       if (newmode) {
-                               drm_mode_probed_add(connector, newmode);
-                               modes++;
-                       }
-               }
-
-       return modes;
-}
-
-/**
- * add_standard_modes - get std. modes from EDID and add them
- * @edid: EDID block to scan
- *
- * Standard modes can be calculated using the CVT standard.  Grab them from
- * @edid, calculate them, and add them to the list.
- */
-static int add_standard_modes(struct drm_connector *connector, struct edid *edid)
-{
-       int i, modes = 0;
-
-       for (i = 0; i < EDID_STD_TIMINGS; i++) {
-               struct drm_display_mode *newmode;
-
-               newmode = drm_mode_std(connector, edid,
-                                      &edid->standard_timings[i],
-                                      edid->revision);
-               if (newmode) {
-                       drm_mode_probed_add(connector, newmode);
-                       modes++;
-               }
-       }
-
-       return modes;
-}
-
 static bool
 mode_is_rb(struct drm_display_mode *mode)
 {
@@ -1267,113 +980,33 @@ drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
        return modes;
 }
 
-static int drm_cvt_modes(struct drm_connector *connector,
-                        struct detailed_timing *timing)
+static void
+do_inferred_modes(struct detailed_timing *timing, void *c)
 {
-       int i, j, modes = 0;
-       struct drm_display_mode *newmode;
-       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]);
+       struct detailed_mode_closure *closure = c;
+       struct detailed_non_pixel *data = &timing->data.other_data;
+       int gtf = (closure->edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
 
-               if (!memcmp(cvt->code, empty, 3))
-                       continue;
+       if (gtf && data->type == EDID_DETAIL_MONITOR_RANGE)
+               closure->modes += drm_gtf_modes_for_range(closure->connector,
+                                                         closure->edid,
+                                                         timing);
+}
 
-               height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 4) + 1) * 2;
-               switch (cvt->code[1] & 0x0c) {
-               case 0x00:
-                       width = height * 4 / 3;
-                       break;
-               case 0x04:
-                       width = height * 16 / 9;
-                       break;
-               case 0x08:
-                       width = height * 16 / 10;
-                       break;
-               case 0x0c:
-                       width = height * 15 / 9;
-                       break;
-               }
+static int
+add_inferred_modes(struct drm_connector *connector, struct edid *edid)
+{
+       struct detailed_mode_closure closure = {
+               connector, edid, 0, 0, 0
+       };
 
-               for (j = 1; j < 5; j++) {
-                       if (cvt->code[2] & (1 << j)) {
-                               newmode = drm_cvt_mode(dev, width, height,
-                                                      rates[j], j == 0,
-                                                      false, false);
-                               if (newmode) {
-                                       drm_mode_probed_add(connector, newmode);
-                                       modes++;
-                               }
-                       }
-               }
-       }
+       if (version_greater(edid, 1, 0))
+               drm_for_each_detailed_block((u8 *)edid, do_inferred_modes,
+                                           &closure);
 
-       return modes;
+       return closure.modes;
 }
 
-static const struct {
-       short w;
-       short h;
-       short r;
-       short rb;
-} est3_modes[] = {
-       /* byte 6 */
-       { 640, 350, 85, 0 },
-       { 640, 400, 85, 0 },
-       { 720, 400, 85, 0 },
-       { 640, 480, 85, 0 },
-       { 848, 480, 60, 0 },
-       { 800, 600, 85, 0 },
-       { 1024, 768, 85, 0 },
-       { 1152, 864, 75, 0 },
-       /* byte 7 */
-       { 1280, 768, 60, 1 },
-       { 1280, 768, 60, 0 },
-       { 1280, 768, 75, 0 },
-       { 1280, 768, 85, 0 },
-       { 1280, 960, 60, 0 },
-       { 1280, 960, 85, 0 },
-       { 1280, 1024, 60, 0 },
-       { 1280, 1024, 85, 0 },
-       /* byte 8 */
-       { 1360, 768, 60, 0 },
-       { 1440, 900, 60, 1 },
-       { 1440, 900, 60, 0 },
-       { 1440, 900, 75, 0 },
-       { 1440, 900, 85, 0 },
-       { 1400, 1050, 60, 1 },
-       { 1400, 1050, 60, 0 },
-       { 1400, 1050, 75, 0 },
-       /* byte 9 */
-       { 1400, 1050, 85, 0 },
-       { 1680, 1050, 60, 1 },
-       { 1680, 1050, 60, 0 },
-       { 1680, 1050, 75, 0 },
-       { 1680, 1050, 85, 0 },
-       { 1600, 1200, 60, 0 },
-       { 1600, 1200, 65, 0 },
-       { 1600, 1200, 70, 0 },
-       /* byte 10 */
-       { 1600, 1200, 75, 0 },
-       { 1600, 1200, 85, 0 },
-       { 1792, 1344, 60, 0 },
-       { 1792, 1344, 85, 0 },
-       { 1856, 1392, 60, 0 },
-       { 1856, 1392, 75, 0 },
-       { 1920, 1200, 60, 1 },
-       { 1920, 1200, 60, 0 },
-       /* byte 11 */
-       { 1920, 1200, 75, 0 },
-       { 1920, 1200, 85, 0 },
-       { 1920, 1440, 60, 0 },
-       { 1920, 1440, 75, 0 },
-};
-
 static int
 drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
 {
@@ -1403,37 +1036,63 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
        return modes;
 }
 
-static int add_detailed_modes(struct drm_connector *connector,
-                             struct detailed_timing *timing,
-                             struct edid *edid, u32 quirks, int preferred)
+static void
+do_established_modes(struct detailed_timing *timing, void *c)
 {
-       int i, modes = 0;
+       struct detailed_mode_closure *closure = c;
        struct detailed_non_pixel *data = &timing->data.other_data;
-       int gtf = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
-       struct drm_display_mode *newmode;
-       struct drm_device *dev = connector->dev;
 
-       if (timing->pixel_clock) {
-               newmode = drm_mode_detailed(dev, edid, timing, quirks);
-               if (!newmode)
-                       return 0;
+       if (data->type == EDID_DETAIL_EST_TIMINGS)
+               closure->modes += drm_est3_modes(closure->connector, timing);
+}
 
-               if (preferred)
-                       newmode->type |= DRM_MODE_TYPE_PREFERRED;
+/**
+ * add_established_modes - get est. modes from EDID and add them
+ * @edid: EDID block to scan
+ *
+ * Each EDID block contains a bitmap of the supported "established modes" list
+ * (defined above).  Tease them out and add them to the global modes list.
+ */
+static int
+add_established_modes(struct drm_connector *connector, struct edid *edid)
+{
+       struct drm_device *dev = connector->dev;
+       unsigned long est_bits = edid->established_timings.t1 |
+               (edid->established_timings.t2 << 8) |
+               ((edid->established_timings.mfg_rsvd & 0x80) << 9);
+       int i, modes = 0;
+       struct detailed_mode_closure closure = {
+               connector, edid, 0, 0, 0
+       };
 
-               drm_mode_probed_add(connector, newmode);
-               return 1;
+       for (i = 0; i <= EDID_EST_TIMINGS; i++) {
+               if (est_bits & (1<<i)) {
+                       struct drm_display_mode *newmode;
+                       newmode = drm_mode_duplicate(dev, &edid_est_modes[i]);
+                       if (newmode) {
+                               drm_mode_probed_add(connector, newmode);
+                               modes++;
+                       }
+               }
        }
 
-       /* other timing types */
-       switch (data->type) {
-       case EDID_DETAIL_MONITOR_RANGE:
-               if (gtf)
-                       modes += drm_gtf_modes_for_range(connector, edid,
-                                                        timing);
-               break;
-       case EDID_DETAIL_STD_MODES:
-               /* Six modes per detailed section */
+       if (version_greater(edid, 1, 0))
+                   drm_for_each_detailed_block((u8 *)edid,
+                                               do_established_modes, &closure);
+
+       return modes + closure.modes;
+}
+
+static void
+do_standard_modes(struct detailed_timing *timing, void *c)
+{
+       struct detailed_mode_closure *closure = c;
+       struct detailed_non_pixel *data = &timing->data.other_data;
+       struct drm_connector *connector = closure->connector;
+       struct edid *edid = closure->edid;
+
+       if (data->type == EDID_DETAIL_STD_MODES) {
+               int i;
                for (i = 0; i < 6; i++) {
                        struct std_timing *std;
                        struct drm_display_mode *newmode;
@@ -1443,108 +1102,169 @@ static int add_detailed_modes(struct drm_connector *connector,
                                               edid->revision);
                        if (newmode) {
                                drm_mode_probed_add(connector, newmode);
-                               modes++;
+                               closure->modes++;
                        }
                }
-               break;
-       case EDID_DETAIL_CVT_3BYTE:
-               modes += drm_cvt_modes(connector, timing);
-               break;
-       case EDID_DETAIL_EST_TIMINGS:
-               modes += drm_est3_modes(connector, timing);
-               break;
-       default:
-               break;
        }
-
-       return modes;
 }
 
 /**
- * add_detailed_info - get detailed mode info from EDID data
- * @connector: attached connector
+ * add_standard_modes - get std. modes from EDID and add them
  * @edid: EDID block to scan
- * @quirks: quirks to apply
  *
- * Some of the detailed timing sections may contain mode information.  Grab
- * it and add it to the list.
+ * Standard modes can be calculated using the appropriate standard (DMT,
+ * GTF or CVT. Grab them from @edid and add them to the list.
  */
-static int add_detailed_info(struct drm_connector *connector,
-                            struct edid *edid, u32 quirks)
+static int
+add_standard_modes(struct drm_connector *connector, struct edid *edid)
 {
        int i, modes = 0;
+       struct detailed_mode_closure closure = {
+               connector, edid, 0, 0, 0
+       };
+
+       for (i = 0; i < EDID_STD_TIMINGS; i++) {
+               struct drm_display_mode *newmode;
+
+               newmode = drm_mode_std(connector, edid,
+                                      &edid->standard_timings[i],
+                                      edid->revision);
+               if (newmode) {
+                       drm_mode_probed_add(connector, newmode);
+                       modes++;
+               }
+       }
+
+       if (version_greater(edid, 1, 0))
+               drm_for_each_detailed_block((u8 *)edid, do_standard_modes,
+                                           &closure);
+
+       /* XXX should also look for standard codes in VTB blocks */
+
+       return modes + closure.modes;
+}
 
-       for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
-               struct detailed_timing *timing = &edid->detailed_timings[i];
-               int preferred = (i == 0);
+static int drm_cvt_modes(struct drm_connector *connector,
+                        struct detailed_timing *timing)
+{
+       int i, j, modes = 0;
+       struct drm_display_mode *newmode;
+       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 };
 
-               if (preferred && edid->version == 1 && edid->revision < 4)
-                       preferred = (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
+       for (i = 0; i < 4; i++) {
+               int uninitialized_var(width), height;
+               cvt = &(timing->data.other_data.data.cvt[i]);
 
-               /* In 1.0, only timings are allowed */
-               if (!timing->pixel_clock && edid->version == 1 &&
-                       edid->revision == 0)
+               if (!memcmp(cvt->code, empty, 3))
                        continue;
 
-               modes += add_detailed_modes(connector, timing, edid, quirks,
-                                           preferred);
+               height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 4) + 1) * 2;
+               switch (cvt->code[1] & 0x0c) {
+               case 0x00:
+                       width = height * 4 / 3;
+                       break;
+               case 0x04:
+                       width = height * 16 / 9;
+                       break;
+               case 0x08:
+                       width = height * 16 / 10;
+                       break;
+               case 0x0c:
+                       width = height * 15 / 9;
+                       break;
+               }
+
+               for (j = 1; j < 5; j++) {
+                       if (cvt->code[2] & (1 << j)) {
+                               newmode = drm_cvt_mode(dev, width, height,
+                                                      rates[j], j == 0,
+                                                      false, false);
+                               if (newmode) {
+                                       drm_mode_probed_add(connector, newmode);
+                                       modes++;
+                               }
+                       }
+               }
        }
 
        return modes;
 }
 
-/**
- * add_detailed_mode_eedid - get detailed mode info from addtional timing
- *                     EDID block
- * @connector: attached connector
- * @edid: EDID block to scan(It is only to get addtional timing EDID block)
- * @quirks: quirks to apply
- *
- * Some of the detailed timing sections may contain mode information.  Grab
- * it and add it to the list.
- */
-static int add_detailed_info_eedid(struct drm_connector *connector,
-                            struct edid *edid, u32 quirks)
+static void
+do_cvt_mode(struct detailed_timing *timing, void *c)
 {
-       int i, modes = 0;
-       char *edid_ext = NULL;
-       struct detailed_timing *timing;
-       int start_offset, end_offset;
+       struct detailed_mode_closure *closure = c;
+       struct detailed_non_pixel *data = &timing->data.other_data;
 
-       if (edid->version == 1 && edid->revision < 3)
-               return 0;
-       if (!edid->extensions)
-               return 0;
+       if (data->type == EDID_DETAIL_CVT_3BYTE)
+               closure->modes += drm_cvt_modes(closure->connector, timing);
+}
 
-       /* Find CEA extension */
-       for (i = 0; i < edid->extensions; i++) {
-               edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
-               if (edid_ext[0] == 0x02)
-                       break;
-       }
+static int
+add_cvt_modes(struct drm_connector *connector, struct edid *edid)
+{      
+       struct detailed_mode_closure closure = {
+               connector, edid, 0, 0, 0
+       };
 
-       if (i == edid->extensions)
-               return 0;
+       if (version_greater(edid, 1, 2))
+               drm_for_each_detailed_block((u8 *)edid, do_cvt_mode, &closure);
 
-       /* Get the start offset of detailed timing block */
-       start_offset = edid_ext[2];
-       if (start_offset == 0) {
-               /* If the start_offset is zero, it means that neither detailed
-                * info nor data block exist. In such case it is also
-                * unnecessary to parse the detailed timing info.
-                */
-               return 0;
-       }
+       /* XXX should also look for CVT codes in VTB blocks */
 
-       end_offset = EDID_LENGTH;
-       end_offset -= sizeof(struct detailed_timing);
-       for (i = start_offset; i < end_offset;
-                       i += sizeof(struct detailed_timing)) {
-               timing = (struct detailed_timing *)(edid_ext + i);
-               modes += add_detailed_modes(connector, timing, edid, quirks, 0);
+       return closure.modes;
+}
+
+static void
+do_detailed_mode(struct detailed_timing *timing, void *c)
+{
+       struct detailed_mode_closure *closure = c;
+       struct drm_display_mode *newmode;
+
+       if (timing->pixel_clock) {
+               newmode = drm_mode_detailed(closure->connector->dev,
+                                           closure->edid, timing,
+                                           closure->quirks);
+               if (!newmode)
+                       return;
+
+               if (closure->preferred)
+                       newmode->type |= DRM_MODE_TYPE_PREFERRED;
+
+               drm_mode_probed_add(closure->connector, newmode);
+               closure->modes++;
+               closure->preferred = 0;
        }
+}
 
-       return modes;
+/*
+ * add_detailed_modes - Add modes from detailed timings
+ * @connector: attached connector
+ * @edid: EDID block to scan
+ * @quirks: quirks to apply
+ */
+static int
+add_detailed_modes(struct drm_connector *connector, struct edid *edid,
+                  u32 quirks)
+{
+       struct detailed_mode_closure closure = {
+               connector,
+               edid,
+               1,
+               quirks,
+               0
+       };
+
+       if (closure.preferred && !version_greater(edid, 1, 3))
+               closure.preferred =
+                   (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
+
+       drm_for_each_detailed_block((u8 *)edid, do_detailed_mode, &closure);
+
+       return closure.modes;
 }
 
 #define HDMI_IDENTIFIER 0x000C03
@@ -1640,35 +1360,21 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
         * - established timing codes
         * - modes inferred from GTF or CVT range information
         *
-        * We don't quite implement this yet, but we're close.
+        * We get this pretty much right.
         *
         * XXX order for additional mode types in extension blocks?
         */
-       num_modes += add_detailed_info(connector, edid, quirks);
-       num_modes += add_detailed_info_eedid(connector, edid, quirks);
+       num_modes += add_detailed_modes(connector, edid, quirks);
+       num_modes += add_cvt_modes(connector, edid);
        num_modes += add_standard_modes(connector, edid);
        num_modes += add_established_modes(connector, edid);
+       num_modes += add_inferred_modes(connector, edid);
 
        if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
                edid_fixup_preferred(connector, quirks);
 
-       connector->display_info.serration_vsync = (edid->input & DRM_EDID_INPUT_SERRATION_VSYNC) ? 1 : 0;
-       connector->display_info.sync_on_green = (edid->input & DRM_EDID_INPUT_SYNC_ON_GREEN) ? 1 : 0;
-       connector->display_info.composite_sync = (edid->input & DRM_EDID_INPUT_COMPOSITE_SYNC) ? 1 : 0;
-       connector->display_info.separate_syncs = (edid->input & DRM_EDID_INPUT_SEPARATE_SYNCS) ? 1 : 0;
-       connector->display_info.blank_to_black = (edid->input & DRM_EDID_INPUT_BLANK_TO_BLACK) ? 1 : 0;
-       connector->display_info.video_level = (edid->input & DRM_EDID_INPUT_VIDEO_LEVEL) >> 5;
-       connector->display_info.digital = (edid->input & DRM_EDID_INPUT_DIGITAL) ? 1 : 0;
        connector->display_info.width_mm = edid->width_cm * 10;
        connector->display_info.height_mm = edid->height_cm * 10;
-       connector->display_info.gamma = edid->gamma;
-       connector->display_info.gtf_supported = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) ? 1 : 0;
-       connector->display_info.standard_color = (edid->features & DRM_EDID_FEATURE_STANDARD_COLOR) ? 1 : 0;
-       connector->display_info.display_type = (edid->features & DRM_EDID_FEATURE_DISPLAY_TYPE) >> 3;
-       connector->display_info.active_off_supported = (edid->features & DRM_EDID_FEATURE_PM_ACTIVE_OFF) ? 1 : 0;
-       connector->display_info.suspend_supported = (edid->features & DRM_EDID_FEATURE_PM_SUSPEND) ? 1 : 0;
-       connector->display_info.standby_supported = (edid->features & DRM_EDID_FEATURE_PM_STANDBY) ? 1 : 0;
-       connector->display_info.gamma = edid->gamma;
 
        return num_modes;
 }
diff --git a/drivers/gpu/drm/drm_edid_modes.h b/drivers/gpu/drm/drm_edid_modes.h
new file mode 100644 (file)
index 0000000..6eb7592
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2007-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include "drmP.h"
+#include "drm_edid.h"
+
+/*
+ * Autogenerated from the DMT spec.
+ * This table is copied from xfree86/modes/xf86EdidModes.c.
+ * But the mode with Reduced blank feature is deleted.
+ */
+static struct drm_display_mode drm_dmt_modes[] = {
+       /* 640x350@85Hz */
+       { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
+                  736, 832, 0, 350, 382, 385, 445, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 640x400@85Hz */
+       { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
+                  736, 832, 0, 400, 401, 404, 445, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 720x400@85Hz */
+       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 756,
+                  828, 936, 0, 400, 401, 404, 446, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 640x480@60Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
+                  752, 800, 0, 480, 489, 492, 525, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 640x480@72Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
+                  704, 832, 0, 480, 489, 492, 520, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 640x480@75Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
+                  720, 840, 0, 480, 481, 484, 500, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 640x480@85Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 36000, 640, 696,
+                  752, 832, 0, 480, 481, 484, 509, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 800x600@56Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
+                  896, 1024, 0, 600, 601, 603, 625, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 800x600@60Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
+                  968, 1056, 0, 600, 601, 605, 628, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 800x600@72Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
+                  976, 1040, 0, 600, 637, 643, 666, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 800x600@75Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
+                  896, 1056, 0, 600, 601, 604, 625, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 800x600@85Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832,
+                  896, 1048, 0, 600, 601, 604, 631, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 848x480@60Hz */
+       { DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864,
+                  976, 1088, 0, 480, 486, 494, 517, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1024x768@43Hz, interlace */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032,
+                  1208, 1264, 0, 768, 768, 772, 817, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
+                       DRM_MODE_FLAG_INTERLACE) },
+       /* 1024x768@60Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
+                  1184, 1344, 0, 768, 771, 777, 806, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1024x768@70Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
+                  1184, 1328, 0, 768, 771, 777, 806, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1024x768@75Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040,
+                  1136, 1312, 0, 768, 769, 772, 800, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1024x768@85Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
+                  1168, 1376, 0, 768, 769, 772, 808, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1152x864@75Hz */
+       { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
+                  1344, 1600, 0, 864, 865, 868, 900, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x768@60Hz */
+       { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
+                  1472, 1664, 0, 768, 771, 778, 798, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x768@75Hz */
+       { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 102250, 1280, 1360,
+                  1488, 1696, 0, 768, 771, 778, 805, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1280x768@85Hz */
+       { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360,
+                  1496, 1712, 0, 768, 771, 778, 809, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x800@60Hz */
+       { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
+                  1480, 1680, 0, 800, 803, 809, 831, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1280x800@75Hz */
+       { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 106500, 1280, 1360,
+                  1488, 1696, 0, 800, 803, 809, 838, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x800@85Hz */
+       { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360,
+                  1496, 1712, 0, 800, 803, 809, 843, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x960@60Hz */
+       { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
+                  1488, 1800, 0, 960, 961, 964, 1000, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x960@85Hz */
+       { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344,
+                  1504, 1728, 0, 960, 961, 964, 1011, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x1024@60Hz */
+       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
+                  1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x1024@75Hz */
+       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
+                  1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x1024@85Hz */
+       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344,
+                  1504, 1728, 0, 1024, 1025, 1028, 1072, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1360x768@60Hz */
+       { DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
+                  1536, 1792, 0, 768, 771, 777, 795, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1440x1050@60Hz */
+       { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
+                  1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1440x1050@75Hz */
+       { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504,
+                  1648, 1896, 0, 1050, 1053, 1057, 1099, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1440x1050@85Hz */
+       { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504,
+                  1656, 1912, 0, 1050, 1053, 1057, 1105, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1440x900@60Hz */
+       { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
+                  1672, 1904, 0, 900, 903, 909, 934, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1440x900@75Hz */
+       { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 136750, 1440, 1536,
+                  1688, 1936, 0, 900, 903, 909, 942, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1440x900@85Hz */
+       { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544,
+                  1696, 1952, 0, 900, 903, 909, 948, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1600x1200@60Hz */
+       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
+                  1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1600x1200@65Hz */
+       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 175500, 1600, 1664,
+                  1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1600x1200@70Hz */
+       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 189000, 1600, 1664,
+                  1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1600x1200@75Hz */
+       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 202500, 1600, 1664,
+                  1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1600x1200@85Hz */
+       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664,
+                  1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1680x1050@60Hz */
+       { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
+                  1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1680x1050@75Hz */
+       { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 187000, 1680, 1800,
+                  1976, 2272, 0, 1050, 1053, 1059, 1099, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1680x1050@85Hz */
+       { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808,
+                  1984, 2288, 0, 1050, 1053, 1059, 1105, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1792x1344@60Hz */
+       { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
+                  2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1729x1344@75Hz */
+       { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888,
+                  2104, 2456, 0, 1344, 1345, 1348, 1417, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1853x1392@60Hz */
+       { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
+                  2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1856x1392@75Hz */
+       { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984,
+                  2208, 2560, 0, 1392, 1395, 1399, 1500, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1920x1200@60Hz */
+       { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
+                  2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1920x1200@75Hz */
+       { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 245250, 1920, 2056,
+                  2264, 2608, 0, 1200, 1203, 1209, 1255, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1920x1200@85Hz */
+       { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064,
+                  2272, 2624, 0, 1200, 1203, 1209, 1262, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1920x1440@60Hz */
+       { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048,
+                  2256, 2600, 0, 1440, 1441, 1444, 1500, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1920x1440@75Hz */
+       { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064,
+                  2288, 2640, 0, 1440, 1441, 1444, 1500, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 2560x1600@60Hz */
+       { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
+                  3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 2560x1600@75HZ */
+       { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 443250, 2560, 2768,
+                  3048, 3536, 0, 1600, 1603, 1609, 1672, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 2560x1600@85HZ */
+       { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768,
+                  3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+};
+static const int drm_num_dmt_modes =
+       sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
+
+static struct drm_display_mode edid_est_modes[] = {
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
+                  968, 1056, 0, 600, 601, 605, 628, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
+                  896, 1024, 0, 600, 601, 603,  625, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
+                  720, 840, 0, 480, 481, 484, 500, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
+                  704,  832, 0, 480, 489, 491, 520, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
+                  768,  864, 0, 480, 483, 486, 525, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
+                  752, 800, 0, 480, 490, 492, 525, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */
+       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
+                  846, 900, 0, 400, 421, 423,  449, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */
+       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
+                  846,  900, 0, 400, 412, 414, 449, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */
+       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
+                  1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
+                  1136, 1312, 0,  768, 769, 772, 800, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
+                  1184, 1328, 0,  768, 771, 777, 806, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
+                  1184, 1344, 0,  768, 771, 777, 806, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
+                  1208, 1264, 0, 768, 768, 776, 817, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
+       { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
+                  928, 1152, 0, 624, 625, 628, 667, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
+                  896, 1056, 0, 600, 601, 604,  625, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
+                  976, 1040, 0, 600, 637, 643, 666, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */
+       { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
+                  1344, 1600, 0,  864, 865, 868, 900, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
+};
+
+static const struct {
+       short w;
+       short h;
+       short r;
+       short rb;
+} est3_modes[] = {
+       /* byte 6 */
+       { 640, 350, 85, 0 },
+       { 640, 400, 85, 0 },
+       { 720, 400, 85, 0 },
+       { 640, 480, 85, 0 },
+       { 848, 480, 60, 0 },
+       { 800, 600, 85, 0 },
+       { 1024, 768, 85, 0 },
+       { 1152, 864, 75, 0 },
+       /* byte 7 */
+       { 1280, 768, 60, 1 },
+       { 1280, 768, 60, 0 },
+       { 1280, 768, 75, 0 },
+       { 1280, 768, 85, 0 },
+       { 1280, 960, 60, 0 },
+       { 1280, 960, 85, 0 },
+       { 1280, 1024, 60, 0 },
+       { 1280, 1024, 85, 0 },
+       /* byte 8 */
+       { 1360, 768, 60, 0 },
+       { 1440, 900, 60, 1 },
+       { 1440, 900, 60, 0 },
+       { 1440, 900, 75, 0 },
+       { 1440, 900, 85, 0 },
+       { 1400, 1050, 60, 1 },
+       { 1400, 1050, 60, 0 },
+       { 1400, 1050, 75, 0 },
+       /* byte 9 */
+       { 1400, 1050, 85, 0 },
+       { 1680, 1050, 60, 1 },
+       { 1680, 1050, 60, 0 },
+       { 1680, 1050, 75, 0 },
+       { 1680, 1050, 85, 0 },
+       { 1600, 1200, 60, 0 },
+       { 1600, 1200, 65, 0 },
+       { 1600, 1200, 70, 0 },
+       /* byte 10 */
+       { 1600, 1200, 75, 0 },
+       { 1600, 1200, 85, 0 },
+       { 1792, 1344, 60, 0 },
+       { 1792, 1344, 85, 0 },
+       { 1856, 1392, 60, 0 },
+       { 1856, 1392, 75, 0 },
+       { 1920, 1200, 60, 1 },
+       { 1920, 1200, 60, 0 },
+       /* byte 11 */
+       { 1920, 1200, 75, 0 },
+       { 1920, 1200, 85, 0 },
+       { 1920, 1440, 60, 0 },
+       { 1920, 1440, 75, 0 },
+};
+static const int num_est3_modes = sizeof(est3_modes) / sizeof(est3_modes[0]);
index 2ca8df8..3a652a6 100644 (file)
@@ -135,15 +135,9 @@ int drm_open(struct inode *inode, struct file *filp)
        retcode = drm_open_helper(inode, filp, dev);
        if (!retcode) {
                atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
-               spin_lock(&dev->count_lock);
-               if (!dev->open_count++) {
-                       spin_unlock(&dev->count_lock);
+               if (!dev->open_count++)
                        retcode = drm_setup(dev);
-                       goto out;
-               }
-               spin_unlock(&dev->count_lock);
        }
-out:
        if (!retcode) {
                mutex_lock(&dev->struct_mutex);
                if (minor->type == DRM_MINOR_LEGACY) {
@@ -570,18 +564,14 @@ int drm_release(struct inode *inode, struct file *filp)
         */
 
        atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
-       spin_lock(&dev->count_lock);
        if (!--dev->open_count) {
                if (atomic_read(&dev->ioctl_count)) {
                        DRM_ERROR("Device busy: %d\n",
                                  atomic_read(&dev->ioctl_count));
                        retcode = -EBUSY;
-                       goto out;
-               }
-               retcode = drm_lastclose(dev);
+               } else
+                       retcode = drm_lastclose(dev);
        }
-out:
-       spin_unlock(&dev->count_lock);
        mutex_unlock(&drm_global_mutex);
 
        return retcode;
index 4f1b867..bf92d07 100644 (file)
@@ -322,7 +322,7 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL)
-               return -EBADF;
+               return -ENOENT;
 
 again:
        if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) {
index 7b03b19..47db4df 100644 (file)
@@ -392,6 +392,7 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri
                if (sv->drm_di_minor >= 1) {
                        /*
                         * Version 1.1 includes tying of DRM to specific device
+                        * Version 1.4 has proper PCI domain support
                         */
                        retcode = drm_set_busid(dev, file_priv);
                        if (retcode)
index 833b35f..08792a7 100644 (file)
@@ -470,6 +470,7 @@ static int ch7006_encoder_init(struct i2c_client *client,
        priv->hmargin = 50;
        priv->vmargin = 50;
        priv->last_dpms = -1;
+       priv->chip_version = ch7006_read(client, CH7006_VERSION_ID);
 
        if (ch7006_tv_norm) {
                for (i = 0; i < NUM_TV_NORMS; i++) {
index e447dfb..c860f24 100644 (file)
@@ -316,7 +316,10 @@ void ch7006_setup_power_state(struct drm_encoder *encoder)
                }
 
        } else {
-               *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF);
+               if (priv->chip_version >= 0x20)
+                       *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF);
+               else
+                       *power |= bitfs(CH7006_POWER_LEVEL, POWER_OFF);
        }
 }
 
index 1c6d2e3..17667b7 100644 (file)
@@ -95,6 +95,7 @@ struct ch7006_priv {
        int flicker;
        int scale;
 
+       int chip_version;
        int last_dpms;
 };
 
index 2a4ed7c..0758c78 100644 (file)
@@ -456,7 +456,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL)
-               return -EBADF;
+               return -ENOENT;
        obj_priv = to_intel_bo(obj);
 
        /* Bounds check source.
@@ -919,7 +919,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL)
-               return -EBADF;
+               return -ENOENT;
        obj_priv = to_intel_bo(obj);
 
        /* Bounds check destination.
@@ -1002,7 +1002,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL)
-               return -EBADF;
+               return -ENOENT;
        obj_priv = to_intel_bo(obj);
 
        mutex_lock(&dev->struct_mutex);
@@ -1060,7 +1060,7 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL) {
                mutex_unlock(&dev->struct_mutex);
-               return -EBADF;
+               return -ENOENT;
        }
 
 #if WATCH_BUF
@@ -1099,7 +1099,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL)
-               return -EBADF;
+               return -ENOENT;
 
        offset = args->offset;
 
@@ -1373,7 +1373,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL)
-               return -EBADF;
+               return -ENOENT;
 
        mutex_lock(&dev->struct_mutex);
 
@@ -3364,7 +3364,7 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
                                                   reloc->target_handle);
                if (target_obj == NULL) {
                        i915_gem_object_unpin(obj);
-                       return -EBADF;
+                       return -ENOENT;
                }
                target_obj_priv = to_intel_bo(target_obj);
 
@@ -3781,7 +3781,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                                   exec_list[i].handle, i);
                        /* prevent error path from reading uninitialized data */
                        args->buffer_count = i + 1;
-                       ret = -EBADF;
+                       ret = -ENOENT;
                        goto err;
                }
 
@@ -3791,7 +3791,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                                   object_list[i]);
                        /* prevent error path from reading uninitialized data */
                        args->buffer_count = i + 1;
-                       ret = -EBADF;
+                       ret = -EINVAL;
                        goto err;
                }
                obj_priv->in_execbuffer = true;
@@ -4265,7 +4265,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
                DRM_ERROR("Bad handle in i915_gem_pin_ioctl(): %d\n",
                          args->handle);
                mutex_unlock(&dev->struct_mutex);
-               return -EBADF;
+               return -ENOENT;
        }
        obj_priv = to_intel_bo(obj);
 
@@ -4321,7 +4321,7 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
                DRM_ERROR("Bad handle in i915_gem_unpin_ioctl(): %d\n",
                          args->handle);
                mutex_unlock(&dev->struct_mutex);
-               return -EBADF;
+               return -ENOENT;
        }
 
        obj_priv = to_intel_bo(obj);
@@ -4355,7 +4355,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
        if (obj == NULL) {
                DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n",
                          args->handle);
-               return -EBADF;
+               return -ENOENT;
        }
 
        mutex_lock(&dev->struct_mutex);
@@ -4408,7 +4408,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
        if (obj == NULL) {
                DRM_ERROR("Bad handle in i915_gem_madvise_ioctl(): %d\n",
                          args->handle);
-               return -EBADF;
+               return -ENOENT;
        }
 
        mutex_lock(&dev->struct_mutex);
index 155719e..710eca7 100644 (file)
@@ -275,7 +275,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL)
-               return -EINVAL;
+               return -ENOENT;
        obj_priv = to_intel_bo(obj);
 
        if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) {
@@ -362,7 +362,7 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL)
-               return -EINVAL;
+               return -ENOENT;
        obj_priv = to_intel_bo(obj);
 
        mutex_lock(&dev->struct_mutex);
index 1e5e0d3..5ec10e0 100644 (file)
@@ -4429,15 +4429,12 @@ void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
 }
 
 static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
-                                u16 *blue, uint32_t size)
+                                u16 *blue, uint32_t start, uint32_t size)
 {
+       int end = (start + size > 256) ? 256 : start + size, i;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int i;
-
-       if (size != 256)
-               return;
 
-       for (i = 0; i < 256; i++) {
+       for (i = start; i < end; i++) {
                intel_crtc->lut_r[i] = red[i] >> 8;
                intel_crtc->lut_g[i] = green[i] >> 8;
                intel_crtc->lut_b[i] = blue[i] >> 8;
@@ -5412,18 +5409,18 @@ intel_user_framebuffer_create(struct drm_device *dev,
 
        obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle);
        if (!obj)
-               return NULL;
+               return ERR_PTR(-ENOENT);
 
        intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
        if (!intel_fb)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        ret = intel_framebuffer_init(dev, intel_fb,
                                     mode_cmd, obj);
        if (ret) {
                drm_gem_object_unreference_unlocked(obj);
                kfree(intel_fb);
-               return NULL;
+               return ERR_PTR(ret);
        }
 
        return &intel_fb->base;
index a79525f..7bdc962 100644 (file)
@@ -121,7 +121,9 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
 
        info->par = ifbdev;
 
-       intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo);
+       ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo);
+       if (ret)
+               goto out_unpin;
 
        fb = &ifbdev->ifb.base;
 
index 2405d5e..e9b06e4 100644 (file)
@@ -12,12 +12,12 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
              nouveau_dp.o \
              nv04_timer.o \
              nv04_mc.o nv40_mc.o nv50_mc.o \
-             nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o \
-             nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
+             nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \
+             nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \
              nv04_graph.o nv10_graph.o nv20_graph.o \
-             nv40_graph.o nv50_graph.o \
+             nv40_graph.o nv50_graph.o nvc0_graph.o \
              nv40_grctx.o nv50_grctx.o \
-             nv04_instmem.o nv50_instmem.o \
+             nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
              nv50_crtc.o nv50_dac.o nv50_sor.o \
              nv50_cursor.o nv50_display.o nv50_fbcon.o \
              nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
index 7369b5e..0b69a96 100644 (file)
@@ -1928,6 +1928,31 @@ init_condition_time(struct nvbios *bios, uint16_t offset,
 }
 
 static int
+init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+{
+       /*
+        * INIT_LTIME   opcode: 0x57 ('V')
+        *
+        * offset      (8  bit): opcode
+        * offset + 1  (16 bit): time
+        *
+        * Sleep for "time" miliseconds.
+        */
+
+       unsigned time = ROM16(bios->data[offset + 1]);
+
+       if (!iexec->execute)
+               return 3;
+
+       BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X miliseconds\n",
+               offset, time);
+
+       msleep(time);
+
+       return 3;
+}
+
+static int
 init_zm_reg_sequence(struct nvbios *bios, uint16_t offset,
                     struct init_exec *iexec)
 {
@@ -1995,6 +2020,64 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 }
 
 static int
+init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+{
+       /*
+        * INIT_I2C_IF   opcode: 0x5E ('^')
+        *
+        * offset      (8 bit): opcode
+        * offset + 1  (8 bit): DCB I2C table entry index
+        * offset + 2  (8 bit): I2C slave address
+        * offset + 3  (8 bit): I2C register
+        * offset + 4  (8 bit): mask
+        * offset + 5  (8 bit): data
+        *
+        * Read the register given by "I2C register" on the device addressed
+        * by "I2C slave address" on the I2C bus given by "DCB I2C table
+        * entry index". Compare the result AND "mask" to "data".
+        * If they're not equal, skip subsequent opcodes until condition is
+        * inverted (INIT_NOT), or we hit INIT_RESUME
+        */
+
+       uint8_t i2c_index = bios->data[offset + 1];
+       uint8_t i2c_address = bios->data[offset + 2] >> 1;
+       uint8_t reg = bios->data[offset + 3];
+       uint8_t mask = bios->data[offset + 4];
+       uint8_t data = bios->data[offset + 5];
+       struct nouveau_i2c_chan *chan;
+       union i2c_smbus_data val;
+       int ret;
+
+       /* no execute check by design */
+
+       BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n",
+               offset, i2c_index, i2c_address);
+
+       chan = init_i2c_device_find(bios->dev, i2c_index);
+       if (!chan)
+               return -ENODEV;
+
+       ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
+                            I2C_SMBUS_READ, reg,
+                            I2C_SMBUS_BYTE_DATA, &val);
+       if (ret < 0) {
+               BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: [no device], "
+                             "Mask: 0x%02X, Data: 0x%02X\n",
+                       offset, reg, mask, data);
+               iexec->execute = 0;
+               return 6;
+       }
+
+       BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, "
+                     "Mask: 0x%02X, Data: 0x%02X\n",
+               offset, reg, val.byte, mask, data);
+
+       iexec->execute = ((val.byte & mask) == data);
+
+       return 6;
+}
+
+static int
 init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2083,9 +2166,10 @@ peek_fb(struct drm_device *dev, struct io_mapping *fb,
        uint32_t val = 0;
 
        if (off < pci_resource_len(dev->pdev, 1)) {
-               uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0);
+               uint32_t __iomem *p =
+                       io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
 
-               val = ioread32(p);
+               val = ioread32(p + (off & ~PAGE_MASK));
 
                io_mapping_unmap_atomic(p, KM_USER0);
        }
@@ -2098,9 +2182,10 @@ poke_fb(struct drm_device *dev, struct io_mapping *fb,
        uint32_t off, uint32_t val)
 {
        if (off < pci_resource_len(dev->pdev, 1)) {
-               uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0);
+               uint32_t __iomem *p =
+                       io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
 
-               iowrite32(val, p);
+               iowrite32(val, p + (off & ~PAGE_MASK));
                wmb();
 
                io_mapping_unmap_atomic(p, KM_USER0);
@@ -2165,7 +2250,7 @@ nv04_init_compute_mem(struct nvbios *bios)
                          NV04_PFB_BOOT_0_RAM_AMOUNT,
                          NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
 
-       } else if (peek_fb(dev, fb, 0) == patt) {
+       } else if (peek_fb(dev, fb, 0) != patt) {
                if (read_back_fb(dev, fb, 0x800000, patt))
                        bios_md32(bios, NV04_PFB_BOOT_0,
                                  NV04_PFB_BOOT_0_RAM_AMOUNT,
@@ -2593,7 +2678,7 @@ init_configure_preinit(struct nvbios *bios, uint16_t offset,
        /* no iexec->execute check by design */
 
        uint32_t straps = bios_rd32(bios, NV_PEXTDEV_BOOT_0);
-       uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6));
+       uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & 0x40) >> 6;
 
        if (bios->major_version > 2)
                return 0;
@@ -3140,7 +3225,7 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
        int i;
 
-       if (dev_priv->card_type != NV_50) {
+       if (dev_priv->card_type < NV_50) {
                NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n");
                return 1;
        }
@@ -3490,6 +3575,69 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        return len;
 }
 
+static int
+init_i2c_long_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+{
+       /*
+        * INIT_I2C_LONG_IF   opcode: 0x9A ('')
+        *
+        * offset      (8 bit): opcode
+        * offset + 1  (8 bit): DCB I2C table entry index
+        * offset + 2  (8 bit): I2C slave address
+        * offset + 3  (16 bit): I2C register
+        * offset + 5  (8 bit): mask
+        * offset + 6  (8 bit): data
+        *
+        * Read the register given by "I2C register" on the device addressed
+        * by "I2C slave address" on the I2C bus given by "DCB I2C table
+        * entry index". Compare the result AND "mask" to "data".
+        * If they're not equal, skip subsequent opcodes until condition is
+        * inverted (INIT_NOT), or we hit INIT_RESUME
+        */
+
+       uint8_t i2c_index = bios->data[offset + 1];
+       uint8_t i2c_address = bios->data[offset + 2] >> 1;
+       uint8_t reglo = bios->data[offset + 3];
+       uint8_t reghi = bios->data[offset + 4];
+       uint8_t mask = bios->data[offset + 5];
+       uint8_t data = bios->data[offset + 6];
+       struct nouveau_i2c_chan *chan;
+       uint8_t buf0[2] = { reghi, reglo };
+       uint8_t buf1[1];
+       struct i2c_msg msg[2] = {
+               { i2c_address, 0, 1, buf0 },
+               { i2c_address, I2C_M_RD, 1, buf1 },
+       };
+       int ret;
+
+       /* no execute check by design */
+
+       BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n",
+               offset, i2c_index, i2c_address);
+
+       chan = init_i2c_device_find(bios->dev, i2c_index);
+       if (!chan)
+               return -ENODEV;
+
+
+       ret = i2c_transfer(&chan->adapter, msg, 2);
+       if (ret < 0) {
+               BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: [no device], "
+                             "Mask: 0x%02X, Data: 0x%02X\n",
+                       offset, reghi, reglo, mask, data);
+               iexec->execute = 0;
+               return 7;
+       }
+
+       BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: 0x%02X, "
+                     "Mask: 0x%02X, Data: 0x%02X\n",
+               offset, reghi, reglo, buf1[0], mask, data);
+
+       iexec->execute = ((buf1[0] & mask) == data);
+
+       return 7;
+}
+
 static struct init_tbl_entry itbl_entry[] = {
        /* command name                       , id  , length  , offset  , mult    , command handler                 */
        /* INIT_PROG (0x31, 15, 10, 4) removed due to no example of use */
@@ -3516,9 +3664,11 @@ static struct init_tbl_entry itbl_entry[] = {
        { "INIT_ZM_CR"                        , 0x53, init_zm_cr                      },
        { "INIT_ZM_CR_GROUP"                  , 0x54, init_zm_cr_group                },
        { "INIT_CONDITION_TIME"               , 0x56, init_condition_time             },
+       { "INIT_LTIME"                        , 0x57, init_ltime                      },
        { "INIT_ZM_REG_SEQUENCE"              , 0x58, init_zm_reg_sequence            },
        /* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */
        { "INIT_SUB_DIRECT"                   , 0x5B, init_sub_direct                 },
+       { "INIT_I2C_IF"                       , 0x5E, init_i2c_if                     },
        { "INIT_COPY_NV_REG"                  , 0x5F, init_copy_nv_reg                },
        { "INIT_ZM_INDEX_IO"                  , 0x62, init_zm_index_io                },
        { "INIT_COMPUTE_MEM"                  , 0x63, init_compute_mem                },
@@ -3552,6 +3702,7 @@ static struct init_tbl_entry itbl_entry[] = {
        { "INIT_97"                           , 0x97, init_97                         },
        { "INIT_AUXCH"                        , 0x98, init_auxch                      },
        { "INIT_ZM_AUXCH"                     , 0x99, init_zm_auxch                   },
+       { "INIT_I2C_LONG_IF"                  , 0x9A, init_i2c_long_if                },
        { NULL                                , 0   , NULL                            }
 };
 
@@ -4410,7 +4561,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
                                          bios->display.script_table_ptr,
                                          table[2], table[3], table[0] >= 0x21);
        if (!otable) {
-               NV_ERROR(dev, "Couldn't find matching output script table\n");
+               NV_DEBUG_KMS(dev, "failed to match any output table\n");
                return 1;
        }
 
@@ -4467,7 +4618,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
                if (script)
                        script = clkcmptable(bios, script, pxclk);
                if (!script) {
-                       NV_ERROR(dev, "clock script 0 not found\n");
+                       NV_DEBUG_KMS(dev, "clock script 0 not found\n");
                        return 1;
                }
 
@@ -4826,7 +4977,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
                pll_lim->min_p = record[12];
                pll_lim->max_p = record[13];
                /* where did this go to?? */
-               if (limit_match == 0x00614100 || limit_match == 0x00614900)
+               if ((entry[0] & 0xf0) == 0x80)
                        pll_lim->refclk = 27000;
                else
                        pll_lim->refclk = 100000;
@@ -5852,7 +6003,7 @@ static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads)
        entry->i2c_index = i2c;
        entry->heads = heads;
        entry->location = DCB_LOC_ON_CHIP;
-       /* "or" mostly unused in early gen crt modesetting, 0 is fine */
+       entry->or = 1;
 }
 
 static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads)
@@ -5980,7 +6131,13 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
                }
                break;
        case OUTPUT_TMDS:
-               entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4;
+               if (dcb->version >= 0x40)
+                       entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4;
+               else if (dcb->version >= 0x30)
+                       entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8;
+               else if (dcb->version >= 0x22)
+                       entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4;
+
                break;
        case 0xe:
                /* weird g80 mobile type that "nv" treats as a terminator */
@@ -6270,6 +6427,19 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
                dcb->i2c_table = &bios->data[i2ctabptr];
                if (dcb->version >= 0x30)
                        dcb->i2c_default_indices = dcb->i2c_table[4];
+
+               /*
+                * Parse the "management" I2C bus, used for hardware
+                * monitoring and some external TMDS transmitters.
+                */
+               if (dcb->version >= 0x22) {
+                       int idx = (dcb->version >= 0x40 ?
+                                  dcb->i2c_default_indices & 0xf :
+                                  2);
+
+                       read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
+                                          idx, &dcb->i2c[idx]);
+               }
        }
 
        if (entries > DCB_MAX_NUM_ENTRIES)
index 024458a..fd14dfd 100644 (file)
@@ -131,6 +131,7 @@ struct dcb_entry {
                } dpconf;
                struct {
                        struct sor_conf sor;
+                       int slave_addr;
                } tmdsconf;
        };
        bool i2c_upper_default;
index 3ca8343..84f8518 100644 (file)
@@ -51,9 +51,6 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *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);
 }
 
@@ -166,9 +163,6 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
        }
        nvbo->channel = NULL;
 
-       spin_lock(&dev_priv->ttm.bo_list_lock);
-       list_add_tail(&nvbo->head, &dev_priv->ttm.bo_list);
-       spin_unlock(&dev_priv->ttm.bo_list_lock);
        *pnvbo = nvbo;
        return 0;
 }
index 734e926..b1b22ba 100644 (file)
 #include "nouveau_connector.h"
 #include "nouveau_hw.h"
 
-static inline struct drm_encoder_slave_funcs *
-get_slave_funcs(struct nouveau_encoder *enc)
-{
-       return to_encoder_slave(to_drm_encoder(enc))->slave_funcs;
-}
-
 static struct nouveau_encoder *
 find_encoder_by_type(struct drm_connector *connector, int type)
 {
@@ -360,6 +354,7 @@ nouveau_connector_set_property(struct drm_connector *connector,
 {
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
+       struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
        struct drm_device *dev = connector->dev;
        int ret;
 
@@ -432,8 +427,8 @@ nouveau_connector_set_property(struct drm_connector *connector,
        }
 
        if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV)
-               return get_slave_funcs(nv_encoder)->
-                       set_property(to_drm_encoder(nv_encoder), connector, property, value);
+               return get_slave_funcs(encoder)->set_property(
+                       encoder, connector, property, value);
 
        return -EINVAL;
 }
@@ -545,6 +540,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
+       struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
        int ret = 0;
 
        /* destroy the native mode, the attached monitor could have changed.
@@ -580,8 +576,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
        }
 
        if (nv_encoder->dcb->type == OUTPUT_TV)
-               ret = get_slave_funcs(nv_encoder)->
-                       get_modes(to_drm_encoder(nv_encoder), connector);
+               ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
 
        if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||
            nv_connector->dcb->type == DCB_CONNECTOR_eDP)
@@ -597,6 +592,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
        struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
+       struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
        unsigned min_clock = 25000, max_clock = min_clock;
        unsigned clock = mode->clock;
 
@@ -623,8 +619,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
                        max_clock = 350000;
                break;
        case OUTPUT_TV:
-               return get_slave_funcs(nv_encoder)->
-                       mode_valid(to_drm_encoder(nv_encoder), mode);
+               return get_slave_funcs(encoder)->mode_valid(encoder, mode);
        case OUTPUT_DP:
                if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7)
                        max_clock = nv_encoder->dp.link_nr * 270000;
index 74e6b4e..2e11fd6 100644 (file)
@@ -84,16 +84,16 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
 
        gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
        if (!gem)
-               return NULL;
+               return ERR_PTR(-ENOENT);
 
        nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
        if (!nouveau_fb)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
        if (ret) {
                drm_gem_object_unreference(gem);
-               return NULL;
+               return ERR_PTR(ret);
        }
 
        return &nouveau_fb->base;
index 33742b1..8a1b188 100644 (file)
@@ -572,47 +572,64 @@ out:
        return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY);
 }
 
-int
-nouveau_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
-                     uint8_t write_byte, uint8_t *read_byte)
+static int
+nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 {
-       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
-       struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adapter;
+       struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap;
        struct drm_device *dev = auxch->dev;
-       int ret = 0, cmd, addr = algo_data->address;
-       uint8_t *buf;
-
-       if (mode == MODE_I2C_READ) {
-               cmd = AUX_I2C_READ;
-               buf = read_byte;
-       } else {
-               cmd = (mode & MODE_I2C_READ) ? AUX_I2C_READ : AUX_I2C_WRITE;
-               buf = &write_byte;
-       }
+       struct i2c_msg *msg = msgs;
+       int ret, mcnt = num;
 
-       if (!(mode & MODE_I2C_STOP))
-               cmd |= AUX_I2C_MOT;
+       while (mcnt--) {
+               u8 remaining = msg->len;
+               u8 *ptr = msg->buf;
 
-       if (mode & MODE_I2C_START)
-               return 1;
+               while (remaining) {
+                       u8 cnt = (remaining > 16) ? 16 : remaining;
+                       u8 cmd;
 
-       for (;;) {
-               ret = nouveau_dp_auxch(auxch, cmd, addr, buf, 1);
-               if (ret < 0)
-                       return ret;
-
-               switch (ret & NV50_AUXCH_STAT_REPLY_I2C) {
-               case NV50_AUXCH_STAT_REPLY_I2C_ACK:
-                       return 1;
-               case NV50_AUXCH_STAT_REPLY_I2C_NACK:
-                       return -EREMOTEIO;
-               case NV50_AUXCH_STAT_REPLY_I2C_DEFER:
-                       udelay(100);
-                       break;
-               default:
-                       NV_ERROR(dev, "invalid auxch status: 0x%08x\n", ret);
-                       return -EREMOTEIO;
+                       if (msg->flags & I2C_M_RD)
+                               cmd = AUX_I2C_READ;
+                       else
+                               cmd = AUX_I2C_WRITE;
+
+                       if (mcnt || remaining > 16)
+                               cmd |= AUX_I2C_MOT;
+
+                       ret = nouveau_dp_auxch(auxch, cmd, msg->addr, ptr, cnt);
+                       if (ret < 0)
+                               return ret;
+
+                       switch (ret & NV50_AUXCH_STAT_REPLY_I2C) {
+                       case NV50_AUXCH_STAT_REPLY_I2C_ACK:
+                               break;
+                       case NV50_AUXCH_STAT_REPLY_I2C_NACK:
+                               return -EREMOTEIO;
+                       case NV50_AUXCH_STAT_REPLY_I2C_DEFER:
+                               udelay(100);
+                               continue;
+                       default:
+                               NV_ERROR(dev, "bad auxch reply: 0x%08x\n", ret);
+                               return -EREMOTEIO;
+                       }
+
+                       ptr += cnt;
+                       remaining -= cnt;
                }
+
+               msg++;
        }
+
+       return num;
+}
+
+static u32
+nouveau_dp_i2c_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
 }
 
+const struct i2c_algorithm nouveau_dp_i2c_algo = {
+       .master_xfer = nouveau_dp_i2c_xfer,
+       .functionality = nouveau_dp_i2c_func
+};
index e15db15..e424bf7 100644 (file)
@@ -410,7 +410,7 @@ enum nv04_fp_display_regs {
 
 struct nv04_crtc_reg {
        unsigned char MiscOutReg;     /* */
-       uint8_t CRTC[0x9f];
+       uint8_t CRTC[0xa0];
        uint8_t CR58[0x10];
        uint8_t Sequencer[5];
        uint8_t Graphics[9];
@@ -509,6 +509,7 @@ enum nouveau_card_type {
        NV_30      = 0x30,
        NV_40      = 0x40,
        NV_50      = 0x50,
+       NV_C0      = 0xc0,
 };
 
 struct drm_nouveau_private {
@@ -536,8 +537,6 @@ struct drm_nouveau_private {
                struct drm_global_reference mem_global_ref;
                struct ttm_bo_global_ref bo_global_ref;
                struct ttm_bo_device bdev;
-               spinlock_t bo_list_lock;
-               struct list_head bo_list;
                atomic_t validate_sequence;
        } ttm;
 
@@ -931,6 +930,10 @@ extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t,
 extern int  nv50_fb_init(struct drm_device *);
 extern void nv50_fb_takedown(struct drm_device *);
 
+/* nvc0_fb.c */
+extern int  nvc0_fb_init(struct drm_device *);
+extern void nvc0_fb_takedown(struct drm_device *);
+
 /* nv04_fifo.c */
 extern int  nv04_fifo_init(struct drm_device *);
 extern void nv04_fifo_disable(struct drm_device *);
@@ -968,6 +971,20 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *);
 extern int  nv50_fifo_load_context(struct nouveau_channel *);
 extern int  nv50_fifo_unload_context(struct drm_device *);
 
+/* nvc0_fifo.c */
+extern int  nvc0_fifo_init(struct drm_device *);
+extern void nvc0_fifo_takedown(struct drm_device *);
+extern void nvc0_fifo_disable(struct drm_device *);
+extern void nvc0_fifo_enable(struct drm_device *);
+extern bool nvc0_fifo_reassign(struct drm_device *, bool);
+extern bool nvc0_fifo_cache_flush(struct drm_device *);
+extern bool nvc0_fifo_cache_pull(struct drm_device *, bool);
+extern int  nvc0_fifo_channel_id(struct drm_device *);
+extern int  nvc0_fifo_create_context(struct nouveau_channel *);
+extern void nvc0_fifo_destroy_context(struct nouveau_channel *);
+extern int  nvc0_fifo_load_context(struct nouveau_channel *);
+extern int  nvc0_fifo_unload_context(struct drm_device *);
+
 /* nv04_graph.c */
 extern struct nouveau_pgraph_object_class nv04_graph_grclass[];
 extern int  nv04_graph_init(struct drm_device *);
@@ -1032,6 +1049,16 @@ extern int  nv50_graph_unload_context(struct drm_device *);
 extern void nv50_graph_context_switch(struct drm_device *);
 extern int  nv50_grctx_init(struct nouveau_grctx *);
 
+/* nvc0_graph.c */
+extern int  nvc0_graph_init(struct drm_device *);
+extern void nvc0_graph_takedown(struct drm_device *);
+extern void nvc0_graph_fifo_access(struct drm_device *, bool);
+extern struct nouveau_channel *nvc0_graph_channel(struct drm_device *);
+extern int  nvc0_graph_create_context(struct nouveau_channel *);
+extern void nvc0_graph_destroy_context(struct nouveau_channel *);
+extern int  nvc0_graph_load_context(struct nouveau_channel *);
+extern int  nvc0_graph_unload_context(struct drm_device *);
+
 /* nv04_instmem.c */
 extern int  nv04_instmem_init(struct drm_device *);
 extern void nv04_instmem_takedown(struct drm_device *);
@@ -1058,6 +1085,18 @@ extern void nv50_instmem_flush(struct drm_device *);
 extern void nv84_instmem_flush(struct drm_device *);
 extern void nv50_vm_flush(struct drm_device *, int engine);
 
+/* nvc0_instmem.c */
+extern int  nvc0_instmem_init(struct drm_device *);
+extern void nvc0_instmem_takedown(struct drm_device *);
+extern int  nvc0_instmem_suspend(struct drm_device *);
+extern void nvc0_instmem_resume(struct drm_device *);
+extern int  nvc0_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
+                                 uint32_t *size);
+extern void nvc0_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
+extern int  nvc0_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
+extern int  nvc0_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
+extern void nvc0_instmem_flush(struct drm_device *);
+
 /* nv04_mc.c */
 extern int  nv04_mc_init(struct drm_device *);
 extern void nv04_mc_takedown(struct drm_device *);
index a1a0d48..7c82d68 100644 (file)
@@ -71,6 +71,12 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc)
        return &enc->base.base;
 }
 
+static inline struct drm_encoder_slave_funcs *
+get_slave_funcs(struct drm_encoder *enc)
+{
+       return to_encoder_slave(enc)->slave_funcs;
+}
+
 struct nouveau_connector *
 nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
 int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
index 099f637..dbd30b2 100644 (file)
@@ -281,6 +281,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
 
        if (dev_priv->channel && !nouveau_nofbaccel) {
                switch (dev_priv->card_type) {
+               case NV_C0:
+                       break;
                case NV_50:
                        nv50_fbcon_accel_init(info);
                        info->fbops = &nv50_fbcon_ops;
index 547f2c2..0f417ac 100644 (file)
@@ -284,7 +284,7 @@ retry:
                if (!gem) {
                        NV_ERROR(dev, "Unknown handle 0x%08x\n", b->handle);
                        validate_fini(op, NULL);
-                       return -EINVAL;
+                       return -ENOENT;
                }
                nvbo = gem->driver_private;
 
@@ -759,7 +759,7 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
 
        gem = drm_gem_object_lookup(dev, file_priv, req->handle);
        if (!gem)
-               return ret;
+               return -ENOENT;
        nvbo = nouveau_gem_object(gem);
 
        if (nvbo->cpu_filp) {
@@ -797,7 +797,7 @@ nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data,
 
        gem = drm_gem_object_lookup(dev, file_priv, req->handle);
        if (!gem)
-               return ret;
+               return -ENOENT;
        nvbo = nouveau_gem_object(gem);
 
        if (nvbo->cpu_filp != file_priv)
@@ -822,7 +822,7 @@ nouveau_gem_ioctl_info(struct drm_device *dev, void *data,
 
        gem = drm_gem_object_lookup(dev, file_priv, req->handle);
        if (!gem)
-               return -EINVAL;
+               return -ENOENT;
 
        ret = nouveau_gem_info(gem, req);
        drm_gem_object_unreference_unlocked(gem);
index 7855b35..7b61368 100644 (file)
@@ -865,8 +865,12 @@ nv_save_state_ext(struct drm_device *dev, int head,
        rd_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
        rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
        rd_cio_state(dev, head, regp, NV_CIO_CRE_21);
-       if (dev_priv->card_type >= NV_30)
+
+       if (dev_priv->card_type >= NV_30) {
                rd_cio_state(dev, head, regp, NV_CIO_CRE_47);
+               rd_cio_state(dev, head, regp, 0x9f);
+       }
+
        rd_cio_state(dev, head, regp, NV_CIO_CRE_49);
        rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
        rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX);
@@ -971,8 +975,11 @@ nv_load_state_ext(struct drm_device *dev, int head,
        wr_cio_state(dev, head, regp, NV_CIO_CRE_ENH_INDEX);
        wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
        wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
-       if (dev_priv->card_type >= NV_30)
+
+       if (dev_priv->card_type >= NV_30) {
                wr_cio_state(dev, head, regp, NV_CIO_CRE_47);
+               wr_cio_state(dev, head, regp, 0x9f);
+       }
 
        wr_cio_state(dev, head, regp, NV_CIO_CRE_49);
        wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
index cb0cb34..0bd407c 100644 (file)
@@ -163,7 +163,7 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
        if (entry->chan)
                return -EEXIST;
 
-       if (dev_priv->card_type == NV_50 && entry->read >= NV50_I2C_PORTS) {
+       if (dev_priv->card_type == NV_C0 && entry->read >= NV50_I2C_PORTS) {
                NV_ERROR(dev, "unknown i2c port %d\n", entry->read);
                return -EINVAL;
        }
@@ -174,26 +174,26 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
 
        switch (entry->port_type) {
        case 0:
-               i2c->algo.bit.setsda = nv04_i2c_setsda;
-               i2c->algo.bit.setscl = nv04_i2c_setscl;
-               i2c->algo.bit.getsda = nv04_i2c_getsda;
-               i2c->algo.bit.getscl = nv04_i2c_getscl;
+               i2c->bit.setsda = nv04_i2c_setsda;
+               i2c->bit.setscl = nv04_i2c_setscl;
+               i2c->bit.getsda = nv04_i2c_getsda;
+               i2c->bit.getscl = nv04_i2c_getscl;
                i2c->rd = entry->read;
                i2c->wr = entry->write;
                break;
        case 4:
-               i2c->algo.bit.setsda = nv4e_i2c_setsda;
-               i2c->algo.bit.setscl = nv4e_i2c_setscl;
-               i2c->algo.bit.getsda = nv4e_i2c_getsda;
-               i2c->algo.bit.getscl = nv4e_i2c_getscl;
+               i2c->bit.setsda = nv4e_i2c_setsda;
+               i2c->bit.setscl = nv4e_i2c_setscl;
+               i2c->bit.getsda = nv4e_i2c_getsda;
+               i2c->bit.getscl = nv4e_i2c_getscl;
                i2c->rd = 0x600800 + entry->read;
                i2c->wr = 0x600800 + entry->write;
                break;
        case 5:
-               i2c->algo.bit.setsda = nv50_i2c_setsda;
-               i2c->algo.bit.setscl = nv50_i2c_setscl;
-               i2c->algo.bit.getsda = nv50_i2c_getsda;
-               i2c->algo.bit.getscl = nv50_i2c_getscl;
+               i2c->bit.setsda = nv50_i2c_setsda;
+               i2c->bit.setscl = nv50_i2c_setscl;
+               i2c->bit.getsda = nv50_i2c_getsda;
+               i2c->bit.getscl = nv50_i2c_getscl;
                i2c->rd = nv50_i2c_port[entry->read];
                i2c->wr = i2c->rd;
                break;
@@ -216,17 +216,14 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
        i2c_set_adapdata(&i2c->adapter, i2c);
 
        if (entry->port_type < 6) {
-               i2c->adapter.algo_data = &i2c->algo.bit;
-               i2c->algo.bit.udelay = 40;
-               i2c->algo.bit.timeout = usecs_to_jiffies(5000);
-               i2c->algo.bit.data = i2c;
+               i2c->adapter.algo_data = &i2c->bit;
+               i2c->bit.udelay = 40;
+               i2c->bit.timeout = usecs_to_jiffies(5000);
+               i2c->bit.data = i2c;
                ret = i2c_bit_add_bus(&i2c->adapter);
        } else {
-               i2c->adapter.algo_data = &i2c->algo.dp;
-               i2c->algo.dp.running = false;
-               i2c->algo.dp.address = 0;
-               i2c->algo.dp.aux_ch = nouveau_dp_i2c_aux_ch;
-               ret = i2c_dp_aux_add_bus(&i2c->adapter);
+               i2c->adapter.algo = &nouveau_dp_i2c_algo;
+               ret = i2c_add_adapter(&i2c->adapter);
        }
 
        if (ret) {
index 6dd2f87..f71cb32 100644 (file)
@@ -33,10 +33,7 @@ struct dcb_i2c_entry;
 struct nouveau_i2c_chan {
        struct i2c_adapter adapter;
        struct drm_device *dev;
-       union {
-               struct i2c_algo_bit_data bit;
-               struct i2c_algo_dp_aux_data dp;
-       } algo;
+       struct i2c_algo_bit_data bit;
        unsigned rd;
        unsigned wr;
        unsigned data;
@@ -49,7 +46,6 @@ bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
 int nouveau_i2c_identify(struct drm_device *dev, const char *what,
                         struct i2c_board_info *info, int index);
 
-int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte,
-                         uint8_t *read_byte);
+extern const struct i2c_algorithm nouveau_dp_i2c_algo;
 
 #endif /* __NOUVEAU_I2C_H__ */
index 53360f1..794b0ee 100644 (file)
@@ -49,7 +49,7 @@ nouveau_irq_preinstall(struct drm_device *dev)
        /* Master disable */
        nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
 
-       if (dev_priv->card_type == NV_50) {
+       if (dev_priv->card_type >= NV_50) {
                INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
                INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh);
                INIT_LIST_HEAD(&dev_priv->vbl_waiting);
@@ -586,11 +586,11 @@ nouveau_pgraph_irq_handler(struct drm_device *dev)
                }
 
                if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
-                       nouveau_pgraph_intr_context_switch(dev);
-
                        status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
                        nv_wr32(dev, NV03_PGRAPH_INTR,
                                 NV_PGRAPH_INTR_CONTEXT_SWITCH);
+
+                       nouveau_pgraph_intr_context_switch(dev);
                }
 
                if (status) {
index a9f36ab..9689d41 100644 (file)
@@ -320,7 +320,8 @@ nouveau_mem_detect(struct drm_device *dev)
        if (dev_priv->card_type < NV_50) {
                dev_priv->vram_size  = nv_rd32(dev, NV04_PFB_FIFO_DATA);
                dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK;
-       } else {
+       } else
+       if (dev_priv->card_type < NV_C0) {
                dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA);
                dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32;
                dev_priv->vram_size &= 0xffffffff00ll;
@@ -328,6 +329,9 @@ nouveau_mem_detect(struct drm_device *dev)
                        dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10);
                        dev_priv->vram_sys_base <<= 12;
                }
+       } else {
+               dev_priv->vram_size  = nv_rd32(dev, 0x10f20c) << 20;
+               dev_priv->vram_size *= nv_rd32(dev, 0x121c74);
        }
 
        NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
@@ -351,7 +355,7 @@ nouveau_mem_reset_agp(struct drm_device *dev)
        /* First of all, disable fast writes, otherwise if it's
         * already enabled in the AGP bridge and we disable the card's
         * AGP controller we might be locking ourselves out of it. */
-       if (dev->agp->acquired) {
+       if (nv_rd32(dev, NV04_PBUS_PCI_NV_19) & PCI_AGP_COMMAND_FW) {
                struct drm_agp_info info;
                struct drm_agp_mode mode;
 
@@ -359,7 +363,7 @@ nouveau_mem_reset_agp(struct drm_device *dev)
                if (ret)
                        return ret;
 
-               mode.mode = info.mode & ~0x10;
+               mode.mode = info.mode & ~PCI_AGP_COMMAND_FW;
                ret = drm_agp_enable(dev, mode);
                if (ret)
                        return ret;
@@ -405,6 +409,8 @@ nouveau_mem_init_agp(struct drm_device *dev)
                }
        }
 
+       nouveau_mem_reset_agp(dev);
+
        ret = drm_agp_info(dev, &info);
        if (ret) {
                NV_ERROR(dev, "Unable to get AGP info: %d\n", ret);
@@ -459,8 +465,6 @@ nouveau_mem_init(struct drm_device *dev)
                return ret;
        }
 
-       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 = dev_priv->vram_size;
@@ -494,7 +498,6 @@ nouveau_mem_init(struct drm_device *dev)
        /* GART */
 #if !defined(__powerpc__) && !defined(__ia64__)
        if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) {
-               nouveau_mem_reset_agp(dev);
                ret = nouveau_mem_init_agp(dev);
                if (ret)
                        NV_ERROR(dev, "Error initialising AGP: %d\n", ret);
index 9c1056c..21a6e45 100644 (file)
 #    define NV_PGRAPH_INTR_ERROR                              (1<<20)
 #define NV10_PGRAPH_CTX_CONTROL                            0x00400144
 #define NV10_PGRAPH_CTX_USER                               0x00400148
-#define NV10_PGRAPH_CTX_SWITCH1                            0x0040014C
-#define NV10_PGRAPH_CTX_SWITCH2                            0x00400150
-#define NV10_PGRAPH_CTX_SWITCH3                            0x00400154
-#define NV10_PGRAPH_CTX_SWITCH4                            0x00400158
-#define NV10_PGRAPH_CTX_SWITCH5                            0x0040015C
+#define NV10_PGRAPH_CTX_SWITCH(i)                         (0x0040014C + 0x4*(i))
 #define NV04_PGRAPH_CTX_SWITCH1                            0x00400160
-#define NV10_PGRAPH_CTX_CACHE1                             0x00400160
+#define NV10_PGRAPH_CTX_CACHE(i, j)                       (0x00400160  \
+                                                          + 0x4*(i) + 0x20*(j))
 #define NV04_PGRAPH_CTX_SWITCH2                            0x00400164
 #define NV04_PGRAPH_CTX_SWITCH3                            0x00400168
 #define NV04_PGRAPH_CTX_SWITCH4                            0x0040016C
 #define NV04_PGRAPH_CTX_CONTROL                            0x00400170
 #define NV04_PGRAPH_CTX_USER                               0x00400174
 #define NV04_PGRAPH_CTX_CACHE1                             0x00400180
-#define NV10_PGRAPH_CTX_CACHE2                             0x00400180
 #define NV03_PGRAPH_CTX_CONTROL                            0x00400190
 #define NV03_PGRAPH_CTX_USER                               0x00400194
 #define NV04_PGRAPH_CTX_CACHE2                             0x004001A0
-#define NV10_PGRAPH_CTX_CACHE3                             0x004001A0
 #define NV04_PGRAPH_CTX_CACHE3                             0x004001C0
-#define NV10_PGRAPH_CTX_CACHE4                             0x004001C0
 #define NV04_PGRAPH_CTX_CACHE4                             0x004001E0
-#define NV10_PGRAPH_CTX_CACHE5                             0x004001E0
 #define NV40_PGRAPH_CTXCTL_0304                            0x00400304
 #define NV40_PGRAPH_CTXCTL_0304_XFER_CTX                   0x00000001
 #define NV40_PGRAPH_CTXCTL_UCODE_STAT                      0x00400308
 #define NV04_PGRAPH_FFINTFC_ST2                            0x00400754
 #define NV10_PGRAPH_RDI_DATA                               0x00400754
 #define NV04_PGRAPH_DMA_PITCH                              0x00400760
-#define NV10_PGRAPH_FFINTFC_ST2                            0x00400764
+#define NV10_PGRAPH_FFINTFC_FIFO_PTR                       0x00400760
 #define NV04_PGRAPH_DVD_COLORFMT                           0x00400764
+#define NV10_PGRAPH_FFINTFC_ST2                            0x00400764
 #define NV04_PGRAPH_SCALED_FORMAT                          0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DL                         0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DH                         0x0040076c
 #define NV10_PGRAPH_DMA_PITCH                              0x00400770
 #define NV10_PGRAPH_DVD_COLORFMT                           0x00400774
 #define NV10_PGRAPH_SCALED_FORMAT                          0x00400778
index ee3729e..989322b 100644 (file)
@@ -359,6 +359,54 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->gpio.set                = nv50_gpio_set;
                engine->gpio.irq_enable         = nv50_gpio_irq_enable;
                break;
+       case 0xC0:
+               engine->instmem.init            = nvc0_instmem_init;
+               engine->instmem.takedown        = nvc0_instmem_takedown;
+               engine->instmem.suspend         = nvc0_instmem_suspend;
+               engine->instmem.resume          = nvc0_instmem_resume;
+               engine->instmem.populate        = nvc0_instmem_populate;
+               engine->instmem.clear           = nvc0_instmem_clear;
+               engine->instmem.bind            = nvc0_instmem_bind;
+               engine->instmem.unbind          = nvc0_instmem_unbind;
+               engine->instmem.flush           = nvc0_instmem_flush;
+               engine->mc.init                 = nv50_mc_init;
+               engine->mc.takedown             = nv50_mc_takedown;
+               engine->timer.init              = nv04_timer_init;
+               engine->timer.read              = nv04_timer_read;
+               engine->timer.takedown          = nv04_timer_takedown;
+               engine->fb.init                 = nvc0_fb_init;
+               engine->fb.takedown             = nvc0_fb_takedown;
+               engine->graph.grclass           = NULL;  //nvc0_graph_grclass;
+               engine->graph.init              = nvc0_graph_init;
+               engine->graph.takedown          = nvc0_graph_takedown;
+               engine->graph.fifo_access       = nvc0_graph_fifo_access;
+               engine->graph.channel           = nvc0_graph_channel;
+               engine->graph.create_context    = nvc0_graph_create_context;
+               engine->graph.destroy_context   = nvc0_graph_destroy_context;
+               engine->graph.load_context      = nvc0_graph_load_context;
+               engine->graph.unload_context    = nvc0_graph_unload_context;
+               engine->fifo.channels           = 128;
+               engine->fifo.init               = nvc0_fifo_init;
+               engine->fifo.takedown           = nvc0_fifo_takedown;
+               engine->fifo.disable            = nvc0_fifo_disable;
+               engine->fifo.enable             = nvc0_fifo_enable;
+               engine->fifo.reassign           = nvc0_fifo_reassign;
+               engine->fifo.channel_id         = nvc0_fifo_channel_id;
+               engine->fifo.create_context     = nvc0_fifo_create_context;
+               engine->fifo.destroy_context    = nvc0_fifo_destroy_context;
+               engine->fifo.load_context       = nvc0_fifo_load_context;
+               engine->fifo.unload_context     = nvc0_fifo_unload_context;
+               engine->display.early_init      = nv50_display_early_init;
+               engine->display.late_takedown   = nv50_display_late_takedown;
+               engine->display.create          = nv50_display_create;
+               engine->display.init            = nv50_display_init;
+               engine->display.destroy         = nv50_display_destroy;
+               engine->gpio.init               = nv50_gpio_init;
+               engine->gpio.takedown           = nouveau_stub_takedown;
+               engine->gpio.get                = nv50_gpio_get;
+               engine->gpio.set                = nv50_gpio_set;
+               engine->gpio.irq_enable         = nv50_gpio_irq_enable;
+               break;
        default:
                NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);
                return 1;
@@ -739,8 +787,10 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
        int ret;
 
        dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
-       if (!dev_priv)
-               return -ENOMEM;
+       if (!dev_priv) {
+               ret = -ENOMEM;
+               goto err_out;
+       }
        dev->dev_private = dev_priv;
        dev_priv->dev = dev;
 
@@ -750,8 +800,10 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
                 dev->pci_vendor, dev->pci_device, dev->pdev->class);
 
        dev_priv->wq = create_workqueue("nouveau");
-       if (!dev_priv->wq)
-               return -EINVAL;
+       if (!dev_priv->wq) {
+               ret = -EINVAL;
+               goto err_priv;
+       }
 
        /* resource 0 is mmio regs */
        /* resource 1 is linear FB */
@@ -764,7 +816,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
        if (!dev_priv->mmio) {
                NV_ERROR(dev, "Unable to initialize the mmio mapping. "
                         "Please report your setup to " DRIVER_EMAIL "\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_wq;
        }
        NV_DEBUG(dev, "regs mapped ok at 0x%llx\n",
                                        (unsigned long long)mmio_start_offs);
@@ -810,9 +863,13 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
        case 0xa0:
                dev_priv->card_type = NV_50;
                break;
+       case 0xc0:
+               dev_priv->card_type = NV_C0;
+               break;
        default:
                NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_mmio;
        }
 
        NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
@@ -820,7 +877,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
 
        ret = nouveau_remove_conflicting_drivers(dev);
        if (ret)
-               return ret;
+               goto err_mmio;
 
        /* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */
        if (dev_priv->card_type >= NV_40) {
@@ -834,7 +891,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
                                dev_priv->ramin_size);
                if (!dev_priv->ramin) {
                        NV_ERROR(dev, "Failed to PRAMIN BAR");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto err_mmio;
                }
        } else {
                dev_priv->ramin_size = 1 * 1024 * 1024;
@@ -842,7 +900,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
                                          dev_priv->ramin_size);
                if (!dev_priv->ramin) {
                        NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto err_mmio;
                }
        }
 
@@ -857,9 +916,21 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
        /* For kernel modesetting, init card now and bring up fbcon */
        ret = nouveau_card_init(dev);
        if (ret)
-               return ret;
+               goto err_ramin;
 
        return 0;
+
+err_ramin:
+       iounmap(dev_priv->ramin);
+err_mmio:
+       iounmap(dev_priv->mmio);
+err_wq:
+       destroy_workqueue(dev_priv->wq);
+err_priv:
+       kfree(dev_priv);
+       dev->dev_private = NULL;
+err_out:
+       return ret;
 }
 
 void nouveau_lastclose(struct drm_device *dev)
index 1c20c08..497df87 100644 (file)
@@ -542,6 +542,9 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
         * 1 << 30 on 0x60.830), for no apparent reason */
        regp->CRTC[NV_CIO_CRE_59] = off_chip_digital;
 
+       if (dev_priv->card_type >= NV_30)
+               regp->CRTC[0x9f] = off_chip_digital ? 0x11 : 0x1;
+
        regp->crtc_830 = mode->crtc_vdisplay - 3;
        regp->crtc_834 = mode->crtc_vdisplay - 1;
 
@@ -739,15 +742,13 @@ nv_crtc_gamma_load(struct drm_crtc *crtc)
 }
 
 static void
-nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t size)
+nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
+                 uint32_t size)
 {
+       int end = (start + size > 256) ? 256 : start + size, i;
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-       int i;
 
-       if (size != 256)
-               return;
-
-       for (i = 0; i < 256; i++) {
+       for (i = start; i < end; i++) {
                nv_crtc->lut.r[i] = r[i];
                nv_crtc->lut.g[i] = g[i];
                nv_crtc->lut.b[i] = b[i];
@@ -914,7 +915,7 @@ nv04_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
 
        gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
        if (!gem)
-               return -EINVAL;
+               return -ENOENT;
        cursor = nouveau_gem_object(gem);
 
        ret = nouveau_bo_map(cursor);
index 3311f3a..a5dcf76 100644 (file)
@@ -34,6 +34,8 @@
 #include "nouveau_hw.h"
 #include "nvreg.h"
 
+#include "i2c/sil164.h"
+
 #define FP_TG_CONTROL_ON  (NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS |       \
                           NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS |         \
                           NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS)
@@ -144,6 +146,36 @@ void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode)
        }
 }
 
+static struct drm_encoder *get_tmds_slave(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+       struct drm_encoder *slave;
+
+       if (dcb->type != OUTPUT_TMDS || dcb->location == DCB_LOC_ON_CHIP)
+               return NULL;
+
+       /* Some BIOSes (e.g. the one in a Quadro FX1000) report several
+        * TMDS transmitters at the same I2C address, in the same I2C
+        * bus. This can still work because in that case one of them is
+        * always hard-wired to a reasonable configuration using straps,
+        * and the other one needs to be programmed.
+        *
+        * I don't think there's a way to know which is which, even the
+        * blob programs the one exposed via I2C for *both* heads, so
+        * let's do the same.
+        */
+       list_for_each_entry(slave, &dev->mode_config.encoder_list, head) {
+               struct dcb_entry *slave_dcb = nouveau_encoder(slave)->dcb;
+
+               if (slave_dcb->type == OUTPUT_TMDS && get_slave_funcs(slave) &&
+                   slave_dcb->tmdsconf.slave_addr == dcb->tmdsconf.slave_addr)
+                       return slave;
+       }
+
+       return NULL;
+}
+
 static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder,
                                struct drm_display_mode *mode,
                                struct drm_display_mode *adjusted_mode)
@@ -429,6 +461,11 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
        else
                NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000);
 
+       /* Init external transmitters */
+       if (get_tmds_slave(encoder))
+               get_slave_funcs(get_tmds_slave(encoder))->mode_set(
+                       encoder, &nv_encoder->mode, &nv_encoder->mode);
+
        helper->dpms(encoder, DRM_MODE_DPMS_ON);
 
        NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
@@ -550,10 +587,42 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder)
 
        NV_DEBUG_KMS(encoder->dev, "\n");
 
+       if (get_slave_funcs(encoder))
+               get_slave_funcs(encoder)->destroy(encoder);
+
        drm_encoder_cleanup(encoder);
        kfree(nv_encoder);
 }
 
+static void nv04_tmds_slave_init(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+       struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, 2);
+       struct i2c_board_info info[] = {
+               {
+                       .type = "sil164",
+                       .addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38),
+                       .platform_data = &(struct sil164_encoder_params) {
+                               SIL164_INPUT_EDGE_RISING
+                       }
+               },
+               { }
+       };
+       int type;
+
+       if (!nv_gf4_disp_arch(dev) || !i2c ||
+           get_tmds_slave(encoder))
+               return;
+
+       type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2);
+       if (type < 0)
+               return;
+
+       drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
+                            &i2c->adapter, &info[type]);
+}
+
 static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = {
        .dpms = nv04_lvds_dpms,
        .save = nv04_dfp_save,
@@ -616,6 +685,10 @@ nv04_dfp_create(struct drm_connector *connector, struct dcb_entry *entry)
        encoder->possible_crtcs = entry->heads;
        encoder->possible_clones = 0;
 
+       if (entry->type == OUTPUT_TMDS &&
+           entry->location != DCB_LOC_ON_CHIP)
+               nv04_tmds_slave_init(encoder);
+
        drm_mode_connector_attach_encoder(connector, encoder);
        return 0;
 }
index 94e299c..0b5d012 100644 (file)
@@ -89,7 +89,7 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode)
 
        NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel);
 
-       to_encoder_slave(encoder)->slave_funcs->dpms(encoder, mode);
+       get_slave_funcs(encoder)->dpms(encoder, mode);
 }
 
 static void nv04_tv_bind(struct drm_device *dev, int head, bool bind)
@@ -152,7 +152,7 @@ static void nv04_tv_mode_set(struct drm_encoder *encoder,
        regp->tv_vskew = 1;
        regp->tv_vsync_delay = 1;
 
-       to_encoder_slave(encoder)->slave_funcs->mode_set(encoder, mode, adjusted_mode);
+       get_slave_funcs(encoder)->mode_set(encoder, mode, adjusted_mode);
 }
 
 static void nv04_tv_commit(struct drm_encoder *encoder)
@@ -171,8 +171,7 @@ static void nv04_tv_commit(struct drm_encoder *encoder)
 
 static void nv04_tv_destroy(struct drm_encoder *encoder)
 {
-       to_encoder_slave(encoder)->slave_funcs->destroy(encoder);
-
+       get_slave_funcs(encoder)->destroy(encoder);
        drm_encoder_cleanup(encoder);
 
        kfree(encoder->helper_private);
@@ -229,7 +228,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
                goto fail_cleanup;
 
        /* Fill the function pointers */
-       sfuncs = to_encoder_slave(encoder)->slave_funcs;
+       sfuncs = get_slave_funcs(encoder);
 
        *hfuncs = (struct drm_encoder_helper_funcs) {
                .dpms = nv04_tv_dpms,
@@ -243,7 +242,6 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
        };
 
        /* Attach it to the specified connector. */
-       sfuncs->set_config(encoder, nv04_tv_encoder_info[type].platform_data);
        sfuncs->create_resources(encoder, connector);
        drm_mode_connector_attach_encoder(connector, encoder);
 
index fcf2cdd..b2f6a57 100644 (file)
@@ -43,51 +43,51 @@ struct pipe_state {
 };
 
 static int nv10_graph_ctx_regs[] = {
-       NV10_PGRAPH_CTX_SWITCH1,
-       NV10_PGRAPH_CTX_SWITCH2,
-       NV10_PGRAPH_CTX_SWITCH3,
-       NV10_PGRAPH_CTX_SWITCH4,
-       NV10_PGRAPH_CTX_SWITCH5,
-       NV10_PGRAPH_CTX_CACHE1, /* 8 values from 0x400160 to 0x40017c */
-       NV10_PGRAPH_CTX_CACHE2, /* 8 values from 0x400180 to 0x40019c */
-       NV10_PGRAPH_CTX_CACHE3, /* 8 values from 0x4001a0 to 0x4001bc */
-       NV10_PGRAPH_CTX_CACHE4, /* 8 values from 0x4001c0 to 0x4001dc */
-       NV10_PGRAPH_CTX_CACHE5, /* 8 values from 0x4001e0 to 0x4001fc */
-       0x00400164,
-       0x00400184,
-       0x004001a4,
-       0x004001c4,
-       0x004001e4,
-       0x00400168,
-       0x00400188,
-       0x004001a8,
-       0x004001c8,
-       0x004001e8,
-       0x0040016c,
-       0x0040018c,
-       0x004001ac,
-       0x004001cc,
-       0x004001ec,
-       0x00400170,
-       0x00400190,
-       0x004001b0,
-       0x004001d0,
-       0x004001f0,
-       0x00400174,
-       0x00400194,
-       0x004001b4,
-       0x004001d4,
-       0x004001f4,
-       0x00400178,
-       0x00400198,
-       0x004001b8,
-       0x004001d8,
-       0x004001f8,
-       0x0040017c,
-       0x0040019c,
-       0x004001bc,
-       0x004001dc,
-       0x004001fc,
+       NV10_PGRAPH_CTX_SWITCH(0),
+       NV10_PGRAPH_CTX_SWITCH(1),
+       NV10_PGRAPH_CTX_SWITCH(2),
+       NV10_PGRAPH_CTX_SWITCH(3),
+       NV10_PGRAPH_CTX_SWITCH(4),
+       NV10_PGRAPH_CTX_CACHE(0, 0),
+       NV10_PGRAPH_CTX_CACHE(0, 1),
+       NV10_PGRAPH_CTX_CACHE(0, 2),
+       NV10_PGRAPH_CTX_CACHE(0, 3),
+       NV10_PGRAPH_CTX_CACHE(0, 4),
+       NV10_PGRAPH_CTX_CACHE(1, 0),
+       NV10_PGRAPH_CTX_CACHE(1, 1),
+       NV10_PGRAPH_CTX_CACHE(1, 2),
+       NV10_PGRAPH_CTX_CACHE(1, 3),
+       NV10_PGRAPH_CTX_CACHE(1, 4),
+       NV10_PGRAPH_CTX_CACHE(2, 0),
+       NV10_PGRAPH_CTX_CACHE(2, 1),
+       NV10_PGRAPH_CTX_CACHE(2, 2),
+       NV10_PGRAPH_CTX_CACHE(2, 3),
+       NV10_PGRAPH_CTX_CACHE(2, 4),
+       NV10_PGRAPH_CTX_CACHE(3, 0),
+       NV10_PGRAPH_CTX_CACHE(3, 1),
+       NV10_PGRAPH_CTX_CACHE(3, 2),
+       NV10_PGRAPH_CTX_CACHE(3, 3),
+       NV10_PGRAPH_CTX_CACHE(3, 4),
+       NV10_PGRAPH_CTX_CACHE(4, 0),
+       NV10_PGRAPH_CTX_CACHE(4, 1),
+       NV10_PGRAPH_CTX_CACHE(4, 2),
+       NV10_PGRAPH_CTX_CACHE(4, 3),
+       NV10_PGRAPH_CTX_CACHE(4, 4),
+       NV10_PGRAPH_CTX_CACHE(5, 0),
+       NV10_PGRAPH_CTX_CACHE(5, 1),
+       NV10_PGRAPH_CTX_CACHE(5, 2),
+       NV10_PGRAPH_CTX_CACHE(5, 3),
+       NV10_PGRAPH_CTX_CACHE(5, 4),
+       NV10_PGRAPH_CTX_CACHE(6, 0),
+       NV10_PGRAPH_CTX_CACHE(6, 1),
+       NV10_PGRAPH_CTX_CACHE(6, 2),
+       NV10_PGRAPH_CTX_CACHE(6, 3),
+       NV10_PGRAPH_CTX_CACHE(6, 4),
+       NV10_PGRAPH_CTX_CACHE(7, 0),
+       NV10_PGRAPH_CTX_CACHE(7, 1),
+       NV10_PGRAPH_CTX_CACHE(7, 2),
+       NV10_PGRAPH_CTX_CACHE(7, 3),
+       NV10_PGRAPH_CTX_CACHE(7, 4),
        NV10_PGRAPH_CTX_USER,
        NV04_PGRAPH_DMA_START_0,
        NV04_PGRAPH_DMA_START_1,
@@ -653,6 +653,78 @@ static int nv17_graph_ctx_regs_find_offset(struct drm_device *dev, int reg)
        return -1;
 }
 
+static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
+                                      uint32_t inst)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+       uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
+       uint32_t ctx_user, ctx_switch[5];
+       int i, subchan = -1;
+
+       /* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state
+        * that cannot be restored via MMIO. Do it through the FIFO
+        * instead.
+        */
+
+       /* Look for a celsius object */
+       for (i = 0; i < 8; i++) {
+               int class = nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
+
+               if (class == 0x56 || class == 0x96 || class == 0x99) {
+                       subchan = i;
+                       break;
+               }
+       }
+
+       if (subchan < 0 || !inst)
+               return;
+
+       /* Save the current ctx object */
+       ctx_user = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
+       for (i = 0; i < 5; i++)
+               ctx_switch[i] = nv_rd32(dev, NV10_PGRAPH_CTX_SWITCH(i));
+
+       /* Save the FIFO state */
+       st2 = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2);
+       st2_dl = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DL);
+       st2_dh = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DH);
+       fifo_ptr = nv_rd32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR);
+
+       for (i = 0; i < ARRAY_SIZE(fifo); i++)
+               fifo[i] = nv_rd32(dev, 0x4007a0 + 4 * i);
+
+       /* Switch to the celsius subchannel */
+       for (i = 0; i < 5; i++)
+               nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i),
+                       nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(subchan, i)));
+       nv_mask(dev, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
+
+       /* Inject NV10TCL_DMA_VTXBUF */
+       nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
+       nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2,
+               0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
+       nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
+       nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
+       pgraph->fifo_access(dev, true);
+       pgraph->fifo_access(dev, false);
+
+       /* Restore the FIFO state */
+       for (i = 0; i < ARRAY_SIZE(fifo); i++)
+               nv_wr32(dev, 0x4007a0 + 4 * i, fifo[i]);
+
+       nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
+       nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, st2);
+       nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
+       nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
+
+       /* Restore the current ctx object */
+       for (i = 0; i < 5; i++)
+               nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
+       nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user);
+}
+
 int nv10_graph_load_context(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
@@ -670,6 +742,8 @@ int nv10_graph_load_context(struct nouveau_channel *chan)
        }
 
        nv10_graph_load_pipe(chan);
+       nv10_graph_load_dma_vtxbuf(chan, (nv_rd32(dev, NV10_PGRAPH_GLOBALSTATE1)
+                                         & 0xffff));
 
        nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
        tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
@@ -856,11 +930,12 @@ int nv10_graph_init(struct drm_device *dev)
        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);
-       nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH3, 0x00000000);
-       nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH4, 0x00000000);
-       nv_wr32(dev, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
+       nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
+       nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
+       nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
+       nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
+       nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
+       nv_wr32(dev, NV10_PGRAPH_STATE, 0xFFFFFFFF);
 
        tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
        tmp |= (dev_priv->engine.fifo.channels - 1) << 24;
index 9d35c8b..4a3f2f0 100644 (file)
 #include "nouveau_drm.h"
 
 static int
-calc_ref(int b, int l, int i)
+calc_bias(struct drm_device *dev, int k, int i, int j)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       int b = (dev_priv->chipset > 0x30 ?
+                nv_rd32(dev, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) :
+                0) & 0xf;
+
+       return 2 * (b & 0x8 ? b - 0x10 : b);
+}
+
+static int
+calc_ref(struct drm_device *dev, int l, int k, int i)
 {
        int j, x = 0;
 
        for (j = 0; j < 4; j++) {
-               int n = (b >> (8 * j) & 0xf);
-               int m = (l >> (8 * i) & 0xff) + 2 * (n & 0x8 ? n - 0x10 : n);
+               int m = (l >> (8 * i) & 0xff) + calc_bias(dev, k, i, j);
 
-               x |= (0x80 | (m & 0x1f)) << (8 * j);
+               x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j);
        }
 
        return x;
@@ -63,18 +73,16 @@ nv30_fb_init(struct drm_device *dev)
            dev_priv->chipset == 0x35) {
                /* Related to ROP count */
                int n = (dev_priv->chipset == 0x31 ? 2 : 4);
-               int b = (dev_priv->chipset > 0x30 ?
-                        nv_rd32(dev, 0x122c) & 0xf : 0);
                int l = nv_rd32(dev, 0x1003d0);
 
                for (i = 0; i < n; i++) {
                        for (j = 0; j < 3; j++)
                                nv_wr32(dev, 0x10037c + 0xc * i + 0x4 * j,
-                                       calc_ref(b, l, j));
+                                       calc_ref(dev, l, 0, j));
 
                        for (j = 0; j < 2; j++)
                                nv_wr32(dev, 0x1003ac + 0x8 * i + 0x4 * j,
-                                       calc_ref(b, l, j));
+                                       calc_ref(dev, l, 1, j));
                }
        }
 
index 5d11ea1..bfd4ca2 100644 (file)
@@ -264,11 +264,16 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update)
 int
 nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
 {
-       uint32_t reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct pll_lims pll;
-       uint32_t reg1, reg2;
+       uint32_t reg, reg1, reg2;
        int ret, N1, M1, N2, M2, P;
 
+       if (dev_priv->chipset < NV_C0)
+               reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
+       else
+               reg = 0x614140 + (head * 0x800);
+
        ret = get_pll_limits(dev, reg, &pll);
        if (ret)
                return ret;
@@ -286,7 +291,8 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
                nv_wr32(dev, reg, 0x10000611);
                nv_wr32(dev, reg + 4, reg1 | (M1 << 16) | N1);
                nv_wr32(dev, reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
-       } else {
+       } else
+       if (dev_priv->chipset < NV_C0) {
                ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
                if (ret <= 0)
                        return 0;
@@ -298,6 +304,17 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
                nv_wr32(dev, reg, 0x50000610);
                nv_wr32(dev, reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
                nv_wr32(dev, reg + 8, N2);
+       } else {
+               ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
+               if (ret <= 0)
+                       return 0;
+
+               NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
+                        pclk, ret, N1, N2, M1, P);
+
+               nv_mask(dev, reg + 0x0c, 0x00000000, 0x00000100);
+               nv_wr32(dev, reg + 0x04, (P << 16) | (N1 << 8) | M1);
+               nv_wr32(dev, reg + 0x10, N2 << 16);
        }
 
        return 0;
@@ -348,7 +365,7 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
 
        gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
        if (!gem)
-               return -EINVAL;
+               return -ENOENT;
        cursor = nouveau_gem_object(gem);
 
        ret = nouveau_bo_map(cursor);
@@ -381,15 +398,12 @@ nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
 
 static void
 nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
-                   uint32_t size)
+                   uint32_t start, uint32_t size)
 {
+       int end = (start + size > 256) ? 256 : start + size, i;
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-       int i;
-
-       if (size != 256)
-               return;
 
-       for (i = 0; i < 256; i++) {
+       for (i = start; i < end; i++) {
                nv_crtc->lut.r[i] = r[i];
                nv_crtc->lut.g[i] = g[i];
                nv_crtc->lut.b[i] = b[i];
index f13ad0d..612fa6d 100644 (file)
@@ -76,7 +76,10 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name,
        nv_wo32(dev, obj, 2, offset);
        nv_wo32(dev, obj, 3, 0x00000000);
        nv_wo32(dev, obj, 4, 0x00000000);
-       nv_wo32(dev, obj, 5, 0x00010000);
+       if (dev_priv->card_type < NV_C0)
+               nv_wo32(dev, obj, 5, 0x00010000);
+       else
+               nv_wo32(dev, obj, 5, 0x00020000);
        dev_priv->engine.instmem.flush(dev);
 
        return 0;
diff --git a/drivers/gpu/drm/nouveau/nvc0_fb.c b/drivers/gpu/drm/nouveau/nvc0_fb.c
new file mode 100644 (file)
index 0000000..26a9960
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+
+int
+nvc0_fb_init(struct drm_device *dev)
+{
+       return 0;
+}
+
+void
+nvc0_fb_takedown(struct drm_device *dev)
+{
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c
new file mode 100644 (file)
index 0000000..d643758
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+
+void
+nvc0_fifo_disable(struct drm_device *dev)
+{
+}
+
+void
+nvc0_fifo_enable(struct drm_device *dev)
+{
+}
+
+bool
+nvc0_fifo_reassign(struct drm_device *dev, bool enable)
+{
+       return false;
+}
+
+bool
+nvc0_fifo_cache_flush(struct drm_device *dev)
+{
+       return true;
+}
+
+bool
+nvc0_fifo_cache_pull(struct drm_device *dev, bool enable)
+{
+       return false;
+}
+
+int
+nvc0_fifo_channel_id(struct drm_device *dev)
+{
+       return 127;
+}
+
+int
+nvc0_fifo_create_context(struct nouveau_channel *chan)
+{
+       return 0;
+}
+
+void
+nvc0_fifo_destroy_context(struct nouveau_channel *chan)
+{
+}
+
+int
+nvc0_fifo_load_context(struct nouveau_channel *chan)
+{
+       return 0;
+}
+
+int
+nvc0_fifo_unload_context(struct drm_device *dev)
+{
+       return 0;
+}
+
+void
+nvc0_fifo_takedown(struct drm_device *dev)
+{
+}
+
+int
+nvc0_fifo_init(struct drm_device *dev)
+{
+       return 0;
+}
+
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
new file mode 100644 (file)
index 0000000..717a517
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+
+void
+nvc0_graph_fifo_access(struct drm_device *dev, bool enabled)
+{
+}
+
+struct nouveau_channel *
+nvc0_graph_channel(struct drm_device *dev)
+{
+       return NULL;
+}
+
+int
+nvc0_graph_create_context(struct nouveau_channel *chan)
+{
+       return 0;
+}
+
+void
+nvc0_graph_destroy_context(struct nouveau_channel *chan)
+{
+}
+
+int
+nvc0_graph_load_context(struct nouveau_channel *chan)
+{
+       return 0;
+}
+
+int
+nvc0_graph_unload_context(struct drm_device *dev)
+{
+       return 0;
+}
+
+void
+nvc0_graph_takedown(struct drm_device *dev)
+{
+}
+
+int
+nvc0_graph_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       dev_priv->engine.graph.accel_blocked = true;
+       return 0;
+}
+
diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c
new file mode 100644 (file)
index 0000000..3ab3cdc
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+
+int
+nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
+                     uint32_t *size)
+{
+       int ret;
+
+       *size = ALIGN(*size, 4096);
+       if (*size == 0)
+               return -EINVAL;
+
+       ret = nouveau_bo_new(dev, NULL, *size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000,
+                            true, false, &gpuobj->im_backing);
+       if (ret) {
+               NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret);
+               return ret;
+       }
+
+       ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM);
+       if (ret) {
+               NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret);
+               nouveau_bo_ref(NULL, &gpuobj->im_backing);
+               return ret;
+       }
+
+       gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start;
+       gpuobj->im_backing_start <<= PAGE_SHIFT;
+       return 0;
+}
+
+void
+nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if (gpuobj && gpuobj->im_backing) {
+               if (gpuobj->im_bound)
+                       dev_priv->engine.instmem.unbind(dev, gpuobj);
+               nouveau_bo_unpin(gpuobj->im_backing);
+               nouveau_bo_ref(NULL, &gpuobj->im_backing);
+               gpuobj->im_backing = NULL;
+       }
+}
+
+int
+nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       uint32_t pte, pte_end;
+       uint64_t vram;
+
+       if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
+               return -EINVAL;
+
+       NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n",
+                gpuobj->im_pramin->start, gpuobj->im_pramin->size);
+
+       pte     = gpuobj->im_pramin->start >> 12;
+       pte_end = (gpuobj->im_pramin->size >> 12) + pte;
+       vram    = gpuobj->im_backing_start;
+
+       NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
+                gpuobj->im_pramin->start, pte, pte_end);
+       NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
+
+       while (pte < pte_end) {
+               nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1);
+               nv_wr32(dev, 0x702004 + (pte * 8), 0);
+               vram += 4096;
+               pte++;
+       }
+       dev_priv->engine.instmem.flush(dev);
+
+       if (1) {
+               u32 chan = nv_rd32(dev, 0x1700) << 16;
+               nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8);
+               nv_wr32(dev, 0x100cbc, 0x80000005);
+       }
+
+       gpuobj->im_bound = 1;
+       return 0;
+}
+
+int
+nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       uint32_t pte, pte_end;
+
+       if (gpuobj->im_bound == 0)
+               return -EINVAL;
+
+       pte     = gpuobj->im_pramin->start >> 12;
+       pte_end = (gpuobj->im_pramin->size >> 12) + pte;
+       while (pte < pte_end) {
+               nv_wr32(dev, 0x702000 + (pte * 8), 0);
+               nv_wr32(dev, 0x702004 + (pte * 8), 0);
+               pte++;
+       }
+       dev_priv->engine.instmem.flush(dev);
+
+       gpuobj->im_bound = 0;
+       return 0;
+}
+
+void
+nvc0_instmem_flush(struct drm_device *dev)
+{
+       nv_wr32(dev, 0x070000, 1);
+       if (!nv_wait(0x070000, 0x00000002, 0x00000000))
+               NV_ERROR(dev, "PRAMIN flush timeout\n");
+}
+
+int
+nvc0_instmem_suspend(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       int i;
+
+       dev_priv->susres.ramin_copy = vmalloc(65536);
+       if (!dev_priv->susres.ramin_copy)
+               return -ENOMEM;
+
+       for (i = 0x700000; i < 0x710000; i += 4)
+               dev_priv->susres.ramin_copy[i/4] = nv_rd32(dev, i);
+       return 0;
+}
+
+void
+nvc0_instmem_resume(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       u64 chan;
+       int i;
+
+       chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
+       nv_wr32(dev, 0x001700, chan >> 16);
+
+       for (i = 0x700000; i < 0x710000; i += 4)
+               nv_wr32(dev, i, dev_priv->susres.ramin_copy[i/4]);
+       vfree(dev_priv->susres.ramin_copy);
+       dev_priv->susres.ramin_copy = NULL;
+
+       nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12));
+}
+
+int
+nvc0_instmem_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1;
+       int ret, i;
+
+       dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024;
+       chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
+       imem = 4096 + 4096 + 32768;
+
+       nv_wr32(dev, 0x001700, chan >> 16);
+
+       /* channel setup */
+       nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000));
+       nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000));
+       nv_wr32(dev, 0x700208, lower_32_bits(lim3));
+       nv_wr32(dev, 0x70020c, upper_32_bits(lim3));
+
+       /* point pgd -> pgt */
+       nv_wr32(dev, 0x701000, 0);
+       nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1);
+
+       /* point pgt -> physical vram for channel */
+       pgt3 = 0x2000;
+       for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) {
+               nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1);
+               nv_wr32(dev, 0x700004 + pgt3, 0);
+       }
+
+       /* clear rest of pgt */
+       for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) {
+               nv_wr32(dev, 0x700000 + pgt3, 0);
+               nv_wr32(dev, 0x700004 + pgt3, 0);
+       }
+
+       /* point bar3 at the channel */
+       nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12));
+
+       /* Global PRAMIN heap */
+       ret = drm_mm_init(&dev_priv->ramin_heap, imem,
+                         dev_priv->ramin_size - imem);
+       if (ret) {
+               NV_ERROR(dev, "Failed to init RAMIN heap\n");
+               return -ENOMEM;
+       }
+
+       /*XXX: incorrect, but needed to make hash func "work" */
+       dev_priv->ramht_offset = 0x10000;
+       dev_priv->ramht_bits   = 9;
+       dev_priv->ramht_size   = (1 << dev_priv->ramht_bits);
+       return 0;
+}
+
+void
+nvc0_instmem_takedown(struct drm_device *dev)
+{
+}
+
index 68e6f43..4f4cd8b 100644 (file)
@@ -200,7 +200,7 @@ int r600_page_table_init(struct drm_device *dev)
                                                 entry->pagelist[i], 0,
                                                 PAGE_SIZE,
                                                 PCI_DMA_BIDIRECTIONAL);
-               if (entry->busaddr[i] == 0) {
+               if (pci_dma_mapping_error(dev->pdev, entry->busaddr[i])) {
                        DRM_ERROR("unable to map PCIGART pages!\n");
                        r600_page_table_cleanup(dev, gart_info);
                        goto done;
index c3ea212..d886494 100644 (file)
@@ -133,6 +133,7 @@ static inline int r600_bpe_from_format(u32 *bpe, u32 format)
        case V_038004_FMT_GB_GR:
        case V_038004_FMT_BG_RG:
        case V_038004_COLOR_INVALID:
+       default:
                *bpe = 16;
                return -EINVAL;
        }
@@ -174,7 +175,7 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
                dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
                return -EINVAL;
        }
-       size = radeon_bo_size(track->cb_color_bo[i]);
+       size = radeon_bo_size(track->cb_color_bo[i]) - track->cb_color_bo_offset[i];
        if (r600_bpe_from_format(&bpe, G_0280A0_FORMAT(track->cb_color_info[i]))) {
                dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08X)\n",
                         __func__, __LINE__, G_0280A0_FORMAT(track->cb_color_info[i]),
@@ -327,7 +328,6 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
                                dev_warn(p->dev, "z/stencil buffer size not set\n");
                                return -EINVAL;
                        }
-                       printk_once(KERN_WARNING "You have old & broken userspace please consider updating mesa\n");
                        tmp = radeon_bo_size(track->db_bo) - track->db_offset;
                        tmp = (tmp / bpe) >> 6;
                        if (!tmp) {
@@ -882,8 +882,6 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
                                return -EINVAL;
                        }
                        ib[idx] = track->cb_color_base_last[tmp];
-                       printk_once(KERN_WARNING "You have old & broken userspace "
-                                       "please consider updating mesa & xf86-video-ati\n");
                        track->cb_color_frag_bo[tmp] = track->cb_color_bo[tmp];
                } else {
                        r = r600_cs_packet_next_reloc(p, &reloc);
@@ -910,8 +908,6 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
                                return -EINVAL;
                        }
                        ib[idx] = track->cb_color_base_last[tmp];
-                       printk_once(KERN_WARNING "You have old & broken userspace "
-                                       "please consider updating mesa & xf86-video-ati\n");
                        track->cb_color_tile_bo[tmp] = track->cb_color_bo[tmp];
                } else {
                        r = r600_cs_packet_next_reloc(p, &reloc);
@@ -938,7 +934,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
                        return -EINVAL;
                }
                tmp = (reg - CB_COLOR0_BASE) / 4;
-               track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
+               track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8;
                ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
                track->cb_color_base_last[tmp] = ib[idx];
                track->cb_color_bo[tmp] = reloc->robj;
@@ -950,7 +946,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
                                        "0x%04X\n", reg);
                        return -EINVAL;
                }
-               track->db_offset = radeon_get_ib_value(p, idx);
+               track->db_offset = radeon_get_ib_value(p, idx) << 8;
                ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
                track->db_bo = reloc->robj;
                break;
@@ -1055,10 +1051,10 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels
        }
        *l0_size = ALIGN((w0 * bpe), pitch_align) * h0 * d0;
        *mipmap_size = offset;
-       if (!blevel)
-               *mipmap_size -= *l0_size;
        if (!nlevels)
                *mipmap_size = *l0_size;
+       if (!blevel)
+               *mipmap_size -= *l0_size;
 }
 
 /**
@@ -1165,14 +1161,14 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 i
                          (pitch_align * bpe),
                          &l0_size, &mipmap_size);
        /* using get ib will give us the offset into the texture bo */
-       word0 = radeon_get_ib_value(p, idx + 2);
+       word0 = radeon_get_ib_value(p, idx + 2) << 8;
        if ((l0_size + word0) > radeon_bo_size(texture)) {
                dev_warn(p->dev, "texture bo too small (%d %d %d %d -> %d have %ld)\n",
                        w0, h0, bpe, word0, l0_size, radeon_bo_size(texture));
                return -EINVAL;
        }
        /* using get ib will give us the offset into the mipmap bo */
-       word0 = radeon_get_ib_value(p, idx + 3);
+       word0 = radeon_get_ib_value(p, idx + 3) << 8;
        if ((mipmap_size + word0) > radeon_bo_size(mipmap)) {
                dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n",
                        w0, h0, bpe, blevel, nlevels, word0, mipmap_size, radeon_bo_size(texture));
@@ -1366,7 +1362,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                }
                for (i = 0; i < (pkt->count / 7); i++) {
                        struct radeon_bo *texture, *mipmap;
-                       u32 size, offset;
+                       u32 size, offset, base_offset, mip_offset;
 
                        switch (G__SQ_VTX_CONSTANT_TYPE(radeon_get_ib_value(p, idx+(i*7)+6+1))) {
                        case SQ_TEX_VTX_VALID_TEXTURE:
@@ -1376,7 +1372,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                        DRM_ERROR("bad SET_RESOURCE\n");
                                        return -EINVAL;
                                }
-                               ib[idx+1+(i*7)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+                               base_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
                                if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
                                        ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1);
                                else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
@@ -1388,12 +1384,14 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                        DRM_ERROR("bad SET_RESOURCE\n");
                                        return -EINVAL;
                                }
-                               ib[idx+1+(i*7)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+                               mip_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
                                mipmap = reloc->robj;
                                r = r600_check_texture_resource(p,  idx+(i*7)+1,
                                                                texture, mipmap, reloc->lobj.tiling_flags);
                                if (r)
                                        return r;
+                               ib[idx+1+(i*7)+2] += base_offset;
+                               ib[idx+1+(i*7)+3] += mip_offset;
                                break;
                        case SQ_TEX_VTX_VALID_BUFFER:
                                /* vtx base */
@@ -1403,10 +1401,11 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                        return -EINVAL;
                                }
                                offset = radeon_get_ib_value(p, idx+1+(i*7)+0);
-                               size = radeon_get_ib_value(p, idx+1+(i*7)+1);
+                               size = radeon_get_ib_value(p, idx+1+(i*7)+1) + 1;
                                if (p->rdev && (size + offset) > radeon_bo_size(reloc->robj)) {
                                        /* force size to size of the buffer */
-                                       dev_warn(p->dev, "vbo resource seems too big for the bo\n");
+                                       dev_warn(p->dev, "vbo resource seems too big (%d) for the bo (%ld)\n",
+                                                size + offset, radeon_bo_size(reloc->robj));
                                        ib[idx+1+(i*7)+1] = radeon_bo_size(reloc->robj);
                                }
                                ib[idx+1+(i*7)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff);
index 3cd1c47..3dfcfa3 100644 (file)
@@ -1100,6 +1100,8 @@ struct radeon_device {
        struct notifier_block acpi_nb;
        /* only one userspace can use Hyperz features at a time */
        struct drm_file *hyperz_filp;
+       /* i2c buses */
+       struct radeon_i2c_chan *i2c_bus[RADEON_MAX_I2C_BUS];
 };
 
 int radeon_device_init(struct radeon_device *rdev,
index 3bc2bcd..6d30868 100644 (file)
@@ -48,7 +48,8 @@ radeon_add_atom_connector(struct drm_device *dev,
                          struct radeon_i2c_bus_rec *i2c_bus,
                          bool linkb, uint32_t igp_lane_info,
                          uint16_t connector_object_id,
-                         struct radeon_hpd *hpd);
+                         struct radeon_hpd *hpd,
+                         struct radeon_router *router);
 
 /* from radeon_legacy_encoder.c */
 extern void
@@ -114,7 +115,8 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev
 
                                i2c.i2c_id = gpio->sucI2cId.ucAccess;
 
-                               i2c.valid = true;
+                               if (i2c.mask_clk_reg)
+                                       i2c.valid = true;
                                break;
                        }
                }
@@ -123,6 +125,66 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev
        return i2c;
 }
 
+void radeon_atombios_i2c_init(struct radeon_device *rdev)
+{
+       struct atom_context *ctx = rdev->mode_info.atom_context;
+       ATOM_GPIO_I2C_ASSIGMENT *gpio;
+       struct radeon_i2c_bus_rec i2c;
+       int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
+       struct _ATOM_GPIO_I2C_INFO *i2c_info;
+       uint16_t data_offset, size;
+       int i, num_indices;
+       char stmp[32];
+
+       memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec));
+
+       if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
+               i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);
+
+               num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+                       sizeof(ATOM_GPIO_I2C_ASSIGMENT);
+
+               for (i = 0; i < num_indices; i++) {
+                       gpio = &i2c_info->asGPIO_Info[i];
+                       i2c.valid = false;
+                       i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
+                       i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
+                       i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
+                       i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4;
+                       i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4;
+                       i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4;
+                       i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4;
+                       i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4;
+                       i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift);
+                       i2c.mask_data_mask = (1 << gpio->ucDataMaskShift);
+                       i2c.en_clk_mask = (1 << gpio->ucClkEnShift);
+                       i2c.en_data_mask = (1 << gpio->ucDataEnShift);
+                       i2c.y_clk_mask = (1 << gpio->ucClkY_Shift);
+                       i2c.y_data_mask = (1 << gpio->ucDataY_Shift);
+                       i2c.a_clk_mask = (1 << gpio->ucClkA_Shift);
+                       i2c.a_data_mask = (1 << gpio->ucDataA_Shift);
+
+                       if (gpio->sucI2cId.sbfAccess.bfHW_Capable)
+                               i2c.hw_capable = true;
+                       else
+                               i2c.hw_capable = false;
+
+                       if (gpio->sucI2cId.ucAccess == 0xa0)
+                               i2c.mm_i2c = true;
+                       else
+                               i2c.mm_i2c = false;
+
+                       i2c.i2c_id = gpio->sucI2cId.ucAccess;
+
+                       if (i2c.mask_clk_reg) {
+                               i2c.valid = true;
+                               sprintf(stmp, "0x%x", i2c.i2c_id);
+                               rdev->i2c_bus[i] = radeon_i2c_create(rdev->ddev, &i2c, stmp);
+                       }
+               }
+       }
+}
+
 static inline struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev,
                                                        u8 id)
 {
@@ -206,6 +268,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
                                     uint16_t *line_mux,
                                     struct radeon_hpd *hpd)
 {
+       struct radeon_device *rdev = dev->dev_private;
 
        /* Asus M2A-VM HDMI board lists the DVI port as HDMI */
        if ((dev->pdev->device == 0x791e) &&
@@ -308,13 +371,22 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
                }
        }
 
-       /* Acer laptop reports DVI-D as DVI-I */
+       /* Acer laptop reports DVI-D as DVI-I and hpd pins reversed */
        if ((dev->pdev->device == 0x95c4) &&
            (dev->pdev->subsystem_vendor == 0x1025) &&
            (dev->pdev->subsystem_device == 0x013c)) {
+               struct radeon_gpio_rec gpio;
+
                if ((*connector_type == DRM_MODE_CONNECTOR_DVII) &&
-                   (supported_device == ATOM_DEVICE_DFP1_SUPPORT))
+                   (supported_device == ATOM_DEVICE_DFP1_SUPPORT)) {
+                       gpio = radeon_lookup_gpio(rdev, 6);
+                       *hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio);
                        *connector_type = DRM_MODE_CONNECTOR_DVID;
+               } else if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
+                          (supported_device == ATOM_DEVICE_DFP1_SUPPORT)) {
+                       gpio = radeon_lookup_gpio(rdev, 7);
+                       *hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio);
+               }
        }
 
        /* XFX Pine Group device rv730 reports no VGA DDC lines
@@ -399,13 +471,15 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
        u16 size, data_offset;
        u8 frev, crev;
        ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
+       ATOM_OBJECT_TABLE *router_obj;
        ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
        ATOM_OBJECT_HEADER *obj_header;
-       int i, j, path_size, device_support;
+       int i, j, k, path_size, device_support;
        int connector_type;
        u16 igp_lane_info, conn_id, connector_object_id;
        bool linkb;
        struct radeon_i2c_bus_rec ddc_bus;
+       struct radeon_router router;
        struct radeon_gpio_rec gpio;
        struct radeon_hpd hpd;
 
@@ -415,6 +489,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
        if (crev < 2)
                return false;
 
+       router.valid = false;
+
        obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);
        path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
            (ctx->bios + data_offset +
@@ -422,6 +498,9 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
        con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
            (ctx->bios + data_offset +
             le16_to_cpu(obj_header->usConnectorObjectTableOffset));
+       router_obj = (ATOM_OBJECT_TABLE *)
+               (ctx->bios + data_offset +
+                le16_to_cpu(obj_header->usRouterObjectTableOffset));
        device_support = le16_to_cpu(obj_header->usDeviceSupport);
 
        path_size = 0;
@@ -508,33 +587,86 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
                        if (connector_type == DRM_MODE_CONNECTOR_Unknown)
                                continue;
 
-                       for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2);
-                            j++) {
-                               uint8_t enc_obj_id, enc_obj_num, enc_obj_type;
+                       for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
+                               uint8_t grph_obj_id, grph_obj_num, grph_obj_type;
 
-                               enc_obj_id =
+                               grph_obj_id =
                                    (le16_to_cpu(path->usGraphicObjIds[j]) &
                                     OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
-                               enc_obj_num =
+                               grph_obj_num =
                                    (le16_to_cpu(path->usGraphicObjIds[j]) &
                                     ENUM_ID_MASK) >> ENUM_ID_SHIFT;
-                               enc_obj_type =
+                               grph_obj_type =
                                    (le16_to_cpu(path->usGraphicObjIds[j]) &
                                     OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
 
-                               /* FIXME: add support for router objects */
-                               if (enc_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
-                                       if (enc_obj_num == 2)
+                               if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
+                                       if (grph_obj_num == 2)
                                                linkb = true;
                                        else
                                                linkb = false;
 
                                        radeon_add_atom_encoder(dev,
-                                                               enc_obj_id,
+                                                               grph_obj_id,
                                                                le16_to_cpu
                                                                (path->
                                                                 usDeviceTag));
 
+                               } else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) {
+                                       router.valid = false;
+                                       for (k = 0; k < router_obj->ucNumberOfObjects; k++) {
+                                               u16 router_obj_id = le16_to_cpu(router_obj->asObjects[j].usObjectID);
+                                               if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) {
+                                                       ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
+                                                               (ctx->bios + data_offset +
+                                                                le16_to_cpu(router_obj->asObjects[k].usRecordOffset));
+                                                       ATOM_I2C_RECORD *i2c_record;
+                                                       ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
+                                                       ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path;
+                                                       ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table =
+                                                               (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
+                                                               (ctx->bios + data_offset +
+                                                                le16_to_cpu(router_obj->asObjects[k].usSrcDstTableOffset));
+                                                       int enum_id;
+
+                                                       router.router_id = router_obj_id;
+                                                       for (enum_id = 0; enum_id < router_src_dst_table->ucNumberOfDst;
+                                                            enum_id++) {
+                                                               if (le16_to_cpu(path->usConnObjectId) ==
+                                                                   le16_to_cpu(router_src_dst_table->usDstObjectID[enum_id]))
+                                                                       break;
+                                                       }
+
+                                                       while (record->ucRecordType > 0 &&
+                                                              record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
+                                                               switch (record->ucRecordType) {
+                                                               case ATOM_I2C_RECORD_TYPE:
+                                                                       i2c_record =
+                                                                               (ATOM_I2C_RECORD *)
+                                                                               record;
+                                                                       i2c_config =
+                                                                               (ATOM_I2C_ID_CONFIG_ACCESS *)
+                                                                               &i2c_record->sucI2cId;
+                                                                       router.i2c_info =
+                                                                               radeon_lookup_i2c_gpio(rdev,
+                                                                                                      i2c_config->
+                                                                                                      ucAccess);
+                                                                       router.i2c_addr = i2c_record->ucI2CAddr >> 1;
+                                                                       break;
+                                                               case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
+                                                                       ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)
+                                                                               record;
+                                                                       router.valid = true;
+                                                                       router.mux_type = ddc_path->ucMuxType;
+                                                                       router.mux_control_pin = ddc_path->ucMuxControlPin;
+                                                                       router.mux_state = ddc_path->ucMuxState[enum_id];
+                                                                       break;
+                                                               }
+                                                               record = (ATOM_COMMON_RECORD_HEADER *)
+                                                                       ((char *)record + record->ucRecordSize);
+                                                       }
+                                               }
+                                       }
                                }
                        }
 
@@ -614,7 +746,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
                                                  connector_type, &ddc_bus,
                                                  linkb, igp_lane_info,
                                                  connector_object_id,
-                                                 &hpd);
+                                                 &hpd,
+                                                 &router);
 
                }
        }
@@ -691,6 +824,9 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
        int i, j, max_device;
        struct bios_connector *bios_connectors;
        size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE;
+       struct radeon_router router;
+
+       router.valid = false;
 
        bios_connectors = kzalloc(bc_size, GFP_KERNEL);
        if (!bios_connectors)
@@ -862,7 +998,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
                                                  &bios_connectors[i].ddc_bus,
                                                  false, 0,
                                                  connector_object_id,
-                                                 &bios_connectors[i].hpd);
+                                                 &bios_connectors[i].hpd,
+                                                 &router);
                }
        }
 
@@ -1521,7 +1658,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                         thermal_controller_names[power_info->info.ucOverdriveThermalController],
                                         power_info->info.ucOverdriveControllerAddress >> 1);
                                i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine);
-                               rdev->pm.i2c_bus = radeon_i2c_create(rdev->ddev, &i2c_bus, "Thermal");
+                               rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
                                if (rdev->pm.i2c_bus) {
                                        struct i2c_board_info info = { };
                                        const char *name = thermal_controller_names[power_info->info.
@@ -1814,7 +1951,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                                 (controller->ucFanParameters &
                                                  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
                                        i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine);
-                                       rdev->pm.i2c_bus = radeon_i2c_create(rdev->ddev, &i2c_bus, "Thermal");
+                                       rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
                                        if (rdev->pm.i2c_bus) {
                                                struct i2c_board_info info = { };
                                                const char *name = pp_lib_thermal_controller_names[controller->ucType];
@@ -1927,6 +2064,11 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                                rdev->pm.power_state[state_index].type =
                                                        POWER_STATE_TYPE_PERFORMANCE;
                                                break;
+                                       case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
+                                               if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
+                                                       rdev->pm.power_state[state_index].type =
+                                                               POWER_STATE_TYPE_PERFORMANCE;
+                                               break;
                                        }
                                        rdev->pm.power_state[state_index].flags = 0;
                                        if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
index f64936c..14448a7 100644 (file)
@@ -91,6 +91,85 @@ uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev)
        return mclk;
 }
 
+#ifdef CONFIG_OF
+/*
+ * Read XTAL (ref clock), SCLK and MCLK from Open Firmware device
+ * tree. Hopefully, ATI OF driver is kind enough to fill these
+ */
+static bool __devinit radeon_read_clocks_OF(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct device_node *dp = rdev->pdev->dev.of_node;
+       const u32 *val;
+       struct radeon_pll *p1pll = &rdev->clock.p1pll;
+       struct radeon_pll *p2pll = &rdev->clock.p2pll;
+       struct radeon_pll *spll = &rdev->clock.spll;
+       struct radeon_pll *mpll = &rdev->clock.mpll;
+
+       if (dp == NULL)
+               return false;
+       val = of_get_property(dp, "ATY,RefCLK", NULL);
+       if (!val || !*val) {
+               printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n");
+               return false;
+       }
+       p1pll->reference_freq = p2pll->reference_freq = (*val) / 10;
+       p1pll->reference_div = RREG32_PLL(RADEON_PPLL_REF_DIV) & 0x3ff;
+       if (p1pll->reference_div < 2)
+               p1pll->reference_div = 12;
+       p2pll->reference_div = p1pll->reference_div;    
+
+       /* These aren't in the device-tree */
+       if (rdev->family >= CHIP_R420) {
+               p1pll->pll_in_min = 100;
+               p1pll->pll_in_max = 1350;
+               p1pll->pll_out_min = 20000;
+               p1pll->pll_out_max = 50000;
+               p2pll->pll_in_min = 100;
+               p2pll->pll_in_max = 1350;
+               p2pll->pll_out_min = 20000;
+               p2pll->pll_out_max = 50000;
+       } else {
+               p1pll->pll_in_min = 40;
+               p1pll->pll_in_max = 500;
+               p1pll->pll_out_min = 12500;
+               p1pll->pll_out_max = 35000;
+               p2pll->pll_in_min = 40;
+               p2pll->pll_in_max = 500;
+               p2pll->pll_out_min = 12500;
+               p2pll->pll_out_max = 35000;
+       }
+
+       spll->reference_freq = mpll->reference_freq = p1pll->reference_freq;
+       spll->reference_div = mpll->reference_div =
+               RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) &
+                           RADEON_M_SPLL_REF_DIV_MASK;
+
+       val = of_get_property(dp, "ATY,SCLK", NULL);
+       if (val && *val)
+               rdev->clock.default_sclk = (*val) / 10;
+       else
+               rdev->clock.default_sclk =
+                       radeon_legacy_get_engine_clock(rdev);
+                       
+       val = of_get_property(dp, "ATY,MCLK", NULL);
+       if (val && *val)
+               rdev->clock.default_mclk = (*val) / 10;
+       else
+               rdev->clock.default_mclk =
+                       radeon_legacy_get_memory_clock(rdev);
+
+       DRM_INFO("Using device-tree clock info\n");
+       
+       return true;
+}
+#else
+static bool __devinit radeon_read_clocks_OF(struct drm_device *dev)
+{
+       return false;
+}
+#endif /* CONFIG_OF */
+
 void radeon_get_clock_info(struct drm_device *dev)
 {
        struct radeon_device *rdev = dev->dev_private;
@@ -105,6 +184,8 @@ void radeon_get_clock_info(struct drm_device *dev)
                ret = radeon_atom_get_clock_info(dev);
        else
                ret = radeon_combios_get_clock_info(dev);
+       if (!ret)
+               ret = radeon_read_clocks_OF(dev);
 
        if (ret) {
                if (p1pll->reference_div < 2) {
index 5e1474c..885dcfa 100644 (file)
@@ -480,9 +480,66 @@ radeon_combios_get_hardcoded_edid(struct radeon_device *rdev)
 }
 
 static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rdev,
-                                                      int ddc_line)
+                                                      enum radeon_combios_ddc ddc,
+                                                      u32 clk_mask,
+                                                      u32 data_mask)
 {
        struct radeon_i2c_bus_rec i2c;
+       int ddc_line = 0;
+
+       /* ddc id            = mask reg
+        * DDC_NONE_DETECTED = none
+        * DDC_DVI           = RADEON_GPIO_DVI_DDC
+        * DDC_VGA           = RADEON_GPIO_VGA_DDC
+        * DDC_LCD           = RADEON_GPIOPAD_MASK
+        * DDC_GPIO          = RADEON_MDGPIO_MASK
+        * r1xx/r2xx
+        * DDC_MONID         = RADEON_GPIO_MONID
+        * DDC_CRT2          = RADEON_GPIO_CRT2_DDC
+        * r3xx
+        * DDC_MONID         = RADEON_GPIO_MONID
+        * DDC_CRT2          = RADEON_GPIO_DVI_DDC
+        * rs3xx/rs4xx
+        * DDC_MONID         = RADEON_GPIOPAD_MASK
+        * DDC_CRT2          = RADEON_GPIO_MONID
+        */
+       switch (ddc) {
+       case DDC_NONE_DETECTED:
+       default:
+               ddc_line = 0;
+               break;
+       case DDC_DVI:
+               ddc_line = RADEON_GPIO_DVI_DDC;
+               break;
+       case DDC_VGA:
+               ddc_line = RADEON_GPIO_VGA_DDC;
+               break;
+       case DDC_LCD:
+               ddc_line = RADEON_GPIOPAD_MASK;
+               break;
+       case DDC_GPIO:
+               ddc_line = RADEON_MDGPIO_MASK;
+               break;
+       case DDC_MONID:
+               if (rdev->family == CHIP_RS300 ||
+                   rdev->family == CHIP_RS400 ||
+                   rdev->family == CHIP_RS480)
+                       ddc_line = RADEON_GPIOPAD_MASK;
+               else
+                       ddc_line = RADEON_GPIO_MONID;
+               break;
+       case DDC_CRT2:
+               if (rdev->family == CHIP_RS300 ||
+                   rdev->family == CHIP_RS400 ||
+                   rdev->family == CHIP_RS480)
+                       ddc_line = RADEON_GPIO_MONID;
+               else if (rdev->family >= CHIP_R300) {
+                       ddc_line = RADEON_GPIO_DVI_DDC;
+                       ddc = DDC_DVI;
+               } else
+                       ddc_line = RADEON_GPIO_CRT2_DDC;
+               break;
+       }
 
        if (ddc_line == RADEON_GPIOPAD_MASK) {
                i2c.mask_clk_reg = RADEON_GPIOPAD_MASK;
@@ -503,15 +560,6 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
                i2c.y_clk_reg = RADEON_MDGPIO_Y;
                i2c.y_data_reg = RADEON_MDGPIO_Y;
        } else {
-               i2c.mask_clk_mask = RADEON_GPIO_EN_1;
-               i2c.mask_data_mask = RADEON_GPIO_EN_0;
-               i2c.a_clk_mask = RADEON_GPIO_A_1;
-               i2c.a_data_mask = RADEON_GPIO_A_0;
-               i2c.en_clk_mask = RADEON_GPIO_EN_1;
-               i2c.en_data_mask = RADEON_GPIO_EN_0;
-               i2c.y_clk_mask = RADEON_GPIO_Y_1;
-               i2c.y_data_mask = RADEON_GPIO_Y_0;
-
                i2c.mask_clk_reg = ddc_line;
                i2c.mask_data_reg = ddc_line;
                i2c.a_clk_reg = ddc_line;
@@ -522,6 +570,26 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
                i2c.y_data_reg = ddc_line;
        }
 
+       if (clk_mask && data_mask) {
+               i2c.mask_clk_mask = clk_mask;
+               i2c.mask_data_mask = data_mask;
+               i2c.a_clk_mask = clk_mask;
+               i2c.a_data_mask = data_mask;
+               i2c.en_clk_mask = clk_mask;
+               i2c.en_data_mask = data_mask;
+               i2c.y_clk_mask = clk_mask;
+               i2c.y_data_mask = data_mask;
+       } else {
+               i2c.mask_clk_mask = RADEON_GPIO_EN_1;
+               i2c.mask_data_mask = RADEON_GPIO_EN_0;
+               i2c.a_clk_mask = RADEON_GPIO_A_1;
+               i2c.a_data_mask = RADEON_GPIO_A_0;
+               i2c.en_clk_mask = RADEON_GPIO_EN_1;
+               i2c.en_data_mask = RADEON_GPIO_EN_0;
+               i2c.y_clk_mask = RADEON_GPIO_Y_1;
+               i2c.y_data_mask = RADEON_GPIO_Y_0;
+       }
+
        switch (rdev->family) {
        case CHIP_R100:
        case CHIP_RV100:
@@ -599,7 +667,8 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
                break;
        }
        i2c.mm_i2c = false;
-       i2c.i2c_id = 0;
+
+       i2c.i2c_id = ddc;
        i2c.hpd = RADEON_HPD_NONE;
 
        if (ddc_line)
@@ -610,6 +679,62 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
        return i2c;
 }
 
+void radeon_combios_i2c_init(struct radeon_device *rdev)
+{
+       struct drm_device *dev = rdev->ddev;
+       struct radeon_i2c_bus_rec i2c;
+
+
+       i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
+       rdev->i2c_bus[0] = radeon_i2c_create(dev, &i2c, "DVI_DDC");
+
+       i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
+       rdev->i2c_bus[1] = radeon_i2c_create(dev, &i2c, "VGA_DDC");
+
+       i2c.valid = true;
+       i2c.hw_capable = true;
+       i2c.mm_i2c = true;
+       i2c.i2c_id = 0xa0;
+       rdev->i2c_bus[2] = radeon_i2c_create(dev, &i2c, "MM_I2C");
+
+       if (rdev->family == CHIP_RS300 ||
+           rdev->family == CHIP_RS400 ||
+           rdev->family == CHIP_RS480) {
+               u16 offset;
+               u8 id, blocks, clk, data;
+               int i;
+
+               i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
+               rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
+
+               offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE);
+               if (offset) {
+                       blocks = RBIOS8(offset + 2);
+                       for (i = 0; i < blocks; i++) {
+                               id = RBIOS8(offset + 3 + (i * 5) + 0);
+                               if (id == 136) {
+                                       clk = RBIOS8(offset + 3 + (i * 5) + 3);
+                                       data = RBIOS8(offset + 3 + (i * 5) + 4);
+                                       i2c = combios_setup_i2c_bus(rdev, DDC_MONID,
+                                                                   clk, data);
+                                       rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");
+                                       break;
+                               }
+                       }
+               }
+
+       } else if (rdev->family >= CHIP_R300) {
+               i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
+               rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
+       } else {
+               i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
+               rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
+
+               i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
+               rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "CRT2_DDC");
+       }
+}
+
 bool radeon_combios_get_clock_info(struct drm_device *dev)
 {
        struct radeon_device *rdev = dev->dev_private;
@@ -1247,8 +1372,8 @@ bool radeon_legacy_get_ext_tmds_info_from_table(struct radeon_encoder *encoder,
        struct radeon_i2c_bus_rec i2c_bus;
 
        /* default for macs */
-       i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
-       tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
+       i2c_bus = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
+       tmds->i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
 
        /* XXX some macs have duallink chips */
        switch (rdev->mode_info.connector_table) {
@@ -1269,47 +1394,16 @@ bool radeon_legacy_get_ext_tmds_info_from_combios(struct radeon_encoder *encoder
        struct drm_device *dev = encoder->base.dev;
        struct radeon_device *rdev = dev->dev_private;
        uint16_t offset;
-       uint8_t ver, id, blocks, clk, data;
-       int i;
+       uint8_t ver;
        enum radeon_combios_ddc gpio;
        struct radeon_i2c_bus_rec i2c_bus;
 
        tmds->i2c_bus = NULL;
        if (rdev->flags & RADEON_IS_IGP) {
-               offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE);
-               if (offset) {
-                       ver = RBIOS8(offset);
-                       DRM_INFO("GPIO Table revision: %d\n", ver);
-                       blocks = RBIOS8(offset + 2);
-                       for (i = 0; i < blocks; i++) {
-                               id = RBIOS8(offset + 3 + (i * 5) + 0);
-                               if (id == 136) {
-                                       clk = RBIOS8(offset + 3 + (i * 5) + 3);
-                                       data = RBIOS8(offset + 3 + (i * 5) + 4);
-                                       i2c_bus.valid = true;
-                                       i2c_bus.mask_clk_mask = (1 << clk);
-                                       i2c_bus.mask_data_mask = (1 << data);
-                                       i2c_bus.a_clk_mask = (1 << clk);
-                                       i2c_bus.a_data_mask = (1 << data);
-                                       i2c_bus.en_clk_mask = (1 << clk);
-                                       i2c_bus.en_data_mask = (1 << data);
-                                       i2c_bus.y_clk_mask = (1 << clk);
-                                       i2c_bus.y_data_mask = (1 << data);
-                                       i2c_bus.mask_clk_reg = RADEON_GPIOPAD_MASK;
-                                       i2c_bus.mask_data_reg = RADEON_GPIOPAD_MASK;
-                                       i2c_bus.a_clk_reg = RADEON_GPIOPAD_A;
-                                       i2c_bus.a_data_reg = RADEON_GPIOPAD_A;
-                                       i2c_bus.en_clk_reg = RADEON_GPIOPAD_EN;
-                                       i2c_bus.en_data_reg = RADEON_GPIOPAD_EN;
-                                       i2c_bus.y_clk_reg = RADEON_GPIOPAD_Y;
-                                       i2c_bus.y_data_reg = RADEON_GPIOPAD_Y;
-                                       tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
-                                       tmds->dvo_chip = DVO_SIL164;
-                                       tmds->slave_addr = 0x70 >> 1; /* 7 bit addressing */
-                                       break;
-                               }
-                       }
-               }
+               i2c_bus = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
+               tmds->i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
+               tmds->dvo_chip = DVO_SIL164;
+               tmds->slave_addr = 0x70 >> 1; /* 7 bit addressing */
        } else {
                offset = combios_get_table_offset(dev, COMBIOS_EXT_TMDS_INFO_TABLE);
                if (offset) {
@@ -1318,37 +1412,15 @@ bool radeon_legacy_get_ext_tmds_info_from_combios(struct radeon_encoder *encoder
                        tmds->slave_addr = RBIOS8(offset + 4 + 2);
                        tmds->slave_addr >>= 1; /* 7 bit addressing */
                        gpio = RBIOS8(offset + 4 + 3);
-                       switch (gpio) {
-                       case DDC_MONID:
-                               i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
-                               tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
-                               break;
-                       case DDC_DVI:
-                               i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
-                               tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
-                               break;
-                       case DDC_VGA:
-                               i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
-                               tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
-                               break;
-                       case DDC_CRT2:
-                               /* R3xx+ chips don't have GPIO_CRT2_DDC gpio pad */
-                               if (rdev->family >= CHIP_R300)
-                                       i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
-                               else
-                                       i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
-                               tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
-                               break;
-                       case DDC_LCD: /* MM i2c */
+                       if (gpio == DDC_LCD) {
+                               /* MM i2c */
                                i2c_bus.valid = true;
                                i2c_bus.hw_capable = true;
                                i2c_bus.mm_i2c = true;
-                               tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
-                               break;
-                       default:
-                               DRM_ERROR("Unsupported gpio %d\n", gpio);
-                               break;
-                       }
+                               i2c_bus.i2c_id = 0xa0;
+                       } else
+                               i2c_bus = combios_setup_i2c_bus(rdev, gpio, 0, 0);
+                       tmds->i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
                }
        }
 
@@ -1430,7 +1502,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                /* these are the most common settings */
                if (rdev->flags & RADEON_SINGLE_CRTC) {
                        /* VGA - primary dac */
-                       ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+                       ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
                        hpd.hpd = RADEON_HPD_NONE;
                        radeon_add_legacy_encoder(dev,
                                                  radeon_get_encoder_id(dev,
@@ -1445,7 +1517,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                                    &hpd);
                } else if (rdev->flags & RADEON_IS_MOBILITY) {
                        /* LVDS */
-                       ddc_i2c = combios_setup_i2c_bus(rdev, 0);
+                       ddc_i2c = combios_setup_i2c_bus(rdev, DDC_NONE_DETECTED, 0, 0);
                        hpd.hpd = RADEON_HPD_NONE;
                        radeon_add_legacy_encoder(dev,
                                                  radeon_get_encoder_id(dev,
@@ -1460,7 +1532,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                                    &hpd);
 
                        /* VGA - primary dac */
-                       ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+                       ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
                        hpd.hpd = RADEON_HPD_NONE;
                        radeon_add_legacy_encoder(dev,
                                                  radeon_get_encoder_id(dev,
@@ -1475,7 +1547,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                                    &hpd);
                } else {
                        /* DVI-I - tv dac, int tmds */
-                       ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+                       ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
                        hpd.hpd = RADEON_HPD_1;
                        radeon_add_legacy_encoder(dev,
                                                  radeon_get_encoder_id(dev,
@@ -1496,7 +1568,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                                    &hpd);
 
                        /* VGA - primary dac */
-                       ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+                       ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
                        hpd.hpd = RADEON_HPD_NONE;
                        radeon_add_legacy_encoder(dev,
                                                  radeon_get_encoder_id(dev,
@@ -1532,7 +1604,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                DRM_INFO("Connector Table: %d (ibook)\n",
                         rdev->mode_info.connector_table);
                /* LVDS */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
                hpd.hpd = RADEON_HPD_NONE;
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1544,7 +1616,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                            CONNECTOR_OBJECT_ID_LVDS,
                                            &hpd);
                /* VGA - TV DAC */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
                hpd.hpd = RADEON_HPD_NONE;
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1573,7 +1645,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                DRM_INFO("Connector Table: %d (powerbook external tmds)\n",
                         rdev->mode_info.connector_table);
                /* LVDS */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
                hpd.hpd = RADEON_HPD_NONE;
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1585,7 +1657,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                            CONNECTOR_OBJECT_ID_LVDS,
                                            &hpd);
                /* DVI-I - primary dac, ext tmds */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
                hpd.hpd = RADEON_HPD_2; /* ??? */
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1622,7 +1694,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                DRM_INFO("Connector Table: %d (powerbook internal tmds)\n",
                         rdev->mode_info.connector_table);
                /* LVDS */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
                hpd.hpd = RADEON_HPD_NONE;
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1634,7 +1706,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                            CONNECTOR_OBJECT_ID_LVDS,
                                            &hpd);
                /* DVI-I - primary dac, int tmds */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
                hpd.hpd = RADEON_HPD_1; /* ??? */
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1670,7 +1742,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                DRM_INFO("Connector Table: %d (powerbook vga)\n",
                         rdev->mode_info.connector_table);
                /* LVDS */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
                hpd.hpd = RADEON_HPD_NONE;
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1682,7 +1754,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                            CONNECTOR_OBJECT_ID_LVDS,
                                            &hpd);
                /* VGA - primary dac */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
                hpd.hpd = RADEON_HPD_NONE;
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1711,7 +1783,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                DRM_INFO("Connector Table: %d (mini external tmds)\n",
                         rdev->mode_info.connector_table);
                /* DVI-I - tv dac, ext tmds */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
                hpd.hpd = RADEON_HPD_2; /* ??? */
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1748,7 +1820,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                DRM_INFO("Connector Table: %d (mini internal tmds)\n",
                         rdev->mode_info.connector_table);
                /* DVI-I - tv dac, int tmds */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
                hpd.hpd = RADEON_HPD_1; /* ??? */
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1784,7 +1856,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                DRM_INFO("Connector Table: %d (imac g5 isight)\n",
                         rdev->mode_info.connector_table);
                /* DVI-D - int tmds */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
                hpd.hpd = RADEON_HPD_1; /* ??? */
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1796,7 +1868,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                            CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D,
                                            &hpd);
                /* VGA - tv dac */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
                hpd.hpd = RADEON_HPD_NONE;
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1825,7 +1897,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                DRM_INFO("Connector Table: %d (emac)\n",
                         rdev->mode_info.connector_table);
                /* VGA - primary dac */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
                hpd.hpd = RADEON_HPD_NONE;
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1837,7 +1909,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                            CONNECTOR_OBJECT_ID_VGA,
                                            &hpd);
                /* VGA - tv dac */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
                hpd.hpd = RADEON_HPD_NONE;
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1866,7 +1938,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                DRM_INFO("Connector Table: %d (rn50-power)\n",
                         rdev->mode_info.connector_table);
                /* VGA - primary dac */
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
                hpd.hpd = RADEON_HPD_NONE;
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1877,7 +1949,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                            DRM_MODE_CONNECTOR_VGA, &ddc_i2c,
                                            CONNECTOR_OBJECT_ID_VGA,
                                            &hpd);
-               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
                hpd.hpd = RADEON_HPD_NONE;
                radeon_add_legacy_encoder(dev,
                                          radeon_get_encoder_id(dev,
@@ -1907,31 +1979,6 @@ static bool radeon_apply_legacy_quirks(struct drm_device *dev,
                                       struct radeon_i2c_bus_rec *ddc_i2c,
                                       struct radeon_hpd *hpd)
 {
-       struct radeon_device *rdev = dev->dev_private;
-
-       /* XPRESS DDC quirks */
-       if ((rdev->family == CHIP_RS400 ||
-            rdev->family == CHIP_RS480) &&
-           ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC)
-               *ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
-       else if ((rdev->family == CHIP_RS400 ||
-                 rdev->family == CHIP_RS480) &&
-                ddc_i2c->mask_clk_reg == RADEON_GPIO_MONID) {
-               *ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIOPAD_MASK);
-               ddc_i2c->mask_clk_mask = (0x20 << 8);
-               ddc_i2c->mask_data_mask = 0x80;
-               ddc_i2c->a_clk_mask = (0x20 << 8);
-               ddc_i2c->a_data_mask = 0x80;
-               ddc_i2c->en_clk_mask = (0x20 << 8);
-               ddc_i2c->en_data_mask = 0x80;
-               ddc_i2c->y_clk_mask = (0x20 << 8);
-               ddc_i2c->y_data_mask = 0x80;
-       }
-
-       /* R3xx+ chips don't have GPIO_CRT2_DDC gpio pad */
-       if ((rdev->family >= CHIP_R300) &&
-           ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC)
-               *ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
 
        /* Certain IBM chipset RN50s have a BIOS reporting two VGAs,
           one with VGA DDC and one with CRT2 DDC. - kill the CRT2 DDC one */
@@ -2035,27 +2082,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
                        connector = (tmp >> 12) & 0xf;
 
                        ddc_type = (tmp >> 8) & 0xf;
-                       switch (ddc_type) {
-                       case DDC_MONID:
-                               ddc_i2c =
-                                       combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
-                               break;
-                       case DDC_DVI:
-                               ddc_i2c =
-                                       combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
-                               break;
-                       case DDC_VGA:
-                               ddc_i2c =
-                                       combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
-                               break;
-                       case DDC_CRT2:
-                               ddc_i2c =
-                                       combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
-                               break;
-                       default:
-                               ddc_i2c.valid = false;
-                               break;
-                       }
+                       ddc_i2c = combios_setup_i2c_bus(rdev, ddc_type, 0, 0);
 
                        switch (connector) {
                        case CONNECTOR_PROPRIETARY_LEGACY:
@@ -2225,7 +2252,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
                                                                        0),
                                                  ATOM_DEVICE_DFP1_SUPPORT);
 
-                       ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+                       ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
                        hpd.hpd = RADEON_HPD_1;
                        radeon_add_legacy_connector(dev,
                                                    0,
@@ -2245,7 +2272,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
                                                                                ATOM_DEVICE_CRT1_SUPPORT,
                                                                                1),
                                                          ATOM_DEVICE_CRT1_SUPPORT);
-                               ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+                               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
                                hpd.hpd = RADEON_HPD_NONE;
                                radeon_add_legacy_connector(dev,
                                                            0,
@@ -2278,70 +2305,25 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
                        if (lcd_ddc_info) {
                                ddc_type = RBIOS8(lcd_ddc_info + 2);
                                switch (ddc_type) {
-                               case DDC_MONID:
-                                       ddc_i2c =
-                                           combios_setup_i2c_bus
-                                               (rdev, RADEON_GPIO_MONID);
-                                       break;
-                               case DDC_DVI:
-                                       ddc_i2c =
-                                           combios_setup_i2c_bus
-                                               (rdev, RADEON_GPIO_DVI_DDC);
-                                       break;
-                               case DDC_VGA:
-                                       ddc_i2c =
-                                           combios_setup_i2c_bus
-                                               (rdev, RADEON_GPIO_VGA_DDC);
-                                       break;
-                               case DDC_CRT2:
-                                       ddc_i2c =
-                                           combios_setup_i2c_bus
-                                               (rdev, RADEON_GPIO_CRT2_DDC);
-                                       break;
                                case DDC_LCD:
                                        ddc_i2c =
-                                           combios_setup_i2c_bus
-                                               (rdev, RADEON_GPIOPAD_MASK);
-                                       ddc_i2c.mask_clk_mask =
-                                           RBIOS32(lcd_ddc_info + 3);
-                                       ddc_i2c.mask_data_mask =
-                                           RBIOS32(lcd_ddc_info + 7);
-                                       ddc_i2c.a_clk_mask =
-                                           RBIOS32(lcd_ddc_info + 3);
-                                       ddc_i2c.a_data_mask =
-                                           RBIOS32(lcd_ddc_info + 7);
-                                       ddc_i2c.en_clk_mask =
-                                           RBIOS32(lcd_ddc_info + 3);
-                                       ddc_i2c.en_data_mask =
-                                           RBIOS32(lcd_ddc_info + 7);
-                                       ddc_i2c.y_clk_mask =
-                                           RBIOS32(lcd_ddc_info + 3);
-                                       ddc_i2c.y_data_mask =
-                                           RBIOS32(lcd_ddc_info + 7);
+                                               combios_setup_i2c_bus(rdev,
+                                                                     DDC_LCD,
+                                                                     RBIOS32(lcd_ddc_info + 3),
+                                                                     RBIOS32(lcd_ddc_info + 7));
+                                       radeon_i2c_add(rdev, &ddc_i2c, "LCD");
                                        break;
                                case DDC_GPIO:
                                        ddc_i2c =
-                                           combios_setup_i2c_bus
-                                               (rdev, RADEON_MDGPIO_MASK);
-                                       ddc_i2c.mask_clk_mask =
-                                           RBIOS32(lcd_ddc_info + 3);
-                                       ddc_i2c.mask_data_mask =
-                                           RBIOS32(lcd_ddc_info + 7);
-                                       ddc_i2c.a_clk_mask =
-                                           RBIOS32(lcd_ddc_info + 3);
-                                       ddc_i2c.a_data_mask =
-                                           RBIOS32(lcd_ddc_info + 7);
-                                       ddc_i2c.en_clk_mask =
-                                           RBIOS32(lcd_ddc_info + 3);
-                                       ddc_i2c.en_data_mask =
-                                           RBIOS32(lcd_ddc_info + 7);
-                                       ddc_i2c.y_clk_mask =
-                                           RBIOS32(lcd_ddc_info + 3);
-                                       ddc_i2c.y_data_mask =
-                                           RBIOS32(lcd_ddc_info + 7);
+                                               combios_setup_i2c_bus(rdev,
+                                                                     DDC_GPIO,
+                                                                     RBIOS32(lcd_ddc_info + 3),
+                                                                     RBIOS32(lcd_ddc_info + 7));
+                                       radeon_i2c_add(rdev, &ddc_i2c, "LCD");
                                        break;
                                default:
-                                       ddc_i2c.valid = false;
+                                       ddc_i2c =
+                                               combios_setup_i2c_bus(rdev, ddc_type, 0, 0);
                                        break;
                                }
                                DRM_DEBUG_KMS("LCD DDC Info Table found!\n");
index 2395c86..47c4b27 100644 (file)
@@ -518,8 +518,6 @@ static void radeon_connector_destroy(struct drm_connector *connector)
 {
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 
-       if (radeon_connector->ddc_bus)
-               radeon_i2c_destroy(radeon_connector->ddc_bus);
        if (radeon_connector->edid)
                kfree(radeon_connector->edid);
        kfree(radeon_connector->con_priv);
@@ -955,8 +953,6 @@ static void radeon_dp_connector_destroy(struct drm_connector *connector)
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
 
-       if (radeon_connector->ddc_bus)
-               radeon_i2c_destroy(radeon_connector->ddc_bus);
        if (radeon_connector->edid)
                kfree(radeon_connector->edid);
        if (radeon_dig_connector->dp_i2c_bus)
@@ -1044,7 +1040,8 @@ radeon_add_atom_connector(struct drm_device *dev,
                          bool linkb,
                          uint32_t igp_lane_info,
                          uint16_t connector_object_id,
-                         struct radeon_hpd *hpd)
+                         struct radeon_hpd *hpd,
+                         struct radeon_router *router)
 {
        struct radeon_device *rdev = dev->dev_private;
        struct drm_connector *connector;
@@ -1069,6 +1066,11 @@ radeon_add_atom_connector(struct drm_device *dev,
                                radeon_connector->shared_ddc = true;
                                shared_ddc = true;
                        }
+                       if (radeon_connector->router_bus && router->valid &&
+                           (radeon_connector->router.router_id == router->router_id)) {
+                               radeon_connector->shared_ddc = false;
+                               shared_ddc = false;
+                       }
                }
        }
 
@@ -1083,12 +1085,18 @@ radeon_add_atom_connector(struct drm_device *dev,
        radeon_connector->shared_ddc = shared_ddc;
        radeon_connector->connector_object_id = connector_object_id;
        radeon_connector->hpd = *hpd;
+       radeon_connector->router = *router;
+       if (router->valid) {
+               radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
+               if (!radeon_connector->router_bus)
+                       goto failed;
+       }
        switch (connector_type) {
        case DRM_MODE_CONNECTOR_VGA:
                drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
                drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
                if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
+                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
                                goto failed;
                }
@@ -1104,7 +1112,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
                drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
                if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
+                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
                                goto failed;
                }
@@ -1126,7 +1134,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
                drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
                if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
+                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
                                goto failed;
                }
@@ -1156,7 +1164,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
                drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
                if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "HDMI");
+                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
                                goto failed;
                }
@@ -1187,10 +1195,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                                radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
                        if (!radeon_dig_connector->dp_i2c_bus)
                                goto failed;
-                       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");
+                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
                                goto failed;
                }
@@ -1230,7 +1235,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
                drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
                if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
+                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
                                goto failed;
                }
@@ -1252,8 +1257,6 @@ radeon_add_atom_connector(struct drm_device *dev,
        return;
 
 failed:
-       if (radeon_connector->ddc_bus)
-               radeon_i2c_destroy(radeon_connector->ddc_bus);
        drm_connector_cleanup(connector);
        kfree(connector);
 }
@@ -1300,7 +1303,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
                drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
                drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
                if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
+                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
                                goto failed;
                }
@@ -1316,7 +1319,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
                drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
                drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
                if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
+                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
                                goto failed;
                }
@@ -1332,7 +1335,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
                drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
                drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
                if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
+                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
                                goto failed;
                }
@@ -1372,7 +1375,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
                drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
                drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
                if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
+                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
                                goto failed;
                }
@@ -1393,8 +1396,6 @@ radeon_add_legacy_connector(struct drm_device *dev,
        return;
 
 failed:
-       if (radeon_connector->ddc_bus)
-               radeon_i2c_destroy(radeon_connector->ddc_bus);
        drm_connector_cleanup(connector);
        kfree(connector);
 }
index ae0fb73..fcc79b5 100644 (file)
@@ -72,7 +72,7 @@ int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
                        if (p->relocs[i].gobj == NULL) {
                                DRM_ERROR("gem object lookup failed 0x%x\n",
                                          r->handle);
-                               return -EINVAL;
+                               return -ENOENT;
                        }
                        p->relocs_ptr[i] = &p->relocs[i];
                        p->relocs[i].robj = p->relocs[i].gobj->driver_private;
index 4eb67c0..5731fc9 100644 (file)
@@ -170,7 +170,7 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc,
        obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
        if (!obj) {
                DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
-               return -EINVAL;
+               return -ENOENT;
        }
 
        ret = radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
index a64811a..4f7a170 100644 (file)
@@ -347,7 +347,8 @@ int radeon_dummy_page_init(struct radeon_device *rdev)
                return -ENOMEM;
        rdev->dummy_page.addr = pci_map_page(rdev->pdev, rdev->dummy_page.page,
                                        0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-       if (!rdev->dummy_page.addr) {
+       if (pci_dma_mapping_error(rdev->pdev, rdev->dummy_page.addr)) {
+               dev_err(&rdev->pdev->dev, "Failed to DMA MAP the dummy page\n");
                __free_page(rdev->dummy_page.page);
                rdev->dummy_page.page = NULL;
                return -ENOMEM;
index 74dac96..5764f4d 100644 (file)
@@ -161,17 +161,13 @@ void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
 }
 
 static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
-                                 u16 *blue, uint32_t size)
+                                 u16 *blue, uint32_t start, uint32_t size)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
-       int i;
-
-       if (size != 256) {
-               return;
-       }
+       int end = (start + size > 256) ? 256 : start + size, i;
 
        /* userspace palettes are always correct as is */
-       for (i = 0; i < 256; i++) {
+       for (i = start; i < end; i++) {
                radeon_crtc->lut_r[i] = red[i] >> 6;
                radeon_crtc->lut_g[i] = green[i] >> 6;
                radeon_crtc->lut_b[i] = blue[i] >> 6;
@@ -319,6 +315,10 @@ 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);
+                       if (radeon_connector->router_bus)
+                               DRM_INFO("  DDC Router 0x%x/0x%x\n",
+                                        radeon_connector->router.mux_control_pin,
+                                        radeon_connector->router.mux_state);
                } else {
                        if (connector->connector_type == DRM_MODE_CONNECTOR_VGA ||
                            connector->connector_type == DRM_MODE_CONNECTOR_DVII ||
@@ -395,6 +395,10 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
        struct radeon_device *rdev = dev->dev_private;
        int ret = 0;
 
+       /* on hw with routers, select right port */
+       if (radeon_connector->router.valid)
+               radeon_router_select_port(radeon_connector);
+
        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;
@@ -425,6 +429,10 @@ static int radeon_ddc_dump(struct drm_connector *connector)
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        int ret = 0;
 
+       /* on hw with routers, select right port */
+       if (radeon_connector->router.valid)
+               radeon_router_select_port(radeon_connector);
+
        if (!radeon_connector->ddc_bus)
                return -1;
        edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter);
@@ -876,13 +884,12 @@ radeon_user_framebuffer_create(struct drm_device *dev,
        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 ERR_PTR(-ENOENT);
        }
 
        radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL);
-       if (radeon_fb == NULL) {
-               return NULL;
-       }
+       if (radeon_fb == NULL)
+               return ERR_PTR(-ENOMEM);
 
        radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj);
 
@@ -1040,6 +1047,9 @@ int radeon_modeset_init(struct radeon_device *rdev)
                return ret;
        }
 
+       /* init i2c buses */
+       radeon_i2c_init(rdev);
+
        /* check combios for a valid hardcoded EDID - Sun servers */
        if (!rdev->is_atom_bios) {
                /* check for hardcoded EDID in BIOS */
@@ -1080,6 +1090,8 @@ void radeon_modeset_fini(struct radeon_device *rdev)
                drm_mode_config_cleanup(rdev->ddev);
                rdev->mode_info.mode_config_initialized = false;
        }
+       /* free i2c buses */
+       radeon_i2c_fini(rdev);
 }
 
 bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
index a72a3ee..c578f26 100644 (file)
@@ -226,7 +226,7 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
        /* just do a BO wait for now */
        gobj = drm_gem_object_lookup(dev, filp, args->handle);
        if (gobj == NULL) {
-               return -EINVAL;
+               return -ENOENT;
        }
        robj = gobj->driver_private;
 
@@ -245,7 +245,7 @@ int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
 
        gobj = drm_gem_object_lookup(dev, filp, args->handle);
        if (gobj == NULL) {
-               return -EINVAL;
+               return -ENOENT;
        }
        robj = gobj->driver_private;
        args->addr_ptr = radeon_bo_mmap_offset(robj);
@@ -264,7 +264,7 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
 
        gobj = drm_gem_object_lookup(dev, filp, args->handle);
        if (gobj == NULL) {
-               return -EINVAL;
+               return -ENOENT;
        }
        robj = gobj->driver_private;
        r = radeon_bo_wait(robj, &cur_placement, true);
@@ -294,7 +294,7 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
 
        gobj = drm_gem_object_lookup(dev, filp, args->handle);
        if (gobj == NULL) {
-               return -EINVAL;
+               return -ENOENT;
        }
        robj = gobj->driver_private;
        r = radeon_bo_wait(robj, NULL, false);
@@ -316,7 +316,7 @@ int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
        DRM_DEBUG("%d \n", args->handle);
        gobj = drm_gem_object_lookup(dev, filp, args->handle);
        if (gobj == NULL)
-               return -EINVAL;
+               return -ENOENT;
        robj = gobj->driver_private;
        r = radeon_bo_set_tiling_flags(robj, args->tiling_flags, args->pitch);
        drm_gem_object_unreference_unlocked(gobj);
@@ -334,7 +334,7 @@ int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
        DRM_DEBUG("\n");
        gobj = drm_gem_object_lookup(dev, filp, args->handle);
        if (gobj == NULL)
-               return -EINVAL;
+               return -ENOENT;
        rbo = gobj->driver_private;
        r = radeon_bo_reserve(rbo, false);
        if (unlikely(r != 0))
index 5def6f5..bfd2ce5 100644 (file)
@@ -52,6 +52,10 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector)
                }
        };
 
+       /* on hw with routers, select right port */
+       if (radeon_connector->router.valid)
+               radeon_router_select_port(radeon_connector);
+
        ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
        if (ret == 2)
                return true;
@@ -960,6 +964,59 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c)
        kfree(i2c);
 }
 
+/* Add the default buses */
+void radeon_i2c_init(struct radeon_device *rdev)
+{
+       if (rdev->is_atom_bios)
+               radeon_atombios_i2c_init(rdev);
+       else
+               radeon_combios_i2c_init(rdev);
+}
+
+/* remove all the buses */
+void radeon_i2c_fini(struct radeon_device *rdev)
+{
+       int i;
+
+       for (i = 0; i < RADEON_MAX_I2C_BUS; i++) {
+               if (rdev->i2c_bus[i]) {
+                       radeon_i2c_destroy(rdev->i2c_bus[i]);
+                       rdev->i2c_bus[i] = NULL;
+               }
+       }
+}
+
+/* Add additional buses */
+void radeon_i2c_add(struct radeon_device *rdev,
+                   struct radeon_i2c_bus_rec *rec,
+                   const char *name)
+{
+       struct drm_device *dev = rdev->ddev;
+       int i;
+
+       for (i = 0; i < RADEON_MAX_I2C_BUS; i++) {
+               if (!rdev->i2c_bus[i]) {
+                       rdev->i2c_bus[i] = radeon_i2c_create(dev, rec, name);
+                       return;
+               }
+       }
+}
+
+/* looks up bus based on id */
+struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev,
+                                         struct radeon_i2c_bus_rec *i2c_bus)
+{
+       int i;
+
+       for (i = 0; i < RADEON_MAX_I2C_BUS; i++) {
+               if (rdev->i2c_bus[i] &&
+                   (rdev->i2c_bus[i]->rec.i2c_id == i2c_bus->i2c_id)) {
+                       return rdev->i2c_bus[i];
+               }
+       }
+       return NULL;
+}
+
 struct drm_encoder *radeon_best_encoder(struct drm_connector *connector)
 {
        return NULL;
@@ -1020,3 +1077,28 @@ void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus,
                          addr, val);
 }
 
+/* router switching */
+void radeon_router_select_port(struct radeon_connector *radeon_connector)
+{
+       u8 val;
+
+       if (!radeon_connector->router.valid)
+               return;
+
+       radeon_i2c_get_byte(radeon_connector->router_bus,
+                           radeon_connector->router.i2c_addr,
+                           0x3, &val);
+       val &= radeon_connector->router.mux_control_pin;
+       radeon_i2c_put_byte(radeon_connector->router_bus,
+                           radeon_connector->router.i2c_addr,
+                           0x3, val);
+       radeon_i2c_get_byte(radeon_connector->router_bus,
+                           radeon_connector->router.i2c_addr,
+                           0x1, &val);
+       val &= radeon_connector->router.mux_control_pin;
+       val |= radeon_connector->router.mux_state;
+       radeon_i2c_put_byte(radeon_connector->router_bus,
+                           radeon_connector->router.i2c_addr,
+                           0x1, val);
+}
+
index ddcd3b1..b1c8ace 100644 (file)
@@ -112,7 +112,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 
        info = data;
        value_ptr = (uint32_t *)((unsigned long)info->value);
-       value = *value_ptr;
+       if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value)))
+               return -EFAULT;
+
        switch (info->request) {
        case RADEON_INFO_DEVICE_ID:
                value = dev->pci_device;
@@ -160,13 +162,27 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                        return -EINVAL;
                }
        case RADEON_INFO_WANT_HYPERZ:
+               /* The "value" here is both an input and output parameter.
+                * If the input value is 1, filp requests hyper-z access.
+                * If the input value is 0, filp revokes its hyper-z access.
+                *
+                * When returning, the value is 1 if filp owns hyper-z access,
+                * 0 otherwise. */
+               if (value >= 2) {
+                       DRM_DEBUG_KMS("WANT_HYPERZ: invalid value %d\n", value);
+                       return -EINVAL;
+               }
                mutex_lock(&dev->struct_mutex);
-               if (rdev->hyperz_filp)
-                       value = 0;
-               else {
-                       rdev->hyperz_filp = filp;
-                       value = 1;
+               if (value == 1) {
+                       /* wants hyper-z */
+                       if (!rdev->hyperz_filp)
+                               rdev->hyperz_filp = filp;
+               } else if (value == 0) {
+                       /* revokes hyper-z */
+                       if (rdev->hyperz_filp == filp)
+                               rdev->hyperz_filp = NULL;
                }
+               value = rdev->hyperz_filp == filp ?  1 : 0;
                mutex_unlock(&dev->struct_mutex);
                break;
        default:
index 71aea40..5bbc086 100644 (file)
@@ -82,6 +82,8 @@ enum radeon_hpd_id {
        RADEON_HPD_NONE = 0xff,
 };
 
+#define RADEON_MAX_I2C_BUS 16
+
 /* radeon gpio-based i2c
  * 1. "mask" reg and bits
  *    grabs the gpio pins for software use
@@ -398,6 +400,16 @@ struct radeon_hpd {
        struct radeon_gpio_rec gpio;
 };
 
+struct radeon_router {
+       bool valid;
+       u32 router_id;
+       struct radeon_i2c_bus_rec i2c_info;
+       u8 i2c_addr;
+       u8 mux_type;
+       u8 mux_control_pin;
+       u8 mux_state;
+};
+
 struct radeon_connector {
        struct drm_connector base;
        uint32_t connector_id;
@@ -413,6 +425,8 @@ struct radeon_connector {
        bool dac_load_detect;
        uint16_t connector_object_id;
        struct radeon_hpd hpd;
+       struct radeon_router router;
+       struct radeon_i2c_chan *router_bus;
 };
 
 struct radeon_framebuffer {
@@ -445,6 +459,15 @@ extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,
 extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                                uint8_t write_byte, uint8_t *read_byte);
 
+extern void radeon_i2c_init(struct radeon_device *rdev);
+extern void radeon_i2c_fini(struct radeon_device *rdev);
+extern void radeon_combios_i2c_init(struct radeon_device *rdev);
+extern void radeon_atombios_i2c_init(struct radeon_device *rdev);
+extern void radeon_i2c_add(struct radeon_device *rdev,
+                          struct radeon_i2c_bus_rec *rec,
+                          const char *name);
+extern struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev,
+                                                struct radeon_i2c_bus_rec *i2c_bus);
 extern struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev,
                                                    struct radeon_i2c_bus_rec *rec,
                                                    const char *name);
@@ -460,6 +483,7 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c,
                                u8 slave_addr,
                                u8 addr,
                                u8 val);
+extern void radeon_router_select_port(struct radeon_connector *radeon_connector);
 extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
 extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
 
index 95f8b3a..58038f5 100644 (file)
@@ -472,9 +472,9 @@ static const struct attribute_group hwmon_attrgroup = {
        .attrs = hwmon_attributes,
 };
 
-static void radeon_hwmon_init(struct radeon_device *rdev)
+static int radeon_hwmon_init(struct radeon_device *rdev)
 {
-       int err;
+       int err = 0;
 
        rdev->pm.int_hwmon_dev = NULL;
 
@@ -483,15 +483,26 @@ static void radeon_hwmon_init(struct radeon_device *rdev)
        case THERMAL_TYPE_RV770:
        case THERMAL_TYPE_EVERGREEN:
                rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev);
+               if (IS_ERR(rdev->pm.int_hwmon_dev)) {
+                       err = PTR_ERR(rdev->pm.int_hwmon_dev);
+                       dev_err(rdev->dev,
+                               "Unable to register hwmon device: %d\n", err);
+                       break;
+               }
                dev_set_drvdata(rdev->pm.int_hwmon_dev, rdev->ddev);
                err = sysfs_create_group(&rdev->pm.int_hwmon_dev->kobj,
                                         &hwmon_attrgroup);
-               if (err)
-                       DRM_ERROR("Unable to create hwmon sysfs file: %d\n", err);
+               if (err) {
+                       dev_err(rdev->dev,
+                               "Unable to create hwmon sysfs file: %d\n", err);
+                       hwmon_device_unregister(rdev->dev);
+               }
                break;
        default:
                break;
        }
+
+       return err;
 }
 
 static void radeon_hwmon_fini(struct radeon_device *rdev)
@@ -540,6 +551,7 @@ void radeon_pm_resume(struct radeon_device *rdev)
 int radeon_pm_init(struct radeon_device *rdev)
 {
        int ret;
+
        /* default to profile method */
        rdev->pm.pm_method = PM_METHOD_PROFILE;
        rdev->pm.profile = PM_PROFILE_DEFAULT;
@@ -561,7 +573,9 @@ int radeon_pm_init(struct radeon_device *rdev)
        }
 
        /* set up the internal thermal sensor if applicable */
-       radeon_hwmon_init(rdev);
+       ret = radeon_hwmon_init(rdev);
+       if (ret)
+               return ret;
        if (rdev->pm.num_power_states > 1) {
                /* where's the best place to put these? */
                ret = device_create_file(rdev->dev, &dev_attr_power_profile);
index 8293855..b3f9f1d 100644 (file)
@@ -316,6 +316,7 @@ rv515 0x6d40
 0x4BD0 FG_FOG_COLOR_B
 0x4BD4 FG_ALPHA_FUNC
 0x4BD8 FG_DEPTH_SRC
+0x4BE0 FG_ALPHA_VALUE
 0x4C00 US_ALU_CONST_R_0
 0x4C04 US_ALU_CONST_G_0
 0x4C08 US_ALU_CONST_B_0
index 437ac78..64d7f47 100644 (file)
@@ -737,7 +737,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
 
        if (ret) {
                DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret);
-               return NULL;
+               return ERR_PTR(ret);
        }
        return &vfb->base;
 
@@ -747,7 +747,7 @@ try_dmabuf:
        ret = vmw_user_dmabuf_lookup(tfile, mode_cmd->handle, &bo);
        if (ret) {
                DRM_ERROR("failed to find buffer: %i\n", ret);
-               return NULL;
+               return ERR_PTR(-ENOENT);
        }
 
        ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb,
@@ -758,7 +758,7 @@ try_dmabuf:
 
        if (ret) {
                DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret);
-               return NULL;
+               return ERR_PTR(ret);
        }
 
        return &vfb->base;
@@ -768,7 +768,7 @@ err_not_scanout:
        /* vmw_user_surface_lookup takes one ref */
        vmw_surface_unreference(&surface);
 
-       return NULL;
+       return ERR_PTR(-EINVAL);
 }
 
 static struct drm_mode_config_funcs vmw_kms_funcs = {
index cfaf690..2ff5cf7 100644 (file)
@@ -79,7 +79,7 @@ static void vmw_ldu_crtc_restore(struct drm_crtc *crtc)
 
 static void vmw_ldu_crtc_gamma_set(struct drm_crtc *crtc,
                                   u16 *r, u16 *g, u16 *b,
-                                  uint32_t size)
+                                  uint32_t start, uint32_t size)
 {
 }
 
index e2a4da7..2a512bc 100644 (file)
@@ -1075,7 +1075,6 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev,
        return ((dev->driver->driver_features & feature) ? 1 : 0);
 }
 
-
 static inline int drm_dev_to_irq(struct drm_device *dev)
 {
        if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE))
@@ -1084,11 +1083,22 @@ static inline int drm_dev_to_irq(struct drm_device *dev)
                return dev->pdev->irq;
 }
 
-#ifdef __alpha__
-#define drm_get_pci_domain(dev) dev->hose->index
-#else
-#define drm_get_pci_domain(dev) 0
-#endif
+static inline int drm_get_pci_domain(struct drm_device *dev)
+{
+       if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE))
+               return 0;
+
+#ifndef __alpha__
+       /* For historical reasons, drm_get_pci_domain() is busticated
+        * on most archs and has to remain so for userspace interface
+        * < 1.4, except on alpha which was right from the beginning
+        */
+       if (dev->if_version < 0x10004)
+               return 0;
+#endif /* __alpha__ */
+
+       return pci_domain_nr(dev->pdev->bus);
+}
 
 #if __OS_HAS_AGP
 static inline int drm_core_has_AGP(struct drm_device *dev)
index 3167390..4e75238 100644 (file)
@@ -27,7 +27,7 @@
 #define CORE_DATE              "20060810"
 
 #define DRM_IF_MAJOR   1
-#define DRM_IF_MINOR   3
+#define DRM_IF_MINOR   4
 
 #define CORE_MAJOR     1
 #define CORE_MINOR     1
index c707270..c9f3cc5 100644 (file)
@@ -189,49 +189,16 @@ enum subpixel_order {
  */
 struct drm_display_info {
        char name[DRM_DISPLAY_INFO_LEN];
-       /* Input info */
-       bool serration_vsync;
-       bool sync_on_green;
-       bool composite_sync;
-       bool separate_syncs;
-       bool blank_to_black;
-       unsigned char video_level;
-       bool digital;
+
        /* Physical size */
         unsigned int width_mm;
        unsigned int height_mm;
 
-       /* Display parameters */
-       unsigned char gamma; /* FIXME: storage format */
-       bool gtf_supported;
-       bool standard_color;
-       enum {
-               monochrome = 0,
-               rgb,
-               other,
-               unknown,
-       } display_type;
-       bool active_off_supported;
-       bool suspend_supported;
-       bool standby_supported;
-
-       /* Color info FIXME: storage format */
-       unsigned short redx, redy;
-       unsigned short greenx, greeny;
-       unsigned short bluex, bluey;
-       unsigned short whitex, whitey;
-
        /* Clock limits FIXME: storage format */
        unsigned int min_vfreq, max_vfreq;
        unsigned int min_hfreq, max_hfreq;
        unsigned int pixel_clock;
 
-       /* White point indices FIXME: storage format */
-       unsigned int wpx1, wpy1;
-       unsigned int wpgamma1;
-       unsigned int wpx2, wpy2;
-       unsigned int wpgamma2;
-
        enum subpixel_order subpixel_order;
 
        char *raw_edid; /* if any */
@@ -342,7 +309,7 @@ struct drm_crtc_funcs {
 
        /* Set gamma on the CRTC */
        void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
-                         uint32_t size);
+                         uint32_t start, uint32_t size);
        /* Object destroy routine */
        void (*destroy)(struct drm_crtc *crtc);
 
index 39e2cc5..5881fad 100644 (file)
 #define EDID_LENGTH 128
 #define DDC_ADDR 0x50
 
+#define CEA_EXT            0x02
+#define VTB_EXT            0x10
+#define DI_EXT     0x40
+#define LS_EXT     0x50
+#define MI_EXT     0x60
+
 struct est_timings {
        u8 t1;
        u8 t2;
index e0ea40f..0a6b3d5 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/slab.h>
 #include <asm/io.h>
 #include <asm/page.h>
-#include <asm/iomap.h>
 
 /*
  * The io_mapping mechanism provides an abstraction for mapping
@@ -33,6 +32,8 @@
 
 #ifdef CONFIG_HAVE_ATOMIC_IOMAP
 
+#include <asm/iomap.h>
+
 struct io_mapping {
        resource_size_t base;
        unsigned long size;
index 814f294..6228b5b 100644 (file)
@@ -31,7 +31,6 @@
 #ifndef LINUX_VGA_H
 #define LINUX_VGA_H
 
-#include <asm/vga.h>
 
 /* Legacy VGA regions */
 #define VGA_RSRC_NONE         0x00