Merge branch 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 4 Mar 2010 15:49:37 +0000 (07:49 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 4 Mar 2010 15:49:37 +0000 (07:49 -0800)
* 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (151 commits)
  vga_switcheroo: disable default y by new rules.
  drm/nouveau: fix *staging* driver build with switcheroo off.
  drm/radeon: fix typo in Makefile
  vga_switcheroo: fix build on platforms with no ACPI
  drm/radeon: Fix printf type warning in 64bit system.
  drm/radeon/kms: bump the KMS version number for square tiling support.
  vga_switcheroo: initial implementation (v15)
  drm/radeon/kms: do not disable audio engine twice
  Revert "drm/radeon/kms: disable HDMI audio for now on rv710/rv730"
  drm/radeon/kms: do not preset audio stuff and start timer when not using audio
  drm/radeon: r100/r200 ums: block ability for userspace app to trash 0 page and beyond
  drm/ttm: fix function prototype to match implementation
  drm/radeon: use ALIGN instead of open coding it
  drm/radeon/kms: initialize set_surface_reg reg for rs600 asic
  drm/i915: Use a dmi quirk to skip a broken SDVO TV output.
  drm/i915: enable/disable LVDS port at DPMS time
  drm/i915: check for multiple write domains in pin_and_relocate
  drm/i915: clean-up i915_gem_flush_gpu_write_domain
  drm/i915: reuse i915_gpu_idle helper
  drm/i915: ensure lru ordering of fence_list
  ...

Fixed trivial conflicts in drivers/gpu/vga/Kconfig

1  2 
drivers/char/agp/intel-agp.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/vga/Kconfig

@@@ -8,9 -8,11 +8,12 @@@
  #include <linux/kernel.h>
  #include <linux/pagemap.h>
  #include <linux/agp_backend.h>
 +#include <asm/smp.h>
  #include "agp.h"
  
+ int intel_agp_enabled;
+ EXPORT_SYMBOL(intel_agp_enabled);
  /*
   * If we have Intel graphics, we're not going to have anything other than
   * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
  #define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB        0x0062
  #define PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB    0x006a
  #define PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG         0x0046
+ #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB  0x0100
+ #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG  0x0102
+ #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB  0x0104
+ #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG  0x0106
  
  /* cover 915 and 945 variants */
  #define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \
                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \
                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB)
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
  
  extern int agp_memory_reserved;
  
  #define INTEL_I7505_AGPCTRL   0x70
  #define INTEL_I7505_MCHCFG    0x50
  
