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

1  2 
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_fb.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
include/drm/drm_crtc.h

index b9e4dbfa053308472b038d6e7c0e8b21bc12d072,7b1eb2fcf6165f0f916b922906eff6ed7b0a267a..7e31d4348340b10c9c4b39b0612e119335dc444c
@@@ -817,12 -817,12 +817,12 @@@ int drm_helper_resume_force_mode(struc
                                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 */
  }
  EXPORT_SYMBOL(drm_helper_resume_force_mode);
  
 -static struct slow_work_ops output_poll_ops;
 -
  #define DRM_OUTPUT_POLL_PERIOD (10*HZ)
 -static void output_poll_execute(struct slow_work *work)
 +static void output_poll_execute(struct work_struct *work)
  {
 -      struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
 -      struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_slow_work);
 +      struct delayed_work *delayed_work = to_delayed_work(work);
 +      struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work);
        struct drm_connector *connector;
        enum drm_connector_status old_status, status;
        bool repoll = false, changed = false;
 -      int ret;
  
        mutex_lock(&dev->mode_config.mutex);
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                        dev->mode_config.funcs->output_poll_changed(dev);
        }
  
 -      if (repoll) {
 -              ret = delayed_slow_work_enqueue(delayed_work, DRM_OUTPUT_POLL_PERIOD);
 -              if (ret)
 -                      DRM_ERROR("delayed enqueue failed %d\n", ret);
 -      }
 +      if (repoll)
 +              queue_delayed_work(system_nrt_wq, delayed_work, DRM_OUTPUT_POLL_PERIOD);
  }
  
  void drm_kms_helper_poll_disable(struct drm_device *dev)
  {
        if (!dev->mode_config.poll_enabled)
                return;
 -      delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
 +      cancel_delayed_work_sync(&dev->mode_config.output_poll_work);
  }
  EXPORT_SYMBOL(drm_kms_helper_poll_disable);
  
@@@ -889,20 -895,26 +889,20 @@@ void drm_kms_helper_poll_enable(struct 
  {
        bool poll = false;
        struct drm_connector *connector;
 -      int ret;
  
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                if (connector->polled)
                        poll = true;
        }
  
 -      if (poll) {
 -              ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD);
 -              if (ret)
 -                      DRM_ERROR("delayed enqueue failed %d\n", ret);
 -      }
 +      if (poll)
 +              queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD);
  }
  EXPORT_SYMBOL(drm_kms_helper_poll_enable);
  
  void drm_kms_helper_poll_init(struct drm_device *dev)
  {
 -      slow_work_register_user(THIS_MODULE);
 -      delayed_slow_work_init(&dev->mode_config.output_poll_slow_work,
 -                             &output_poll_ops);
 +      INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute);
        dev->mode_config.poll_enabled = true;
  
        drm_kms_helper_poll_enable(dev);
@@@ -912,6 -924,7 +912,6 @@@ EXPORT_SYMBOL(drm_kms_helper_poll_init)
  void drm_kms_helper_poll_fini(struct drm_device *dev)
  {
        drm_kms_helper_poll_disable(dev);
 -      slow_work_unregister_user(THIS_MODULE);
  }
  EXPORT_SYMBOL(drm_kms_helper_poll_fini);
  
@@@ -919,8 -932,12 +919,8 @@@ void drm_helper_hpd_irq_event(struct dr
  {
        if (!dev->mode_config.poll_enabled)
                return;
 -      delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
 -      /* schedule a slow work asap */
 -      delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, 0);
 +      /* kill timer and schedule immediate execution, this doesn't block */
 +      cancel_delayed_work(&dev->mode_config.output_poll_work);
 +      queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0);
  }
  EXPORT_SYMBOL(drm_helper_hpd_irq_event);
 -
 -static struct slow_work_ops output_poll_ops = {
 -      .execute = output_poll_execute,
 -};