+ #define SNB_GMCH_CTRL 0x50
+ #define SNB_GMCH_GMS_STOLEN_MASK      0xF8
+ #define SNB_GMCH_GMS_STOLEN_32M               (1 << 3)
+ #define SNB_GMCH_GMS_STOLEN_64M               (2 << 3)
+ #define SNB_GMCH_GMS_STOLEN_96M               (3 << 3)
+ #define SNB_GMCH_GMS_STOLEN_128M      (4 << 3)
+ #define SNB_GMCH_GMS_STOLEN_160M      (5 << 3)
+ #define SNB_GMCH_GMS_STOLEN_192M      (6 << 3)
+ #define SNB_GMCH_GMS_STOLEN_224M      (7 << 3)
+ #define SNB_GMCH_GMS_STOLEN_256M      (8 << 3)
+ #define SNB_GMCH_GMS_STOLEN_288M      (9 << 3)
+ #define SNB_GMCH_GMS_STOLEN_320M      (0xa << 3)
+ #define SNB_GMCH_GMS_STOLEN_352M      (0xb << 3)
+ #define SNB_GMCH_GMS_STOLEN_384M      (0xc << 3)
+ #define SNB_GMCH_GMS_STOLEN_416M      (0xd << 3)
+ #define SNB_GMCH_GMS_STOLEN_448M      (0xe << 3)
+ #define SNB_GMCH_GMS_STOLEN_480M      (0xf << 3)
+ #define SNB_GMCH_GMS_STOLEN_512M      (0x10 << 3)
  static const struct aper_size_info_fixed intel_i810_sizes[] =
  {
        {64, 16384, 4},
@@@ -294,6 -321,13 +322,13 @@@ static void intel_agp_insert_sg_entries
                                        off_t pg_start, int mask_type)
  {
        int i, j;
+       u32 cache_bits = 0;
+       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
+           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
+       {
+               cache_bits = I830_PTE_SYSTEM_CACHED;
+       }
  
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
                writel(agp_bridge->driver->mask_memory(agp_bridge,
@@@ -614,7 -648,7 +649,7 @@@ static struct aper_size_info_fixed inte
  static void intel_i830_init_gtt_entries(void)
  {
        u16 gmch_ctrl;
-       int gtt_entries;
+       int gtt_entries = 0;
        u8 rdct;
        int local = 0;
        static const int ddt[4] = { 0, 16, 32, 64 };
                        gtt_entries = 0;
                        break;
                }
+       } else if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
+                  agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) {
+               /*
+                * SandyBridge has new memory control reg at 0x50.w
+                */
+               u16 snb_gmch_ctl;
+               pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+               switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
+               case SNB_GMCH_GMS_STOLEN_32M:
+                       gtt_entries = MB(32) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_64M:
+                       gtt_entries = MB(64) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_96M:
+                       gtt_entries = MB(96) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_128M:
+                       gtt_entries = MB(128) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_160M:
+                       gtt_entries = MB(160) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_192M:
+                       gtt_entries = MB(192) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_224M:
+                       gtt_entries = MB(224) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_256M:
+                       gtt_entries = MB(256) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_288M:
+                       gtt_entries = MB(288) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_320M:
+                       gtt_entries = MB(320) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_352M:
+                       gtt_entries = MB(352) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_384M:
+                       gtt_entries = MB(384) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_416M:
+                       gtt_entries = MB(416) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_448M:
+                       gtt_entries = MB(448) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_480M:
+                       gtt_entries = MB(480) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_512M:
+                       gtt_entries = MB(512) - KB(size);
+                       break;
+               }
        } else {
                switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
                case I855_GMCH_GMS_STOLEN_1M:
@@@ -816,6 -907,12 +908,6 @@@ static void intel_i830_setup_flush(void
                intel_i830_fini_flush();
  }
  
 -static void
 -do_wbinvd(void *null)
 -{
 -      wbinvd();
 -}
 -
  /* The chipset_flush interface needs to get data that has already been
   * flushed out of the CPU all the way out to main memory, because the GPU
   * doesn't snoop those buffers.
@@@ -832,10 -929,12 +924,10 @@@ static void intel_i830_chipset_flush(st
  
        memset(pg, 0, 1024);
  
 -      if (cpu_has_clflush) {
 +      if (cpu_has_clflush)
                clflush_cache_range(pg, 1024);
 -      } else {
 -              if (on_each_cpu(do_wbinvd, NULL, 1) != 0)
 -                      printk(KERN_ERR "Timed out waiting for cache flush.\n");
 -      }
 +      else if (wbinvd_on_all_cpus() != 0)
 +              printk(KERN_ERR "Timed out waiting for cache flush.\n");
  }
  
  /* The intel i830 automatically initializes the agp aperture during POST.
@@@ -1357,6 -1456,8 +1449,8 @@@ static void intel_i965_get_gtt_range(in
        case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB:
        case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB:
        case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB:
+       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB:
+       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB:
                *gtt_offset = *gtt_size = MB(2);
                break;
        default:
@@@ -2338,9 -2439,9 +2432,9 @@@ static const struct intel_driver_descri
                NULL, &intel_g33_driver },
        { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33",
                NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, 0, "Pineview",
+       { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, 0, "GMA3150",
                NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, 0, "Pineview",
+       { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, 0, "GMA3150",
                NULL, &intel_g33_driver },
        { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, 0,
            "GM45", NULL, &intel_i965_driver },
        { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0,
            "G41", NULL, &intel_i965_driver },
        { PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 0,
-           "Ironlake/D", NULL, &intel_i965_driver },
+           "HD Graphics", NULL, &intel_i965_driver },
        { PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
-           "Ironlake/M", NULL, &intel_i965_driver },
+           "HD Graphics", NULL, &intel_i965_driver },
        { PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
-           "Ironlake/MA", NULL, &intel_i965_driver },
+           "HD Graphics", NULL, &intel_i965_driver },
        { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
-           "Ironlake/MC2", NULL, &intel_i965_driver },
+           "HD Graphics", NULL, &intel_i965_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG, 0,
+           "Sandybridge", NULL, &intel_i965_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG, 0,
+           "Sandybridge", NULL, &intel_i965_driver },
        { 0, 0, 0, NULL, NULL, NULL }
  };
  
@@@ -2371,7 -2476,7 +2469,7 @@@ static int __devinit agp_intel_probe(st
        struct agp_bridge_data *bridge;
        u8 cap_ptr = 0;
        struct resource *r;
-       int i;
+       int i, err;
  
        cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
  
        }
  
        pci_set_drvdata(pdev, bridge);
-       return agp_add_bridge(bridge);
+       err = agp_add_bridge(bridge);
+       if (!err)
+               intel_agp_enabled = 1;
+       return err;
  }
  
  static void __devexit agp_intel_remove(struct pci_dev *pdev)
@@@ -2568,6 -2676,8 +2669,8 @@@ static struct pci_device_id agp_intel_p
        ID(PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB),
        ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB),
        ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB),
+       ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB),
+       ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB),
        { }
  };
  
@@@ -150,6 -150,9 +150,9 @@@ static uint16_t combios_get_table_offse
        int rev;
        uint16_t offset = 0, check_offset;
  
+       if (!rdev->bios)
+               return 0;
        switch (table) {
                /* absolute offset tables */
        case COMBIOS_ASIC_INIT_1_TABLE:
  
  }
  
+ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
+ {
+       int edid_info;
+       struct edid *edid;
+       edid_info = combios_get_table_offset(rdev->ddev, COMBIOS_HARDCODED_EDID_TABLE);
+       if (!edid_info)
+               return false;
+       edid = kmalloc(EDID_LENGTH * (DRM_MAX_EDID_EXT_NUM + 1),
+                      GFP_KERNEL);
+       if (edid == NULL)
+               return false;
+       memcpy((unsigned char *)edid,
+              (unsigned char *)(rdev->bios + edid_info), EDID_LENGTH);
+       if (!drm_edid_is_valid(edid)) {
+               kfree(edid);
+               return false;
+       }
+       rdev->mode_info.bios_hardcoded_edid = edid;
+       return true;
+ }
+ struct edid *
+ radeon_combios_get_hardcoded_edid(struct radeon_device *rdev)
+ {
+       if (rdev->mode_info.bios_hardcoded_edid)
+               return rdev->mode_info.bios_hardcoded_edid;
+       return NULL;
+ }
  static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rdev,
                                                       int ddc_line)
  {
                i2c.y_data_reg = ddc_line;
        }
  
-       if (rdev->family < CHIP_R200)
-               i2c.hw_capable = false;
-       else {
+       switch (rdev->family) {
+       case CHIP_R100:
+       case CHIP_RV100:
+       case CHIP_RS100:
+       case CHIP_RV200:
+       case CHIP_RS200:
+       case CHIP_RS300:
+               switch (ddc_line) {
+               case RADEON_GPIO_DVI_DDC:
+                       /* in theory this should be hw capable,
+                        * but it doesn't seem to work
+                        */
+                       i2c.hw_capable = false;
+                       break;
+               default:
+                       i2c.hw_capable = false;
+                       break;
+               }
+               break;
+       case CHIP_R200:
+               switch (ddc_line) {
+               case RADEON_GPIO_DVI_DDC:
+               case RADEON_GPIO_MONID:
+                       i2c.hw_capable = true;
+                       break;
+               default:
+                       i2c.hw_capable = false;
+                       break;
+               }
+               break;
+       case CHIP_RV250:
+       case CHIP_RV280:
+               switch (ddc_line) {
+               case RADEON_GPIO_VGA_DDC:
+               case RADEON_GPIO_DVI_DDC:
+               case RADEON_GPIO_CRT2_DDC:
+                       i2c.hw_capable = true;
+                       break;
+               default:
+                       i2c.hw_capable = false;
+                       break;
+               }
+               break;
+       case CHIP_R300:
+       case CHIP_R350:
+               switch (ddc_line) {
+               case RADEON_GPIO_VGA_DDC:
+               case RADEON_GPIO_DVI_DDC:
+                       i2c.hw_capable = true;
+                       break;
+               default:
+                       i2c.hw_capable = false;
+                       break;
+               }
+               break;
+       case CHIP_RV350:
+       case CHIP_RV380:
+       case CHIP_RS400:
+       case CHIP_RS480:
                switch (ddc_line) {
                case RADEON_GPIO_VGA_DDC:
                case RADEON_GPIO_DVI_DDC:
                        i2c.hw_capable = false;
                        break;
                }
+               break;
+       default:
+               i2c.hw_capable = false;
+               break;
        }
        i2c.mm_i2c = false;
        i2c.i2c_id = 0;
+       i2c.hpd_id = 0;
  
        if (ddc_line)
                i2c.valid = true;
@@@ -527,9 -624,6 +624,6 @@@ bool radeon_combios_get_clock_info(stru
        int8_t rev;
        uint16_t sclk, mclk;
  
-       if (rdev->bios == NULL)
-               return false;
        pll_info = combios_get_table_offset(dev, COMBIOS_PLL_INFO_TABLE);
        if (pll_info) {
                rev = RBIOS8(pll_info);
@@@ -654,9 -748,6 +748,6 @@@ struct radeon_encoder_primary_dac *rade
        if (!p_dac)
                return NULL;
  
-       if (rdev->bios == NULL)
-               goto out;
        /* check CRT table */
        dac_info = combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE);
        if (dac_info) {
                found = 1;
        }
  
- out:
        if (!found) /* fallback to defaults */
                radeon_legacy_get_primary_dac_info_from_table(rdev, p_dac);
  
@@@ -687,9 -777,6 +777,6 @@@ radeon_combios_get_tv_info(struct radeo
        uint16_t tv_info;
        enum radeon_tv_std tv_std = TV_STD_NTSC;
  
-       if (rdev->bios == NULL)
-               return tv_std;
        tv_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE);
        if (tv_info) {
                if (RBIOS8(tv_info + 6) == 'T') {
@@@ -793,9 -880,6 +880,6 @@@ struct radeon_encoder_tv_dac *radeon_co
        if (!tv_dac)
                return NULL;
  
-       if (rdev->bios == NULL)
-               goto out;
        /* first check TV table */
        dac_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE);
        if (dac_info) {
                }
        }
  
- out:
        if (!found) /* fallback to defaults */
                radeon_legacy_get_tv_dac_info_from_table(rdev, tv_dac);
  
@@@ -945,11 -1028,6 +1028,6 @@@ struct radeon_encoder_lvds *radeon_comb
        int tmp, i;
        struct radeon_encoder_lvds *lvds = NULL;
  
-       if (rdev->bios == NULL) {
-               lvds = radeon_legacy_get_lvds_info_from_regs(rdev);
-               goto out;
-       }
        lcd_info = combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE);
  
        if (lcd_info) {
                DRM_INFO("No panel info found in BIOS\n");
                lvds = radeon_legacy_get_lvds_info_from_regs(rdev);
        }
- out:
        if (lvds)
                encoder->native_mode = lvds->native_mode;
        return lvds;
@@@ -1102,9 -1180,6 +1180,6 @@@ bool radeon_legacy_get_tmds_info_from_c
        int i, n;
        uint8_t ver;
  
-       if (rdev->bios == NULL)
-               return false;
        tmds_info = combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE);
  
        if (tmds_info) {
@@@ -1184,9 -1259,6 +1259,6 @@@ bool radeon_legacy_get_ext_tmds_info_fr
        enum radeon_combios_ddc gpio;
        struct radeon_i2c_bus_rec i2c_bus;
  
-       if (rdev->bios == NULL)
-               return false;
        tmds->i2c_bus = NULL;
        if (rdev->flags & RADEON_IS_IGP) {
                offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE);
                                tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
                                break;
                        case DDC_LCD: /* MM i2c */
-                               DRM_ERROR("MM i2c requires hw i2c engine\n");
+                               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);
@@@ -1279,47 -1354,47 +1354,47 @@@ bool radeon_get_legacy_connector_info_f
        rdev->mode_info.connector_table = radeon_connector_table;
        if (rdev->mode_info.connector_table == CT_NONE) {
  #ifdef CONFIG_PPC_PMAC
 -              if (machine_is_compatible("PowerBook3,3")) {
 +              if (of_machine_is_compatible("PowerBook3,3")) {
                        /* powerbook with VGA */
                        rdev->mode_info.connector_table = CT_POWERBOOK_VGA;
 -              } else if (machine_is_compatible("PowerBook3,4") ||
 -                         machine_is_compatible("PowerBook3,5")) {
 +              } else if (of_machine_is_compatible("PowerBook3,4") ||
 +                         of_machine_is_compatible("PowerBook3,5")) {
                        /* powerbook with internal tmds */
                        rdev->mode_info.connector_table = CT_POWERBOOK_INTERNAL;
 -              } else if (machine_is_compatible("PowerBook5,1") ||
 -                         machine_is_compatible("PowerBook5,2") ||
 -                         machine_is_compatible("PowerBook5,3") ||
 -                         machine_is_compatible("PowerBook5,4") ||
 -                         machine_is_compatible("PowerBook5,5")) {
 +              } else if (of_machine_is_compatible("PowerBook5,1") ||
 +                         of_machine_is_compatible("PowerBook5,2") ||
 +                         of_machine_is_compatible("PowerBook5,3") ||
 +                         of_machine_is_compatible("PowerBook5,4") ||
 +                         of_machine_is_compatible("PowerBook5,5")) {
                        /* powerbook with external single link tmds (sil164) */
                        rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL;
 -              } else if (machine_is_compatible("PowerBook5,6")) {
 +              } else if (of_machine_is_compatible("PowerBook5,6")) {
                        /* powerbook with external dual or single link tmds */
                        rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL;
 -              } else if (machine_is_compatible("PowerBook5,7") ||
 -                         machine_is_compatible("PowerBook5,8") ||
 -                         machine_is_compatible("PowerBook5,9")) {
 +              } else if (of_machine_is_compatible("PowerBook5,7") ||
 +                         of_machine_is_compatible("PowerBook5,8") ||
 +                         of_machine_is_compatible("PowerBook5,9")) {
                        /* PowerBook6,2 ? */
                        /* powerbook with external dual link tmds (sil1178?) */
                        rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL;
 -              } else if (machine_is_compatible("PowerBook4,1") ||
 -                         machine_is_compatible("PowerBook4,2") ||
 -                         machine_is_compatible("PowerBook4,3") ||
 -                         machine_is_compatible("PowerBook6,3") ||
 -                         machine_is_compatible("PowerBook6,5") ||
 -                         machine_is_compatible("PowerBook6,7")) {
 +              } else if (of_machine_is_compatible("PowerBook4,1") ||
 +                         of_machine_is_compatible("PowerBook4,2") ||
 +                         of_machine_is_compatible("PowerBook4,3") ||
 +                         of_machine_is_compatible("PowerBook6,3") ||
 +                         of_machine_is_compatible("PowerBook6,5") ||
 +                         of_machine_is_compatible("PowerBook6,7")) {
                        /* ibook */
                        rdev->mode_info.connector_table = CT_IBOOK;
 -              } else if (machine_is_compatible("PowerMac4,4")) {
 +              } else if (of_machine_is_compatible("PowerMac4,4")) {
                        /* emac */
                        rdev->mode_info.connector_table = CT_EMAC;
 -              } else if (machine_is_compatible("PowerMac10,1")) {
 +              } else if (of_machine_is_compatible("PowerMac10,1")) {
                        /* mini with internal tmds */
                        rdev->mode_info.connector_table = CT_MINI_INTERNAL;
 -              } else if (machine_is_compatible("PowerMac10,2")) {
 +              } else if (of_machine_is_compatible("PowerMac10,2")) {
                        /* mini with external tmds */
                        rdev->mode_info.connector_table = CT_MINI_EXTERNAL;
 -              } else if (machine_is_compatible("PowerMac12,1")) {
 +              } else if (of_machine_is_compatible("PowerMac12,1")) {
                        /* PowerMac8,1 ? */
                        /* imac g5 isight */
                        rdev->mode_info.connector_table = CT_IMAC_G5_ISIGHT;
@@@ -1909,9 -1984,6 +1984,6 @@@ bool radeon_get_legacy_connector_info_f
        struct radeon_i2c_bus_rec ddc_i2c;
        struct radeon_hpd hpd;
  
-       if (rdev->bios == NULL)
-               return false;
        conn_info = combios_get_table_offset(dev, COMBIOS_CONNECTOR_INFO_TABLE);
        if (conn_info) {
                for (i = 0; i < 4; i++) {
        return true;
  }
  
+ void radeon_combios_get_power_modes(struct radeon_device *rdev)
+ {
+       struct drm_device *dev = rdev->ddev;
+       u16 offset, misc, misc2 = 0;
+       u8 rev, blocks, tmp;
+       int state_index = 0;
+       rdev->pm.default_power_state = NULL;
+       if (rdev->flags & RADEON_IS_MOBILITY) {
+               offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE);
+               if (offset) {
+                       rev = RBIOS8(offset);
+                       blocks = RBIOS8(offset + 0x2);
+                       /* power mode 0 tends to be the only valid one */
+                       rdev->pm.power_state[state_index].num_clock_modes = 1;
+                       rdev->pm.power_state[state_index].clock_info[0].mclk = RBIOS32(offset + 0x5 + 0x2);
+                       rdev->pm.power_state[state_index].clock_info[0].sclk = RBIOS32(offset + 0x5 + 0x6);
+                       if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
+                           (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
+                               goto default_mode;
+                       /* skip overclock modes for now */
+                       if ((rdev->pm.power_state[state_index].clock_info[0].mclk >
+                            rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
+                           (rdev->pm.power_state[state_index].clock_info[0].sclk >
+                            rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
+                               goto default_mode;
+                       rdev->pm.power_state[state_index].type =
+                               POWER_STATE_TYPE_BATTERY;
+                       misc = RBIOS16(offset + 0x5 + 0x0);
+                       if (rev > 4)
+                               misc2 = RBIOS16(offset + 0x5 + 0xe);
+                       if (misc & 0x4) {
+                               rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO;
+                               if (misc & 0x8)
+                                       rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+                                               true;
+                               else
+                                       rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+                                               false;
+                               rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.valid = true;
+                               if (rev < 6) {
+                                       rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.reg =
+                                               RBIOS16(offset + 0x5 + 0xb) * 4;
+                                       tmp = RBIOS8(offset + 0x5 + 0xd);
+                                       rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.mask = (1 << tmp);
+                               } else {
+                                       u8 entries = RBIOS8(offset + 0x5 + 0xb);
+                                       u16 voltage_table_offset = RBIOS16(offset + 0x5 + 0xc);
+                                       if (entries && voltage_table_offset) {
+                                               rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.reg =
+                                                       RBIOS16(voltage_table_offset) * 4;
+                                               tmp = RBIOS8(voltage_table_offset + 0x2);
+                                               rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.mask = (1 << tmp);
+                                       } else
+                                               rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.valid = false;
+                               }
+                               switch ((misc2 & 0x700) >> 8) {
+                               case 0:
+                               default:
+                                       rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 0;
+                                       break;
+                               case 1:
+                                       rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 33;
+                                       break;
+                               case 2:
+                                       rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 66;
+                                       break;
+                               case 3:
+                                       rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 99;
+                                       break;
+                               case 4:
+                                       rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 132;
+                                       break;
+                               }
+                       } else
+                               rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
+                       if (rev > 6)
+                               rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
+                                       RBIOS8(offset + 0x5 + 0x10);
+                       state_index++;
+               } else {
+                       /* XXX figure out some good default low power mode for mobility cards w/out power tables */
+               }
+       } else {
+               /* XXX figure out some good default low power mode for desktop cards */
+       }
+ default_mode:
+       /* add the default mode */
+       rdev->pm.power_state[state_index].type =
+               POWER_STATE_TYPE_DEFAULT;
+       rdev->pm.power_state[state_index].num_clock_modes = 1;
+       rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
+       rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
+       rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0];
+       rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
+       if (rdev->asic->get_pcie_lanes)
+               rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev);
+       else
+               rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16;
+       rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
+       rdev->pm.num_power_states = state_index + 1;
+       rdev->pm.current_power_state = rdev->pm.default_power_state;
+       rdev->pm.current_clock_mode =
+               rdev->pm.default_power_state->default_clock_mode;
+ }
  void radeon_external_tmds_setup(struct drm_encoder *encoder)
  {
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        switch (tmds->dvo_chip) {
        case DVO_SIL164:
                /* sil 164 */
-               radeon_i2c_do_lock(tmds->i2c_bus, 1);
-               radeon_i2c_sw_put_byte(tmds->i2c_bus,
-                                      tmds->slave_addr,
-                                      0x08, 0x30);
-               radeon_i2c_sw_put_byte(tmds->i2c_bus,
+               radeon_i2c_put_byte(tmds->i2c_bus,
+                                   tmds->slave_addr,
+                                   0x08, 0x30);
+               radeon_i2c_put_byte(tmds->i2c_bus,
                                       tmds->slave_addr,
                                       0x09, 0x00);
-               radeon_i2c_sw_put_byte(tmds->i2c_bus,
-                                      tmds->slave_addr,
-                                      0x0a, 0x90);
-               radeon_i2c_sw_put_byte(tmds->i2c_bus,
-                                      tmds->slave_addr,
-                                      0x0c, 0x89);
-               radeon_i2c_sw_put_byte(tmds->i2c_bus,
+               radeon_i2c_put_byte(tmds->i2c_bus,
+                                   tmds->slave_addr,
+                                   0x0a, 0x90);
+               radeon_i2c_put_byte(tmds->i2c_bus,
+                                   tmds->slave_addr,
+                                   0x0c, 0x89);
+               radeon_i2c_put_byte(tmds->i2c_bus,
                                       tmds->slave_addr,
                                       0x08, 0x3b);
-               radeon_i2c_do_lock(tmds->i2c_bus, 0);
                break;
        case DVO_SIL1178:
                /* sil 1178 - untested */
@@@ -2338,9 -2517,6 +2517,6 @@@ bool radeon_combios_external_tmds_setup
        uint32_t reg, val, and_mask, or_mask;
        struct radeon_encoder_ext_tmds *tmds = radeon_encoder->enc_priv;
  
-       if (rdev->bios == NULL)
-               return false;
        if (!tmds)
                return false;
  
                                                index++;
                                                val = RBIOS8(index);
                                                index++;
-                                               radeon_i2c_do_lock(tmds->i2c_bus, 1);
-                                               radeon_i2c_sw_put_byte(tmds->i2c_bus,
-                                                                      slave_addr,
-                                                                      reg, val);
-                                               radeon_i2c_do_lock(tmds->i2c_bus, 0);
+                                               radeon_i2c_put_byte(tmds->i2c_bus,
+                                                                   slave_addr,
+                                                                   reg, val);
                                                break;
                                        default:
                                                DRM_ERROR("Unknown id %d\n", id >> 13);
                                        reg = id & 0x1fff;
                                        val = RBIOS8(index);
                                        index += 1;
-                                       radeon_i2c_do_lock(tmds->i2c_bus, 1);
-                                       radeon_i2c_sw_put_byte(tmds->i2c_bus,
-                                                              tmds->slave_addr,
-                                                              reg, val);
-                                       radeon_i2c_do_lock(tmds->i2c_bus, 0);
+                                       radeon_i2c_put_byte(tmds->i2c_bus,
+                                                           tmds->slave_addr,
+                                                           reg, val);
                                        break;
                                default:
                                        DRM_ERROR("Unknown id %d\n", id >> 13);
diff --combined drivers/gpu/vga/Kconfig
@@@ -9,10 -9,14 +9,21 @@@ config VGA_AR
          see Documentation/vgaarbiter.txt for more details. Select this to
          enable VGA arbiter.
  
 -
 +config VGA_ARB_MAX_GPUS
 +      int "Maximum number of GPUs"
 +      default 16
 +      depends on VGA_ARB
 +      help
 +        Reserves space in the kernel to maintain resource locking for
 +        multiple GPUS.  The overhead for each GPU is very small.
++
+ config VGA_SWITCHEROO
+       bool "Laptop Hybrid Grapics - GPU switching support"
+       depends on X86
+       depends on ACPI
+       help
+         Many laptops released in 2008/9/10 have two gpus with a multiplxer
+         to switch between them. This adds support for dynamic switching when
+           X isn't running and delayed switching until the next logoff. This
+         features is called hybrid graphics, ATI PowerXpress, and Nvidia
+         HybridPower.