index dce5c4a97f8d3d933791164abfdf0156e2badca5,6ac405534620cfd3bc1bdf2397b468f67c35018c..96e96310822513bfd9c984054a913eac7b5acc50
  #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 +387,6 @@@ static u32 edid_get_quirks(struct 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 +433,6 @@@ static void edid_fixup_preferred(struc
        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)
  {
@@@ -684,6 -456,46 +456,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)
  {
        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
@@@ -929,11 -753,13 +753,11 @@@ drm_mode_do_interlace_quirk(struct drm_
                { 1440,  576 },
                { 2880,  576 },
        };
 -      static const int n_sizes =
 -              sizeof(cea_interlaced)/sizeof(cea_interlaced[0]);
  
        if (!(pt->misc & DRM_EDID_PT_INTERLACED))
                return;
  
 -      for (i = 0; i < n_sizes; i++) {
 +      for (i = 0; i < ARRAY_SIZE(cea_interlaced); i++) {
                if ((mode->hdisplay == cea_interlaced[i].w) &&
                    (mode->vdisplay == cea_interlaced[i].h / 2)) {
                        mode->vdisplay *= 2;
@@@ -1047,117 -873,6 +871,6 @@@ static struct drm_display_mode *drm_mod
        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 -982,33 +980,33 @@@ drm_gtf_modes_for_range(struct drm_conn
        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)
  {
        for (i = 0; i < 6; i++) {
                for (j = 7; j > 0; j--) {
                        m = (i * 8) + (7 - j);
 -                      if (m >= num_est3_modes)
 +                      if (m >= ARRAY_SIZE(est3_modes))
                                break;
                        if (est[i] & (1 << j)) {
                                mode = drm_mode_find_dmt(connector->dev,
        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;
                                               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 -1362,21 +1360,21 @@@ int drm_add_edid_modes(struct drm_conne
         * - 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;
  }
index 1e5e0d379fa9a684670a073adfffcc0f6fbee338,6bb5ffc76ced351406882420856b0ec1ff1564d3..5ec10e02341b44f6fa5b6ebe6c6e9f78bd9f2ad2
@@@ -980,10 -980,7 +980,10 @@@ voi
  intel_wait_for_vblank(struct drm_device *dev)
  {
        /* Wait for 20ms, i.e. one cycle at 50hz. */
 -      msleep(20);
 +      if (in_dbg_master())
 +              mdelay(20); /* The kernel debugger cannot call msleep() */
 +      else
 +              msleep(20);
  }
  
  /* Parameters have changed, update FBC info */
@@@ -1317,10 -1314,6 +1317,10 @@@ static void intel_update_fbc(struct drm
                goto out_disable;
        }
  
 +      /* If the kernel debugger is active, always disable compression */
 +      if (in_dbg_master())
 +              goto out_disable;
 +
        if (intel_fbc_enabled(dev)) {
                /* We can re-enable it in this case, but need to update pitch */
                if ((fb->pitch > dev_priv->cfb_pitch) ||
@@@ -1392,98 -1385,6 +1392,98 @@@ intel_pin_and_fence_fb_obj(struct drm_d
        return 0;
  }
  
 +/* Assume fb object is pinned & idle & fenced and just update base pointers */
 +static int
 +intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 +                         int x, int y)
 +{
 +      struct drm_device *dev = crtc->dev;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 +      struct intel_framebuffer *intel_fb;
 +      struct drm_i915_gem_object *obj_priv;
 +      struct drm_gem_object *obj;
 +      int plane = intel_crtc->plane;
 +      unsigned long Start, Offset;
 +      int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR);
 +      int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF);
 +      int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
 +      int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF);
 +      int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
 +      u32 dspcntr;
 +
 +      switch (plane) {
 +      case 0:
 +      case 1:
 +              break;
 +      default:
 +              DRM_ERROR("Can't update plane %d in SAREA\n", plane);
 +              return -EINVAL;
 +      }
 +
 +      intel_fb = to_intel_framebuffer(fb);
 +      obj = intel_fb->obj;
 +      obj_priv = to_intel_bo(obj);
 +
 +      dspcntr = I915_READ(dspcntr_reg);
 +      /* Mask out pixel format bits in case we change it */
 +      dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
 +      switch (fb->bits_per_pixel) {
 +      case 8:
 +              dspcntr |= DISPPLANE_8BPP;
 +              break;
 +      case 16:
 +              if (fb->depth == 15)
 +                      dspcntr |= DISPPLANE_15_16BPP;
 +              else
 +                      dspcntr |= DISPPLANE_16BPP;
 +              break;
 +      case 24:
 +      case 32:
 +              dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
 +              break;
 +      default:
 +              DRM_ERROR("Unknown color depth\n");
 +              return -EINVAL;
 +      }
 +      if (IS_I965G(dev)) {
 +              if (obj_priv->tiling_mode != I915_TILING_NONE)
 +                      dspcntr |= DISPPLANE_TILED;
 +              else
 +                      dspcntr &= ~DISPPLANE_TILED;
 +      }
 +
 +      if (IS_IRONLAKE(dev))
 +              /* must disable */
 +              dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 +
 +      I915_WRITE(dspcntr_reg, dspcntr);
 +
 +      Start = obj_priv->gtt_offset;
 +      Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
 +
 +      DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y);
 +      I915_WRITE(dspstride, fb->pitch);
 +      if (IS_I965G(dev)) {
 +              I915_WRITE(dspbase, Offset);
 +              I915_READ(dspbase);
 +              I915_WRITE(dspsurf, Start);
 +              I915_READ(dspsurf);
 +              I915_WRITE(dsptileoff, (y << 16) | x);
 +      } else {
 +              I915_WRITE(dspbase, Start + Offset);
 +              I915_READ(dspbase);
 +      }
 +
 +      if ((IS_I965G(dev) || plane == 0))
 +              intel_update_fbc(crtc, &crtc->mode);
 +
 +      intel_wait_for_vblank(dev);
 +      intel_increase_pllclock(crtc, true);
 +
 +      return 0;
 +}
 +
  static int
  intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                    struct drm_framebuffer *old_fb)
@@@ -4429,15 -4330,12 +4429,12 @@@ void intel_crtc_fb_gamma_get(struct drm
  }
  
  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;
@@@ -5142,7 -5040,6 +5139,7 @@@ static const struct drm_crtc_helper_fun
        .mode_fixup = intel_crtc_mode_fixup,
        .mode_set = intel_crtc_mode_set,
        .mode_set_base = intel_pipe_set_base,
 +      .mode_set_base_atomic = intel_pipe_set_base_atomic,
        .prepare = intel_crtc_prepare,
        .commit = intel_crtc_commit,
        .load_lut = intel_crtc_load_lut,
@@@ -5412,18 -5309,18 +5409,18 @@@ intel_user_framebuffer_create(struct dr
  
        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 a79525f434a8fae8a4654927050f285ff49f20e0,1d2d67ce4a8467b9885d1dd808ff07fb82abdb01..7bdc96256bf55b6e87d102377b428a871792be91
@@@ -61,8 -61,6 +61,8 @@@ static struct fb_ops intelfb_ops = 
        .fb_pan_display = drm_fb_helper_pan_display,
        .fb_blank = drm_fb_helper_blank,
        .fb_setcmap = drm_fb_helper_setcmap,
 +      .fb_debug_enter = drm_fb_helper_debug_enter,
 +      .fb_debug_leave = drm_fb_helper_debug_leave,
  };
  
  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;
  
  
        strcpy(info->fix.id, "inteldrmfb");
  
 -      info->flags = FBINFO_DEFAULT;
 +      info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
        info->fbops = &intelfb_ops;
  
        /* setup aperture base/size for vesafb takeover */
        info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset;
        info->fix.smem_len = size;
  
 -      info->flags = FBINFO_DEFAULT;
 -
        info->screen_base = ioremap_wc(dev->agp->base + obj_priv->gtt_offset,
                                       size);
        if (!info->screen_base) {
index 099f637264aa7ba8b39e6a22977c570a6b213a20,11f13fc46971564bcecaa7ad3495fd1792ea7e39..dbd30b2e43fd13b39aaa59eb0abc4fb0332bd1ee
@@@ -250,7 -250,6 +250,7 @@@ nouveau_fbcon_create(struct nouveau_fbd
                info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
                              FBINFO_HWACCEL_FILLRECT |
                              FBINFO_HWACCEL_IMAGEBLIT;
 +      info->flags |= FBINFO_CAN_FORCE_OUTPUT;
        info->fbops = &nouveau_fbcon_ops;
        info->fix.smem_start = dev->mode_config.fb_base + nvbo->bo.offset -
                               dev_priv->vm_vram_base;
  
        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;
diff --combined include/drm/drm_crtc.h
index c707270bff5afef28538471ef1ee39feb9d5ce31,692cc55eeab69b1522fa5b72abe6c0cc5107061b..c9f3cc5949a82eb0ae5ba4b463891df5f96806dd
@@@ -31,6 -31,7 +31,6 @@@
  #include <linux/idr.h>
  
  #include <linux/fb.h>
 -#include <linux/slow-work.h>
  
  struct drm_device;
  struct drm_mode_set;
@@@ -189,49 -190,16 +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 -310,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);
  
@@@ -594,7 -562,7 +561,7 @@@ struct drm_mode_config 
  
        /* output poll support */
        bool poll_enabled;
 -      struct delayed_slow_work output_poll_slow_work;
 +      struct delayed_work output_poll_work;
  
        /* pointers to standard properties */
        struct list_head property_blob_list;