Merge branch 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
Linus Torvalds [Mon, 21 Sep 2009 15:10:09 +0000 (08:10 -0700)]
* 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (133 commits)
  drm/vgaarb: add VGA arbitration support to the drm and kms.
  drm/radeon: some r420s have a CP race with the DMA engine.
  drm/radeon/r600/kms: rv670 is not DCE3
  drm/radeon/kms: r420 idle after programming GA_ENHANCE
  drm/radeon/kms: more fixes to rv770 suspend/resume path.
  drm/radeon/kms: more alignment for rv770.c with r600.c
  drm/radeon/kms: rv770 blit init called too late.
  drm/radeon/kms: move around new init path code to avoid posting at init
  drm/radeon/r600: fix some issues with suspend/resume.
  drm/radeon/kms: disable VGA rendering engine before taking over VRAM
  drm/radeon/kms: Move radeon_get_clock_info() call out of radeon_clocks_init().
  drm/radeon/kms: add initial connector properties
  drm/radeon/kms: Use surfaces for scanout / cursor byte swapping on big endian.
  drm/radeon/kms: don't fail if we fail to init GPU acceleration
  drm/r600/kms: fixup number of loops per blit calculation.
  drm/radeon/kms: reprogram format in set base.
  drm/radeon: avivo chips have no separate int bit for display
  drm/radeon/r600: don't do interrupts
  drm: fix _DRM_GEM addmap error message
  drm: update crtc x/y when only fb changes
  ...

Fixed up trivial conflicts in firmware/Makefile due to network driver
(cxgb3) and drm (mga/r128/radeon) firmware being listed next to each
other.

165 files changed:
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_cache.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_encoder_slave.c [new file with mode: 0644]
drivers/gpu/drm/drm_fb_helper.c [new file with mode: 0644]
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_proc.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_debugfs.c [moved from drivers/gpu/drm/i915/i915_gem_debugfs.c with 79% similarity]
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_fb.c
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/mga/mga_dma.c
drivers/gpu/drm/mga/mga_drv.h
drivers/gpu/drm/mga/mga_ucode.h [deleted file]
drivers/gpu/drm/mga/mga_warp.c
drivers/gpu/drm/r128/r128_cce.c
drivers/gpu/drm/r128/r128_drv.h
drivers/gpu/drm/r128/r128_state.c
drivers/gpu/drm/radeon/Kconfig
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/atombios.h
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/avivod.h [new file with mode: 0644]
drivers/gpu/drm/radeon/mkregtable.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r100_track.h [new file with mode: 0644]
drivers/gpu/drm/radeon/r100d.h [new file with mode: 0644]
drivers/gpu/drm/radeon/r200.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r300.h [deleted file]
drivers/gpu/drm/radeon/r300d.h [new file with mode: 0644]
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r420d.h [new file with mode: 0644]
drivers/gpu/drm/radeon/r520.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_blit.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r600_blit_kms.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r600_blit_shaders.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r600_blit_shaders.h [new file with mode: 0644]
drivers/gpu/drm/radeon/r600_cp.c
drivers/gpu/drm/radeon/r600_cs.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r600_microcode.h [deleted file]
drivers/gpu/drm/radeon/r600d.h [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_clocks.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cp.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_drv.h
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_ioc32.c
drivers/gpu/drm/radeon/radeon_irq.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_legacy_encoders.c
drivers/gpu/drm/radeon/radeon_legacy_tv.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_microcode.h [deleted file]
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_object.h
drivers/gpu/drm/radeon/radeon_reg.h
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_share.h [deleted file]
drivers/gpu/drm/radeon/radeon_state.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/reg_srcs/r100 [new file with mode: 0644]
drivers/gpu/drm/radeon/reg_srcs/r200 [new file with mode: 0644]
drivers/gpu/drm/radeon/reg_srcs/r300 [new file with mode: 0644]
drivers/gpu/drm/radeon/reg_srcs/rn50 [new file with mode: 0644]
drivers/gpu/drm/radeon/reg_srcs/rs600 [new file with mode: 0644]
drivers/gpu/drm/radeon/reg_srcs/rv515 [new file with mode: 0644]
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rs780.c [deleted file]
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv515d.h [moved from drivers/gpu/drm/radeon/rv515r.h with 78% similarity]
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/rv770d.h [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_global.c
drivers/gpu/drm/ttm/ttm_memory.c
drivers/gpu/drm/ttm/ttm_module.c
drivers/gpu/drm/ttm/ttm_tt.c
firmware/Makefile
firmware/WHENCE
firmware/matrox/g200_warp.H16 [new file with mode: 0644]
firmware/matrox/g400_warp.H16 [new file with mode: 0644]
firmware/r128/r128_cce.bin.ihex [new file with mode: 0644]
firmware/radeon/R100_cp.bin.ihex [new file with mode: 0644]
firmware/radeon/R200_cp.bin.ihex [new file with mode: 0644]
firmware/radeon/R300_cp.bin.ihex [new file with mode: 0644]
firmware/radeon/R420_cp.bin.ihex [new file with mode: 0644]
firmware/radeon/R520_cp.bin.ihex [new file with mode: 0644]
firmware/radeon/R600_me.bin.ihex [new file with mode: 0644]
firmware/radeon/R600_pfp.bin.ihex [new file with mode: 0644]
firmware/radeon/RS600_cp.bin.ihex [new file with mode: 0644]
firmware/radeon/RS690_cp.bin.ihex [new file with mode: 0644]
firmware/radeon/RS780_me.bin.ihex [new file with mode: 0644]
firmware/radeon/RS780_pfp.bin.ihex [new file with mode: 0644]
firmware/radeon/RV610_me.bin.ihex [new file with mode: 0644]
firmware/radeon/RV610_pfp.bin.ihex [new file with mode: 0644]
firmware/radeon/RV620_me.bin.ihex [new file with mode: 0644]
firmware/radeon/RV620_pfp.bin.ihex [new file with mode: 0644]
firmware/radeon/RV630_me.bin.ihex [new file with mode: 0644]
firmware/radeon/RV630_pfp.bin.ihex [new file with mode: 0644]
firmware/radeon/RV635_me.bin.ihex [new file with mode: 0644]
firmware/radeon/RV635_pfp.bin.ihex [new file with mode: 0644]
firmware/radeon/RV670_me.bin.ihex [new file with mode: 0644]
firmware/radeon/RV670_pfp.bin.ihex [new file with mode: 0644]
firmware/radeon/RV710_me.bin.ihex [new file with mode: 0644]
firmware/radeon/RV710_pfp.bin.ihex [new file with mode: 0644]
firmware/radeon/RV730_me.bin.ihex [new file with mode: 0644]
firmware/radeon/RV730_pfp.bin.ihex [new file with mode: 0644]
firmware/radeon/RV770_me.bin.ihex [new file with mode: 0644]
firmware/radeon/RV770_pfp.bin.ihex [new file with mode: 0644]
include/drm/drmP.h
include/drm/drm_cache.h [new file with mode: 0644]
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_encoder_slave.h [new file with mode: 0644]
include/drm/drm_fb_helper.h [new file with mode: 0644]
include/drm/drm_mm.h
include/drm/drm_mode.h
include/drm/drm_sysfs.h [new file with mode: 0644]
include/drm/radeon_drm.h
include/drm/ttm/ttm_bo_api.h
include/drm/ttm/ttm_bo_driver.h
include/drm/ttm/ttm_memory.h
include/drm/ttm/ttm_module.h

index 39b393d..e4d971c 100644 (file)
@@ -18,6 +18,14 @@ menuconfig DRM
          details.  You should also select and configure AGP
          (/dev/agpgart) support.
 
+config DRM_KMS_HELPER
+       tristate
+       depends on DRM
+       select FB
+       select FRAMEBUFFER_CONSOLE if !EMBEDDED
+       help
+         FB and CRTC helpers for KMS drivers.
+
 config DRM_TTM
        tristate
        depends on DRM
@@ -36,6 +44,7 @@ config DRM_TDFX
 config DRM_R128
        tristate "ATI Rage 128"
        depends on DRM && PCI
+       select FW_LOADER
        help
          Choose this option if you have an ATI Rage 128 graphics card.  If M
          is selected, the module will be called r128.  AGP support for
@@ -47,8 +56,9 @@ config DRM_RADEON
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
-       select FB
-       select FRAMEBUFFER_CONSOLE if !EMBEDDED
+       select FW_LOADER
+        select DRM_KMS_HELPER
+        select DRM_TTM
        help
          Choose this option if you have an ATI Radeon graphics card.  There
          are both PCI and AGP versions.  You don't need to choose this to
@@ -82,11 +92,10 @@ config DRM_I830
 config DRM_I915
        tristate "i915 driver"
        depends on AGP_INTEL
+       select DRM_KMS_HELPER
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
-       select FB
-       select FRAMEBUFFER_CONSOLE if !EMBEDDED
        # i915 depends on ACPI_VIDEO when ACPI is enabled
        # but for select to work, need to select ACPI_VIDEO's dependencies, ick
        select VIDEO_OUTPUT_CONTROL if ACPI
@@ -116,6 +125,7 @@ endchoice
 config DRM_MGA
        tristate "Matrox g200/g400"
        depends on DRM
+       select FW_LOADER
        help
          Choose this option if you have a Matrox G200, G400 or G450 graphics
          card.  If M is selected, the module will be called mga.  AGP
index fe23f29..3c8827a 100644 (file)
@@ -10,11 +10,15 @@ drm-y       :=      drm_auth.o drm_bufs.o drm_cache.o \
                drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
                drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
                drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \
-               drm_crtc.o drm_crtc_helper.o drm_modes.o drm_edid.o \
-               drm_info.o drm_debugfs.o
+               drm_crtc.o drm_modes.o drm_edid.o \
+               drm_info.o drm_debugfs.o drm_encoder_slave.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 
+drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o
+
+obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
+
 obj-$(CONFIG_DRM)      += drm.o
 obj-$(CONFIG_DRM_TTM)  += ttm/
 obj-$(CONFIG_DRM_TDFX) += tdfx/
index 6246e3f..3d09e30 100644 (file)
@@ -310,10 +310,10 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
                          (unsigned long long)map->offset, map->size);
 
                break;
+       }
        case _DRM_GEM:
-               DRM_ERROR("tried to rmmap GEM object\n");
+               DRM_ERROR("tried to addmap GEM object\n");
                break;
-       }
        case _DRM_SCATTER_GATHER:
                if (!dev->sg) {
                        kfree(map);
index 0e994a0..0e3bd5b 100644 (file)
@@ -45,6 +45,23 @@ drm_clflush_page(struct page *page)
                clflush(page_virtual + i);
        kunmap_atomic(page_virtual, KM_USER0);
 }
+
+static void drm_cache_flush_clflush(struct page *pages[],
+                                   unsigned long num_pages)
+{
+       unsigned long i;
+
+       mb();
+       for (i = 0; i < num_pages; i++)
+               drm_clflush_page(*pages++);
+       mb();
+}
+
+static void
+drm_clflush_ipi_handler(void *null)
+{
+       wbinvd();
+}
 #endif
 
 void
@@ -53,17 +70,30 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
 
 #if defined(CONFIG_X86)
        if (cpu_has_clflush) {
-               unsigned long i;
-
-               mb();
-               for (i = 0; i < num_pages; ++i)
-                       drm_clflush_page(*pages++);
-               mb();
-
+               drm_cache_flush_clflush(pages, num_pages);
                return;
        }
 
-       wbinvd();
+       if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0)
+               printk(KERN_ERR "Timed out waiting for cache flush.\n");
+
+#elif defined(__powerpc__)
+       unsigned long i;
+       for (i = 0; i < num_pages; i++) {
+               struct page *page = pages[i];
+               void *page_virtual;
+
+               if (unlikely(page == NULL))
+                       continue;
+
+               page_virtual = kmap_atomic(page, KM_USER0);
+               flush_dcache_range((unsigned long)page_virtual,
+                                  (unsigned long)page_virtual + PAGE_SIZE);
+               kunmap_atomic(page_virtual, KM_USER0);
+       }
+#else
+       printk(KERN_ERR "Architecture has no drm_cache.c support\n");
+       WARN_ON_ONCE(1);
 #endif
 }
 EXPORT_SYMBOL(drm_clflush_pages);
index 2f631c7..ba728ad 100644 (file)
@@ -68,10 +68,10 @@ DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
  */
 static struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
 {
-       { DRM_MODE_SCALE_NON_GPU, "Non-GPU" },
-       { DRM_MODE_SCALE_FULLSCREEN, "Fullscreen" },
-       { DRM_MODE_SCALE_NO_SCALE, "No scale" },
-       { DRM_MODE_SCALE_ASPECT, "Aspect" },
+       { DRM_MODE_SCALE_NONE, "None" },
+       { DRM_MODE_SCALE_FULLSCREEN, "Full" },
+       { DRM_MODE_SCALE_CENTER, "Center" },
+       { DRM_MODE_SCALE_ASPECT, "Full aspect" },
 };
 
 static struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
@@ -108,6 +108,7 @@ static struct drm_prop_enum_list drm_tv_select_enum_list[] =
        { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
        { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
        { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_SCART,     "SCART"     }, /* TV-out */
 };
 
 DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
@@ -118,6 +119,7 @@ static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
        { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
        { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
        { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_SCART,     "SCART"     }, /* TV-out */
 };
 
 DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
@@ -146,6 +148,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
        { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort", 0 },
        { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A", 0 },
        { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B", 0 },
+       { DRM_MODE_CONNECTOR_TV, "TV", 0 },
 };
 
 static struct drm_prop_enum_list drm_encoder_enum_list[] =
@@ -165,6 +168,7 @@ char *drm_get_encoder_name(struct drm_encoder *encoder)
                 encoder->base.id);
        return buf;
 }
+EXPORT_SYMBOL(drm_get_encoder_name);
 
 char *drm_get_connector_name(struct drm_connector *connector)
 {
@@ -699,6 +703,42 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
                drm_property_add_enum(dev->mode_config.tv_mode_property, i,
                                      i, modes[i]);
 
+       dev->mode_config.tv_brightness_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                   "brightness", 2);
+       dev->mode_config.tv_brightness_property->values[0] = 0;
+       dev->mode_config.tv_brightness_property->values[1] = 100;
+
+       dev->mode_config.tv_contrast_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                   "contrast", 2);
+       dev->mode_config.tv_contrast_property->values[0] = 0;
+       dev->mode_config.tv_contrast_property->values[1] = 100;
+
+       dev->mode_config.tv_flicker_reduction_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                   "flicker reduction", 2);
+       dev->mode_config.tv_flicker_reduction_property->values[0] = 0;
+       dev->mode_config.tv_flicker_reduction_property->values[1] = 100;
+
+       dev->mode_config.tv_overscan_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                   "overscan", 2);
+       dev->mode_config.tv_overscan_property->values[0] = 0;
+       dev->mode_config.tv_overscan_property->values[1] = 100;
+
+       dev->mode_config.tv_saturation_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                   "saturation", 2);
+       dev->mode_config.tv_saturation_property->values[0] = 0;
+       dev->mode_config.tv_saturation_property->values[1] = 100;
+
+       dev->mode_config.tv_hue_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                   "hue", 2);
+       dev->mode_config.tv_hue_property->values[0] = 0;
+       dev->mode_config.tv_hue_property->values[1] = 100;
+
        return 0;
 }
 EXPORT_SYMBOL(drm_mode_create_tv_properties);
@@ -1044,7 +1084,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
                if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
                        list_for_each_entry(crtc, &dev->mode_config.crtc_list,
                                            head) {
-                               DRM_DEBUG("CRTC ID is %d\n", crtc->base.id);
+                               DRM_DEBUG_KMS("CRTC ID is %d\n", crtc->base.id);
                                if (put_user(crtc->base.id, crtc_id + copied)) {
                                        ret = -EFAULT;
                                        goto out;
@@ -1072,7 +1112,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
                        list_for_each_entry(encoder,
                                            &dev->mode_config.encoder_list,
                                            head) {
-                               DRM_DEBUG("ENCODER ID is %d\n",
+                               DRM_DEBUG_KMS("ENCODER ID is %d\n",
                                          encoder->base.id);
                                if (put_user(encoder->base.id, encoder_id +
                                             copied)) {
@@ -1103,7 +1143,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
                        list_for_each_entry(connector,
                                            &dev->mode_config.connector_list,
                                            head) {
-                               DRM_DEBUG("CONNECTOR ID is %d\n",
+                               DRM_DEBUG_KMS("CONNECTOR ID is %d\n",
                                          connector->base.id);
                                if (put_user(connector->base.id,
                                             connector_id + copied)) {
@@ -1127,7 +1167,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
        }
        card_res->count_connectors = connector_count;
 
-       DRM_DEBUG("Counted %d %d %d\n", card_res->count_crtcs,
+       DRM_DEBUG_KMS("Counted %d %d %d\n", card_res->count_crtcs,
                  card_res->count_connectors, card_res->count_encoders);
 
 out:
@@ -1230,7 +1270,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 
        memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
 
-       DRM_DEBUG("connector id %d:\n", out_resp->connector_id);
+       DRM_DEBUG_KMS("connector id %d:\n", out_resp->connector_id);
 
        mutex_lock(&dev->mode_config.mutex);
 
@@ -1406,7 +1446,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
        obj = drm_mode_object_find(dev, crtc_req->crtc_id,
                                   DRM_MODE_OBJECT_CRTC);
        if (!obj) {
-               DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req->crtc_id);
+               DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
                ret = -EINVAL;
                goto out;
        }
@@ -1419,7 +1459,8 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
                        list_for_each_entry(crtcfb,
                                            &dev->mode_config.crtc_list, head) {
                                if (crtcfb == crtc) {
-                                       DRM_DEBUG("Using current fb for setmode\n");
+                                       DRM_DEBUG_KMS("Using current fb for "
+                                                       "setmode\n");
                                        fb = crtc->fb;
                                }
                        }
@@ -1427,7 +1468,8 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
                        obj = drm_mode_object_find(dev, crtc_req->fb_id,
                                                   DRM_MODE_OBJECT_FB);
                        if (!obj) {
-                               DRM_DEBUG("Unknown FB ID%d\n", crtc_req->fb_id);
+                               DRM_DEBUG_KMS("Unknown FB ID%d\n",
+                                               crtc_req->fb_id);
                                ret = -EINVAL;
                                goto out;
                        }
@@ -1440,13 +1482,13 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
        }
 
        if (crtc_req->count_connectors == 0 && mode) {
-               DRM_DEBUG("Count connectors is 0 but mode set\n");
+               DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
                ret = -EINVAL;
                goto out;
        }
 
        if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
-               DRM_DEBUG("Count connectors is %d but no mode or fb set\n",
+               DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
                          crtc_req->count_connectors);
                ret = -EINVAL;
                goto out;
@@ -1479,7 +1521,8 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
                        obj = drm_mode_object_find(dev, out_id,
                                                   DRM_MODE_OBJECT_CONNECTOR);
                        if (!obj) {
-                               DRM_DEBUG("Connector id %d unknown\n", out_id);
+                               DRM_DEBUG_KMS("Connector id %d unknown\n",
+                                               out_id);
                                ret = -EINVAL;
                                goto out;
                        }
@@ -1512,7 +1555,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
        struct drm_crtc *crtc;
        int ret = 0;
 
-       DRM_DEBUG("\n");
+       DRM_DEBUG_KMS("\n");
 
        if (!req->flags) {
                DRM_ERROR("no operation set\n");
@@ -1522,7 +1565,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
        if (!obj) {
-               DRM_DEBUG("Unknown CRTC ID %d\n", req->crtc_id);
+               DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
                ret = -EINVAL;
                goto out;
        }
index 6aaa2cb..fe86974 100644 (file)
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
 
-/*
- * Detailed mode info for 800x600@60Hz
- */
-static struct drm_display_mode std_modes[] = {
-       { DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 40000, 800, 840,
-                  968, 1056, 0, 600, 601, 605, 628, 0,
-                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-};
-
 static void drm_mode_validate_flag(struct drm_connector *connector,
                                   int flags)
 {
@@ -94,7 +85,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
        int count = 0;
        int mode_flags = 0;
 
-       DRM_DEBUG("%s\n", drm_get_connector_name(connector));
+       DRM_DEBUG_KMS("%s\n", drm_get_connector_name(connector));
        /* set all modes to the unverified state */
        list_for_each_entry_safe(mode, t, &connector->modes, head)
                mode->status = MODE_UNVERIFIED;
@@ -102,15 +93,17 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
        connector->status = connector->funcs->detect(connector);
 
        if (connector->status == connector_status_disconnected) {
-               DRM_DEBUG("%s is disconnected\n",
+               DRM_DEBUG_KMS("%s is disconnected\n",
                          drm_get_connector_name(connector));
-               /* TODO set EDID to NULL */
-               return 0;
+               goto prune;
        }
 
        count = (*connector_funcs->get_modes)(connector);
-       if (!count)
-               return 0;
+       if (!count) {
+               count = drm_add_modes_noedid(connector, 800, 600);
+               if (!count)
+                       return 0;
+       }
 
        drm_mode_connector_list_update(connector);
 
@@ -130,7 +123,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
                                                                   mode);
        }
 
-
+prune:
        drm_mode_prune_invalid(dev, &connector->modes, true);
 
        if (list_empty(&connector->modes))
@@ -138,7 +131,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
 
        drm_mode_sort(&connector->modes);
 
-       DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(connector));
+       DRM_DEBUG_KMS("Probed modes for %s\n",
+                               drm_get_connector_name(connector));
        list_for_each_entry_safe(mode, t, &connector->modes, head) {
                mode->vrefresh = drm_mode_vrefresh(mode);
 
@@ -165,39 +159,6 @@ int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
 }
 EXPORT_SYMBOL(drm_helper_probe_connector_modes);
 
-static void drm_helper_add_std_modes(struct drm_device *dev,
-                                    struct drm_connector *connector)
-{
-       struct drm_display_mode *mode, *t;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(std_modes); i++) {
-               struct drm_display_mode *stdmode;
-
-               /*
-                * When no valid EDID modes are available we end up
-                * here and bailed in the past, now we add some standard
-                * modes and move on.
-                */
-               stdmode = drm_mode_duplicate(dev, &std_modes[i]);
-               drm_mode_probed_add(connector, stdmode);
-               drm_mode_list_concat(&connector->probed_modes,
-                                    &connector->modes);
-
-               DRM_DEBUG("Adding mode %s to %s\n", stdmode->name,
-                         drm_get_connector_name(connector));
-       }
-       drm_mode_sort(&connector->modes);
-
-       DRM_DEBUG("Added std modes on %s\n", drm_get_connector_name(connector));
-       list_for_each_entry_safe(mode, t, &connector->modes, head) {
-               mode->vrefresh = drm_mode_vrefresh(mode);
-
-               drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
-               drm_mode_debug_printmodeline(mode);
-       }
-}
-
 /**
  * drm_helper_encoder_in_use - check if a given encoder is in use
  * @encoder: encoder to check
@@ -258,13 +219,27 @@ EXPORT_SYMBOL(drm_helper_crtc_in_use);
 void drm_helper_disable_unused_functions(struct drm_device *dev)
 {
        struct drm_encoder *encoder;
+       struct drm_connector *connector;
        struct drm_encoder_helper_funcs *encoder_funcs;
        struct drm_crtc *crtc;
 
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (!connector->encoder)
+                       continue;
+               if (connector->status == connector_status_disconnected)
+                       connector->encoder = NULL;
+       }
+
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                encoder_funcs = encoder->helper_private;
-               if (!drm_helper_encoder_in_use(encoder))
-                       (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
+               if (!drm_helper_encoder_in_use(encoder)) {
+                       if (encoder_funcs->disable)
+                               (*encoder_funcs->disable)(encoder);
+                       else
+                               (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
+                       /* disconnector encoder from any connector */
+                       encoder->crtc = NULL;
+               }
        }
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
@@ -312,7 +287,7 @@ static void drm_enable_connectors(struct drm_device *dev, bool *enabled)
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                enabled[i] = drm_connector_enabled(connector, true);
-               DRM_DEBUG("connector %d enabled? %s\n", connector->base.id,
+               DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
                          enabled[i] ? "yes" : "no");
                any_enabled |= enabled[i];
                i++;
@@ -342,7 +317,7 @@ static bool drm_target_preferred(struct drm_device *dev,
                        continue;
                }
 
-               DRM_DEBUG("looking for preferred mode on connector %d\n",
+               DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
                          connector->base.id);
 
                modes[i] = drm_has_preferred_mode(connector, width, height);
@@ -351,7 +326,7 @@ static bool drm_target_preferred(struct drm_device *dev,
                        list_for_each_entry(modes[i], &connector->modes, head)
                                break;
                }
-               DRM_DEBUG("found mode %s\n", modes[i] ? modes[i]->name :
+               DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
                          "none");
                i++;
        }
@@ -409,7 +384,7 @@ static int drm_pick_crtcs(struct drm_device *dev,
        c = 0;
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 
-               if ((connector->encoder->possible_crtcs & (1 << c)) == 0) {
+               if ((encoder->possible_crtcs & (1 << c)) == 0) {
                        c++;
                        continue;
                }
@@ -452,7 +427,7 @@ static void drm_setup_crtcs(struct drm_device *dev)
        int width, height;
        int i, ret;
 
-       DRM_DEBUG("\n");
+       DRM_DEBUG_KMS("\n");
 
        width = dev->mode_config.max_width;
        height = dev->mode_config.max_height;
@@ -475,7 +450,7 @@ static void drm_setup_crtcs(struct drm_device *dev)
        if (!ret)
                DRM_ERROR("Unable to find initial modes\n");
 
-       DRM_DEBUG("picking CRTCs for %dx%d config\n", width, height);
+       DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
 
        drm_pick_crtcs(dev, crtcs, modes, 0, width, height);
 
@@ -490,12 +465,14 @@ static void drm_setup_crtcs(struct drm_device *dev)
                }
 
                if (mode && crtc) {
-                       DRM_DEBUG("desired mode %s set on crtc %d\n",
+                       DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
                                  mode->name, crtc->base.id);
                        crtc->desired_mode = mode;
                        connector->encoder->crtc = crtc;
-               } else
+               } else {
                        connector->encoder->crtc = NULL;
+                       connector->encoder = NULL;
+               }
                i++;
        }
 
@@ -702,18 +679,17 @@ EXPORT_SYMBOL(drm_crtc_helper_set_mode);
 int drm_crtc_helper_set_config(struct drm_mode_set *set)
 {
        struct drm_device *dev;
-       struct drm_crtc **save_crtcs, *new_crtc;
-       struct drm_encoder **save_encoders, *new_encoder;
+       struct drm_crtc *save_crtcs, *new_crtc, *crtc;
+       struct drm_encoder *save_encoders, *new_encoder, *encoder;
        struct drm_framebuffer *old_fb = NULL;
-       bool save_enabled;
        bool mode_changed = false; /* if true do a full mode set */
        bool fb_changed = false; /* if true and !mode_changed just do a flip */
-       struct drm_connector *connector;
+       struct drm_connector *save_connectors, *connector;
        int count = 0, ro, fail = 0;
        struct drm_crtc_helper_funcs *crtc_funcs;
        int ret = 0;
 
-       DRM_DEBUG("\n");
+       DRM_DEBUG_KMS("\n");
 
        if (!set)
                return -EINVAL;
@@ -726,37 +702,60 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
 
        crtc_funcs = set->crtc->helper_private;
 
-       DRM_DEBUG("crtc: %p %d fb: %p connectors: %p num_connectors: %d (x, y) (%i, %i)\n",
+       DRM_DEBUG_KMS("crtc: %p %d fb: %p connectors: %p num_connectors:"
+                       " %d (x, y) (%i, %i)\n",
                  set->crtc, set->crtc->base.id, set->fb, set->connectors,
                  (int)set->num_connectors, set->x, set->y);
 
        dev = set->crtc->dev;
 
-       /* save previous config */
-       save_enabled = set->crtc->enabled;
-
-       /*
-        * We do mode_config.num_connectors here since we'll look at the
-        * CRTC and encoder associated with each connector later.
-        */
-       save_crtcs = kzalloc(dev->mode_config.num_connector *
-                            sizeof(struct drm_crtc *), GFP_KERNEL);
+       /* Allocate space for the backup of all (non-pointer) crtc, encoder and
+        * connector data. */
+       save_crtcs = kzalloc(dev->mode_config.num_crtc *
+                            sizeof(struct drm_crtc), GFP_KERNEL);
        if (!save_crtcs)
                return -ENOMEM;
 
-       save_encoders = kzalloc(dev->mode_config.num_connector *
-                               sizeof(struct drm_encoders *), GFP_KERNEL);
+       save_encoders = kzalloc(dev->mode_config.num_encoder *
+                               sizeof(struct drm_encoder), GFP_KERNEL);
        if (!save_encoders) {
                kfree(save_crtcs);
                return -ENOMEM;
        }
 
+       save_connectors = kzalloc(dev->mode_config.num_connector *
+                               sizeof(struct drm_connector), GFP_KERNEL);
+       if (!save_connectors) {
+               kfree(save_crtcs);
+               kfree(save_encoders);
+               return -ENOMEM;
+       }
+
+       /* Copy data. Note that driver private data is not affected.
+        * Should anything bad happen only the expected state is
+        * restored, not the drivers personal bookkeeping.
+        */
+       count = 0;
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               save_crtcs[count++] = *crtc;
+       }
+
+       count = 0;
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               save_encoders[count++] = *encoder;
+       }
+
+       count = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               save_connectors[count++] = *connector;
+       }
+
        /* We should be able to check here if the fb has the same properties
         * and then just flip_or_move it */
        if (set->crtc->fb != set->fb) {
                /* If we have no fb then treat it as a full mode set */
                if (set->crtc->fb == NULL) {
-                       DRM_DEBUG("crtc has no fb, full mode set\n");
+                       DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
                        mode_changed = true;
                } else if (set->fb == NULL) {
                        mode_changed = true;
@@ -772,7 +771,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                fb_changed = true;
 
        if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
-               DRM_DEBUG("modes are different, full mode set\n");
+               DRM_DEBUG_KMS("modes are different, full mode set\n");
                drm_mode_debug_printmodeline(&set->crtc->mode);
                drm_mode_debug_printmodeline(set->mode);
                mode_changed = true;
@@ -783,7 +782,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct drm_connector_helper_funcs *connector_funcs =
                        connector->helper_private;
-               save_encoders[count++] = connector->encoder;
                new_encoder = connector->encoder;
                for (ro = 0; ro < set->num_connectors; ro++) {
                        if (set->connectors[ro] == connector) {
@@ -798,15 +796,20 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                }
 
                if (new_encoder != connector->encoder) {
-                       DRM_DEBUG("encoder changed, full mode switch\n");
+                       DRM_DEBUG_KMS("encoder changed, full mode switch\n");
                        mode_changed = true;
+                       /* If the encoder is reused for another connector, then
+                        * the appropriate crtc will be set later.
+                        */
+                       if (connector->encoder)
+                               connector->encoder->crtc = NULL;
                        connector->encoder = new_encoder;
                }
        }
 
        if (fail) {
                ret = -EINVAL;
-               goto fail_no_encoder;
+               goto fail;
        }
 
        count = 0;
@@ -814,8 +817,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                if (!connector->encoder)
                        continue;
 
-               save_crtcs[count++] = connector->encoder->crtc;
-
                if (connector->encoder->crtc == set->crtc)
                        new_crtc = NULL;
                else
@@ -830,14 +831,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                if (new_crtc &&
                    !drm_encoder_crtc_ok(connector->encoder, new_crtc)) {
                        ret = -EINVAL;
-                       goto fail_set_mode;
+                       goto fail;
                }
                if (new_crtc != connector->encoder->crtc) {
-                       DRM_DEBUG("crtc changed, full mode switch\n");
+                       DRM_DEBUG_KMS("crtc changed, full mode switch\n");
                        mode_changed = true;
                        connector->encoder->crtc = new_crtc;
                }
-               DRM_DEBUG("setting connector %d crtc to %p\n",
+               DRM_DEBUG_KMS("setting connector %d crtc to %p\n",
                          connector->base.id, new_crtc);
        }
 
@@ -850,7 +851,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                set->crtc->fb = set->fb;
                set->crtc->enabled = (set->mode != NULL);
                if (set->mode != NULL) {
-                       DRM_DEBUG("attempting to set mode from userspace\n");
+                       DRM_DEBUG_KMS("attempting to set mode from"
+                                       " userspace\n");
                        drm_mode_debug_printmodeline(set->mode);
                        if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
                                                      set->x, set->y,
@@ -858,7 +860,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                                DRM_ERROR("failed to set mode on crtc %p\n",
                                          set->crtc);
                                ret = -EINVAL;
-                               goto fail_set_mode;
+                               goto fail;
                        }
                        /* TODO are these needed? */
                        set->crtc->desired_x = set->x;
@@ -867,43 +869,50 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                }
                drm_helper_disable_unused_functions(dev);
        } else if (fb_changed) {
+               set->crtc->x = set->x;
+               set->crtc->y = set->y;
+
                old_fb = set->crtc->fb;
                if (set->crtc->fb != set->fb)
                        set->crtc->fb = set->fb;
                ret = crtc_funcs->mode_set_base(set->crtc,
                                                set->x, set->y, old_fb);
                if (ret != 0)
-                   goto fail_set_mode;
+                       goto fail;
        }
 
+       kfree(save_connectors);
        kfree(save_encoders);
        kfree(save_crtcs);
        return 0;
 
-fail_set_mode:
-       set->crtc->enabled = save_enabled;
-       set->crtc->fb = old_fb;
+fail:
+       /* Restore all previous data. */
        count = 0;
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               if (!connector->encoder)
-                       continue;
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               *crtc = save_crtcs[count++];
+       }
 
-               connector->encoder->crtc = save_crtcs[count++];
+       count = 0;
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               *encoder = save_encoders[count++];
        }
-fail_no_encoder:
-       kfree(save_crtcs);
+
        count = 0;
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               connector->encoder = save_encoders[count++];
+               *connector = save_connectors[count++];
        }
+
+       kfree(save_connectors);
        kfree(save_encoders);
+       kfree(save_crtcs);
        return ret;
 }
 EXPORT_SYMBOL(drm_crtc_helper_set_config);
 
 bool drm_helper_plugged_event(struct drm_device *dev)
 {
-       DRM_DEBUG("\n");
+       DRM_DEBUG_KMS("\n");
 
        drm_helper_probe_connector_modes(dev, dev->mode_config.max_width,
                                         dev->mode_config.max_height);
@@ -932,7 +941,6 @@ bool drm_helper_plugged_event(struct drm_device *dev)
  */
 bool drm_helper_initial_config(struct drm_device *dev)
 {
-       struct drm_connector *connector;
        int count = 0;
 
        count = drm_helper_probe_connector_modes(dev,
@@ -940,16 +948,9 @@ bool drm_helper_initial_config(struct drm_device *dev)
                                                 dev->mode_config.max_height);
 
        /*
-        * None of the available connectors had any modes, so add some
-        * and try to light them up anyway
+        * we shouldn't end up with no modes here.
         */
-       if (!count) {
-               DRM_ERROR("connectors have no modes, using standard modes\n");
-               list_for_each_entry(connector,
-                                   &dev->mode_config.connector_list,
-                                   head)
-                       drm_helper_add_std_modes(dev, connector);
-       }
+       WARN(!count, "Connected connector with 0 modes\n");
 
        drm_setup_crtcs(dev);
 
index b39d7bf..a75ca63 100644 (file)
@@ -63,12 +63,12 @@ static struct drm_ioctl_desc drm_ioctls[] = {
        DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0),
-       DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER),
 
        DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER),
 
        DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH),
index 7f2728b..90d76ba 100644 (file)
 #define EDID_QUIRK_FIRST_DETAILED_PREFERRED    (1 << 5)
 /* use +hsync +vsync for detailed mode */
 #define EDID_QUIRK_DETAILED_SYNC_PP            (1 << 6)
+/* define the number of Extension EDID block */
+#define MAX_EDID_EXT_NUM 4
+
+#define LEVEL_DMT      0
+#define LEVEL_GTF      1
+#define LEVEL_CVT      2
 
 static struct edid_quirk {
        char *vendor;
@@ -237,28 +243,291 @@ static void edid_fixup_preferred(struct drm_connector *connector,
        preferred_mode->type |= DRM_MODE_TYPE_PREFERRED;
 }
 
+/*
+ * Add the Autogenerated from the DMT spec.
+ * This table is copied from xfree86/modes/xf86EdidModes.c.
+ * But the mode with Reduced blank feature is deleted.
+ */
+static struct drm_display_mode drm_dmt_modes[] = {
+       /* 640x350@85Hz */
+       { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
+                  736, 832, 0, 350, 382, 385, 445, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 640x400@85Hz */
+       { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
+                  736, 832, 0, 400, 401, 404, 445, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 720x400@85Hz */
+       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 756,
+                  828, 936, 0, 400, 401, 404, 446, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 640x480@60Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
+                  752, 800, 0, 480, 489, 492, 525, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 640x480@72Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
+                  704, 832, 0, 480, 489, 492, 520, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 640x480@75Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
+                  720, 840, 0, 480, 481, 484, 500, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 640x480@85Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 36000, 640, 696,
+                  752, 832, 0, 480, 481, 484, 509, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 800x600@56Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
+                  896, 1024, 0, 600, 601, 603, 625, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 800x600@60Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
+                  968, 1056, 0, 600, 601, 605, 628, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 800x600@72Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
+                  976, 1040, 0, 600, 637, 643, 666, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 800x600@75Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
+                  896, 1056, 0, 600, 601, 604, 625, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 800x600@85Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832,
+                  896, 1048, 0, 600, 601, 604, 631, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 848x480@60Hz */
+       { DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864,
+                  976, 1088, 0, 480, 486, 494, 517, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1024x768@43Hz, interlace */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032,
+                  1208, 1264, 0, 768, 768, 772, 817, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
+                       DRM_MODE_FLAG_INTERLACE) },
+       /* 1024x768@60Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
+                  1184, 1344, 0, 768, 771, 777, 806, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1024x768@70Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
+                  1184, 1328, 0, 768, 771, 777, 806, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1024x768@75Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040,
+                  1136, 1312, 0, 768, 769, 772, 800, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1024x768@85Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
+                  1072, 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, 2025000, 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 struct drm_display_mode *drm_find_dmt(struct drm_device *dev,
+                       int hsize, int vsize, int fresh)
+{
+       int i, count;
+       struct drm_display_mode *ptr, *mode;
+
+       count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
+       mode = NULL;
+       for (i = 0; i < count; i++) {
+               ptr = &drm_dmt_modes[i];
+               if (hsize == ptr->hdisplay &&
+                       vsize == ptr->vdisplay &&
+                       fresh == drm_mode_vrefresh(ptr)) {
+                       /* get the expected default mode */
+                       mode = drm_mode_duplicate(dev, ptr);
+                       break;
+               }
+       }
+       return mode;
+}
 /**
  * drm_mode_std - convert standard mode info (width, height, refresh) into mode
  * @t: standard timing params
+ * @timing_level: standard timing level
  *
  * Take the standard timing params (in this case width, aspect, and refresh)
- * and convert them into a real mode using CVT.
+ * and convert them into a real mode using CVT/GTF/DMT.
  *
  * Punts for now, but should eventually use the FB layer's CVT based mode
  * generation code.
  */
 struct drm_display_mode *drm_mode_std(struct drm_device *dev,
-                                     struct std_timing *t)
+                                     struct std_timing *t,
+                                     int timing_level)
 {
        struct drm_display_mode *mode;
-       int hsize = t->hsize * 8 + 248, vsize;
+       int hsize, vsize;
+       int vrefresh_rate;
        unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK)
                >> EDID_TIMING_ASPECT_SHIFT;
-
-       mode = drm_mode_create(dev);
-       if (!mode)
-               return NULL;
-
+       unsigned vfreq = (t->vfreq_aspect & EDID_TIMING_VFREQ_MASK)
+               >> EDID_TIMING_VFREQ_SHIFT;
+
+       /* According to the EDID spec, the hdisplay = hsize * 8 + 248 */
+       hsize = t->hsize * 8 + 248;
+       /* vrefresh_rate = vfreq + 60 */
+       vrefresh_rate = vfreq + 60;
+       /* the vdisplay is calculated based on the aspect ratio */
        if (aspect_ratio == 0)
                vsize = (hsize * 10) / 16;
        else if (aspect_ratio == 1)
@@ -267,9 +536,30 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
                vsize = (hsize * 4) / 5;
        else
                vsize = (hsize * 9) / 16;
-
-       drm_mode_set_name(mode);
-
+       /* HDTV hack */
+       if (hsize == 1360 && vsize == 765 && vrefresh_rate == 60) {
+               mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
+               mode->hdisplay = 1366;
+               mode->vsync_start = mode->vsync_start - 1;
+               mode->vsync_end = mode->vsync_end - 1;
+               return mode;
+       }
+       mode = NULL;
+       /* check whether it can be found in default mode table */
+       mode = drm_find_dmt(dev, hsize, vsize, vrefresh_rate);
+       if (mode)
+               return mode;
+
+       switch (timing_level) {
+       case LEVEL_DMT:
+               break;
+       case LEVEL_GTF:
+               mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
+               break;
+       case LEVEL_CVT:
+               mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
+               break;
+       }
        return mode;
 }
 
@@ -451,6 +741,19 @@ static int add_established_modes(struct drm_connector *connector, struct edid *e
 
        return modes;
 }
+/**
+ * stanard_timing_level - get std. timing level(CVT/GTF/DMT)
+ * @edid: EDID block to scan
+ */
+static int standard_timing_level(struct edid *edid)
+{
+       if (edid->revision >= 2) {
+               if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF))
+                       return LEVEL_CVT;
+               return LEVEL_GTF;
+       }
+       return LEVEL_DMT;
+}
 
 /**
  * add_standard_modes - get std. modes from EDID and add them
@@ -463,6 +766,9 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
 {
        struct drm_device *dev = connector->dev;
        int i, modes = 0;
+       int timing_level;
+
+       timing_level = standard_timing_level(edid);
 
        for (i = 0; i < EDID_STD_TIMINGS; i++) {
                struct std_timing *t = &edid->standard_timings[i];
@@ -472,7 +778,8 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
                if (t->hsize == 1 && t->vfreq_aspect == 1)
                        continue;
 
-               newmode = drm_mode_std(dev, &edid->standard_timings[i]);
+               newmode = drm_mode_std(dev, &edid->standard_timings[i],
+                                       timing_level);
                if (newmode) {
                        drm_mode_probed_add(connector, newmode);
                        modes++;
@@ -496,6 +803,9 @@ static int add_detailed_info(struct drm_connector *connector,
 {
        struct drm_device *dev = connector->dev;
        int i, j, modes = 0;
+       int timing_level;
+
+       timing_level = standard_timing_level(edid);
 
        for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
                struct detailed_timing *timing = &edid->detailed_timings[i];
@@ -525,7 +835,8 @@ static int add_detailed_info(struct drm_connector *connector,
                                        struct drm_display_mode *newmode;
 
                                        std = &data->data.timings[j];
-                                       newmode = drm_mode_std(dev, std);
+                                       newmode = drm_mode_std(dev, std,
+                                                              timing_level);
                                        if (newmode) {
                                                drm_mode_probed_add(connector, newmode);
                                                modes++;
@@ -551,6 +862,122 @@ static int add_detailed_info(struct drm_connector *connector,
 
        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)
+{
+       struct drm_device *dev = connector->dev;
+       int i, j, modes = 0;
+       char *edid_ext = NULL;
+       struct detailed_timing *timing;
+       struct detailed_non_pixel *data;
+       struct drm_display_mode *newmode;
+       int edid_ext_num;
+       int start_offset, end_offset;
+       int timing_level;
+
+       if (edid->version == 1 && edid->revision < 3) {
+               /* If the EDID version is less than 1.3, there is no
+                * extension EDID.
+                */
+               return 0;
+       }
+       if (!edid->extensions) {
+               /* if there is no extension EDID, it is unnecessary to
+                * parse the E-EDID to get detailed info
+                */
+               return 0;
+       }
+
+       /* Chose real EDID extension number */
+       edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ?
+                      MAX_EDID_EXT_NUM : edid->extensions;
+
+       /* Find CEA extension */
+       for (i = 0; i < edid_ext_num; i++) {
+               edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
+               /* This block is CEA extension */
+               if (edid_ext[0] == 0x02)
+                       break;
+       }
+
+       if (i == edid_ext_num) {
+               /* if there is no additional timing EDID block, return */
+               return 0;
+       }
+
+       /* 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;
+       }
+
+       timing_level = standard_timing_level(edid);
+       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);
+               data = &timing->data.other_data;
+               /* Detailed mode timing */
+               if (timing->pixel_clock) {
+                       newmode = drm_mode_detailed(dev, edid, timing, quirks);
+                       if (!newmode)
+                               continue;
+
+                       drm_mode_probed_add(connector, newmode);
+
+                       modes++;
+                       continue;
+               }
+
+               /* Other timing or info */
+               switch (data->type) {
+               case EDID_DETAIL_MONITOR_SERIAL:
+                       break;
+               case EDID_DETAIL_MONITOR_STRING:
+                       break;
+               case EDID_DETAIL_MONITOR_RANGE:
+                       /* Get monitor range data */
+                       break;
+               case EDID_DETAIL_MONITOR_NAME:
+                       break;
+               case EDID_DETAIL_MONITOR_CPDATA:
+                       break;
+               case EDID_DETAIL_STD_MODES:
+                       /* Five modes per detailed section */
+                       for (j = 0; j < 5; i++) {
+                               struct std_timing *std;
+                               struct drm_display_mode *newmode;
+
+                               std = &data->data.timings[j];
+                               newmode = drm_mode_std(dev, std, timing_level);
+                               if (newmode) {
+                                       drm_mode_probed_add(connector, newmode);
+                                       modes++;
+                               }
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return modes;
+}
 
 #define DDC_ADDR 0x50
 /**
@@ -584,7 +1011,6 @@ int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
        if (i2c_transfer(adapter, msgs, 2) == 2)
                return 0;
 
-       dev_info(&adapter->dev, "unable to read EDID block.\n");
        return -1;
 }
 EXPORT_SYMBOL(drm_do_probe_ddc_edid);
@@ -597,8 +1023,6 @@ static int drm_ddc_read_edid(struct drm_connector *connector,
 
        ret = drm_do_probe_ddc_edid(adapter, buf, len);
        if (ret != 0) {
-               dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
-                        drm_get_connector_name(connector));
                goto end;
        }
        if (!edid_is_valid((struct edid *)buf)) {
@@ -610,7 +1034,6 @@ end:
        return ret;
 }
 
-#define MAX_EDID_EXT_NUM 4
 /**
  * drm_get_edid - get EDID data, if available
  * @connector: connector we're probing
@@ -763,6 +1186,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
        num_modes += add_established_modes(connector, edid);
        num_modes += add_standard_modes(connector, edid);
        num_modes += add_detailed_info(connector, edid, quirks);
+       num_modes += add_detailed_info_eedid(connector, edid, quirks);
 
        if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
                edid_fixup_preferred(connector, quirks);
@@ -788,3 +1212,49 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
        return num_modes;
 }
 EXPORT_SYMBOL(drm_add_edid_modes);
+
+/**
+ * drm_add_modes_noedid - add modes for the connectors without EDID
+ * @connector: connector we're probing
+ * @hdisplay: the horizontal display limit
+ * @vdisplay: the vertical display limit
+ *
+ * Add the specified modes to the connector's mode list. Only when the
+ * hdisplay/vdisplay is not beyond the given limit, it will be added.
+ *
+ * Return number of modes added or 0 if we couldn't find any.
+ */
+int drm_add_modes_noedid(struct drm_connector *connector,
+                       int hdisplay, int vdisplay)
+{
+       int i, count, num_modes = 0;
+       struct drm_display_mode *mode, *ptr;
+       struct drm_device *dev = connector->dev;
+
+       count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
+       if (hdisplay < 0)
+               hdisplay = 0;
+       if (vdisplay < 0)
+               vdisplay = 0;
+
+       for (i = 0; i < count; i++) {
+               ptr = &drm_dmt_modes[i];
+               if (hdisplay && vdisplay) {
+                       /*
+                        * Only when two are valid, they will be used to check
+                        * whether the mode should be added to the mode list of
+                        * the connector.
+                        */
+                       if (ptr->hdisplay > hdisplay ||
+                                       ptr->vdisplay > vdisplay)
+                               continue;
+               }
+               mode = drm_mode_duplicate(dev, ptr);
+               if (mode) {
+                       drm_mode_probed_add(connector, mode);
+                       num_modes++;
+               }
+       }
+       return num_modes;
+}
+EXPORT_SYMBOL(drm_add_modes_noedid);
diff --git a/drivers/gpu/drm/drm_encoder_slave.c b/drivers/gpu/drm/drm_encoder_slave.c
new file mode 100644 (file)
index 0000000..f018469
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2009 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "drm_encoder_slave.h"
+
+/**
+ * drm_i2c_encoder_init - Initialize an I2C slave encoder
+ * @dev:       DRM device.
+ * @encoder:    Encoder to be attached to the I2C device. You aren't
+ *             required to have called drm_encoder_init() before.
+ * @adap:      I2C adapter that will be used to communicate with
+ *             the device.
+ * @info:      Information that will be used to create the I2C device.
+ *             Required fields are @addr and @type.
+ *
+ * Create an I2C device on the specified bus (the module containing its
+ * driver is transparently loaded) and attach it to the specified
+ * &drm_encoder_slave. The @slave_funcs field will be initialized with
+ * the hooks provided by the slave driver.
+ *
+ * Returns 0 on success or a negative errno on failure, in particular,
+ * -ENODEV is returned when no matching driver is found.
+ */
+int drm_i2c_encoder_init(struct drm_device *dev,
+                        struct drm_encoder_slave *encoder,
+                        struct i2c_adapter *adap,
+                        const struct i2c_board_info *info)
+{
+       char modalias[sizeof(I2C_MODULE_PREFIX)
+                     + I2C_NAME_SIZE];
+       struct module *module = NULL;
+       struct i2c_client *client;
+       struct drm_i2c_encoder_driver *encoder_drv;
+       int err = 0;
+
+       snprintf(modalias, sizeof(modalias),
+                "%s%s", I2C_MODULE_PREFIX, info->type);
+       request_module(modalias);
+
+       client = i2c_new_device(adap, info);
+       if (!client) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       if (!client->driver) {
+               err = -ENODEV;
+               goto fail_unregister;
+       }
+
+       module = client->driver->driver.owner;
+       if (!try_module_get(module)) {
+               err = -ENODEV;
+               goto fail_unregister;
+       }
+
+       encoder->bus_priv = client;
+
+       encoder_drv = to_drm_i2c_encoder_driver(client->driver);
+
+       err = encoder_drv->encoder_init(client, dev, encoder);
+       if (err)
+               goto fail_unregister;
+
+       return 0;
+
+fail_unregister:
+       i2c_unregister_device(client);
+       module_put(module);
+fail:
+       return err;
+}
+EXPORT_SYMBOL(drm_i2c_encoder_init);
+
+/**
+ * drm_i2c_encoder_destroy - Unregister the I2C device backing an encoder
+ * @drm_encoder:       Encoder to be unregistered.
+ *
+ * This should be called from the @destroy method of an I2C slave
+ * encoder driver once I2C access is no longer needed.
+ */
+void drm_i2c_encoder_destroy(struct drm_encoder *drm_encoder)
+{
+       struct drm_encoder_slave *encoder = to_encoder_slave(drm_encoder);
+       struct i2c_client *client = drm_i2c_encoder_get_client(drm_encoder);
+       struct module *module = client->driver->driver.owner;
+
+       i2c_unregister_device(client);
+       encoder->bus_priv = NULL;
+
+       module_put(module);
+}
+EXPORT_SYMBOL(drm_i2c_encoder_destroy);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
new file mode 100644 (file)
index 0000000..2c46713
--- /dev/null
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 2006-2009 Red Hat Inc.
+ * Copyright (c) 2006-2008 Intel Corporation
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
+ *
+ * DRM framebuffer helper functions
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * Authors:
+ *      Dave Airlie <airlied@linux.ie>
+ *      Jesse Barnes <jesse.barnes@intel.com>
+ */
+#include <linux/sysrq.h>
+#include <linux/fb.h>
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_fb_helper.h"
+#include "drm_crtc_helper.h"
+
+MODULE_AUTHOR("David Airlie, Jesse Barnes");
+MODULE_DESCRIPTION("DRM KMS helper");
+MODULE_LICENSE("GPL and additional rights");
+
+static LIST_HEAD(kernel_fb_helper_list);
+
+bool drm_fb_helper_force_kernel_mode(void)
+{
+       int i = 0;
+       bool ret, error = false;
+       struct drm_fb_helper *helper;
+
+       if (list_empty(&kernel_fb_helper_list))
+               return false;
+
+       list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
+               for (i = 0; i < helper->crtc_count; i++) {
+                       struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
+                       ret = drm_crtc_helper_set_config(mode_set);
+                       if (ret)
+                               error = true;
+               }
+       }
+       return error;
+}
+
+int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
+                       void *panic_str)
+{
+       DRM_ERROR("panic occurred, switching back to text console\n");
+       return drm_fb_helper_force_kernel_mode();
+       return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_panic);
+
+static struct notifier_block paniced = {
+       .notifier_call = drm_fb_helper_panic,
+};
+
+/**
+ * drm_fb_helper_restore - restore the framebuffer console (kernel) config
+ *
+ * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
+ */
+void drm_fb_helper_restore(void)
+{
+       bool ret;
+       ret = drm_fb_helper_force_kernel_mode();
+       if (ret == true)
+               DRM_ERROR("Failed to restore crtc configuration\n");
+}
+EXPORT_SYMBOL(drm_fb_helper_restore);
+
+static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
+{
+       drm_fb_helper_restore();
+}
+static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
+
+static void drm_fb_helper_sysrq(int dummy1, struct tty_struct *dummy3)
+{
+       schedule_work(&drm_fb_helper_restore_work);
+}
+
+static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
+       .handler = drm_fb_helper_sysrq,
+       .help_msg = "force-fb(V)",
+       .action_msg = "Restore framebuffer console",
+};
+
+static void drm_fb_helper_on(struct fb_info *info)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+       struct drm_device *dev = fb_helper->dev;
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       int i;
+
+       /*
+        * For each CRTC in this fb, turn the crtc on then,
+        * find all associated encoders and turn them on.
+        */
+       for (i = 0; i < fb_helper->crtc_count; i++) {
+               list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+                       struct drm_crtc_helper_funcs *crtc_funcs =
+                               crtc->helper_private;
+
+                       /* Only mess with CRTCs in this fb */
+                       if (crtc->base.id != fb_helper->crtc_info[i].crtc_id ||
+                           !crtc->enabled)
+                               continue;
+
+                       mutex_lock(&dev->mode_config.mutex);
+                       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+                       mutex_unlock(&dev->mode_config.mutex);
+
+                       /* Found a CRTC on this fb, now find encoders */
+                       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+                               if (encoder->crtc == crtc) {
+                                       struct drm_encoder_helper_funcs *encoder_funcs;
+
+                                       encoder_funcs = encoder->helper_private;
+                                       mutex_lock(&dev->mode_config.mutex);
+                                       encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
+                                       mutex_unlock(&dev->mode_config.mutex);
+                               }
+                       }
+               }
+       }
+}
+
+static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+       struct drm_device *dev = fb_helper->dev;
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       int i;
+
+       /*
+        * For each CRTC in this fb, find all associated encoders
+        * and turn them off, then turn off the CRTC.
+        */
+       for (i = 0; i < fb_helper->crtc_count; i++) {
+               list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+                       struct drm_crtc_helper_funcs *crtc_funcs =
+                               crtc->helper_private;
+
+                       /* Only mess with CRTCs in this fb */
+                       if (crtc->base.id != fb_helper->crtc_info[i].crtc_id ||
+                           !crtc->enabled)
+                               continue;
+
+                       /* Found a CRTC on this fb, now find encoders */
+                       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+                               if (encoder->crtc == crtc) {
+                                       struct drm_encoder_helper_funcs *encoder_funcs;
+
+                                       encoder_funcs = encoder->helper_private;
+                                       mutex_lock(&dev->mode_config.mutex);
+                                       encoder_funcs->dpms(encoder, dpms_mode);
+                                       mutex_unlock(&dev->mode_config.mutex);
+                               }
+                       }
+                       if (dpms_mode == DRM_MODE_DPMS_OFF) {
+                               mutex_lock(&dev->mode_config.mutex);
+                               crtc_funcs->dpms(crtc, dpms_mode);
+                               mutex_unlock(&dev->mode_config.mutex);
+                       }
+               }
+       }
+}
+
+int drm_fb_helper_blank(int blank, struct fb_info *info)
+{
+       switch (blank) {
+       case FB_BLANK_UNBLANK:
+               drm_fb_helper_on(info);
+               break;
+       case FB_BLANK_NORMAL:
+               drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
+               break;
+       case FB_BLANK_HSYNC_SUSPEND:
+               drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
+               drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND);
+               break;
+       case FB_BLANK_POWERDOWN:
+               drm_fb_helper_off(info, DRM_MODE_DPMS_OFF);
+               break;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_blank);
+
+static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
+{
+       int i;
+
+       for (i = 0; i < helper->crtc_count; i++)
+               kfree(helper->crtc_info[i].mode_set.connectors);
+       kfree(helper->crtc_info);
+}
+
+int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, int max_conn_count)
+{
+       struct drm_device *dev = helper->dev;
+       struct drm_crtc *crtc;
+       int ret = 0;
+       int i;
+
+       helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
+       if (!helper->crtc_info)
+               return -ENOMEM;
+
+       helper->crtc_count = crtc_count;
+
+       for (i = 0; i < crtc_count; i++) {
+               helper->crtc_info[i].mode_set.connectors =
+                       kcalloc(max_conn_count,
+                               sizeof(struct drm_connector *),
+                               GFP_KERNEL);
+
+               if (!helper->crtc_info[i].mode_set.connectors) {
+                       ret = -ENOMEM;
+                       goto out_free;
+               }
+               helper->crtc_info[i].mode_set.num_connectors = 0;
+       }
+
+       i = 0;
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               helper->crtc_info[i].crtc_id = crtc->base.id;
+               helper->crtc_info[i].mode_set.crtc = crtc;
+               i++;
+       }
+       helper->conn_limit = max_conn_count;
+       return 0;
+out_free:
+       drm_fb_helper_crtc_free(helper);
+       return -ENOMEM;
+}
+EXPORT_SYMBOL(drm_fb_helper_init_crtc_count);
+
+int drm_fb_helper_setcolreg(unsigned regno,
+                           unsigned red,
+                           unsigned green,
+                           unsigned blue,
+                           unsigned transp,
+                           struct fb_info *info)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+       struct drm_device *dev = fb_helper->dev;
+       struct drm_crtc *crtc;
+       int i;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct drm_framebuffer *fb = fb_helper->fb;
+
+               for (i = 0; i < fb_helper->crtc_count; i++) {
+                       if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
+                               break;
+               }
+               if (i == fb_helper->crtc_count)
+                       continue;
+
+               if (regno > 255)
+                       return 1;
+
+               if (fb->depth == 8) {
+                       fb_helper->funcs->gamma_set(crtc, red, green, blue, regno);
+                       return 0;
+               }
+
+               if (regno < 16) {
+                       switch (fb->depth) {
+                       case 15:
+                               fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
+                                       ((green & 0xf800) >>  6) |
+                                       ((blue & 0xf800) >> 11);
+                               break;
+                       case 16:
+                               fb->pseudo_palette[regno] = (red & 0xf800) |
+                                       ((green & 0xfc00) >>  5) |
+                                       ((blue  & 0xf800) >> 11);
+                               break;
+                       case 24:
+                       case 32:
+                               fb->pseudo_palette[regno] =
+                                       (((red >> 8) & 0xff) << info->var.red.offset) |
+                                       (((green >> 8) & 0xff) << info->var.green.offset) |
+                                       (((blue >> 8) & 0xff) << info->var.blue.offset);
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_setcolreg);
+
+int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
+                           struct fb_info *info)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+       struct drm_framebuffer *fb = fb_helper->fb;
+       int depth;
+
+       if (var->pixclock == -1 || !var->pixclock)
+               return -EINVAL;
+
+       /* Need to resize the fb object !!! */
+       if (var->xres > fb->width || var->yres > fb->height) {
+               DRM_ERROR("Requested width/height is greater than current fb "
+                          "object %dx%d > %dx%d\n", var->xres, var->yres,
+                          fb->width, fb->height);
+               DRM_ERROR("Need resizing code.\n");
+               return -EINVAL;
+       }
+
+       switch (var->bits_per_pixel) {
+       case 16:
+               depth = (var->green.length == 6) ? 16 : 15;
+               break;
+       case 32:
+               depth = (var->transp.length > 0) ? 32 : 24;
+               break;
+       default:
+               depth = var->bits_per_pixel;
+               break;
+       }
+
+       switch (depth) {
+       case 8:
+               var->red.offset = 0;
+               var->green.offset = 0;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 15:
+               var->red.offset = 10;
+               var->green.offset = 5;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 5;
+               var->blue.length = 5;
+               var->transp.length = 1;
+               var->transp.offset = 15;
+               break;
+       case 16:
+               var->red.offset = 11;
+               var->green.offset = 5;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 6;
+               var->blue.length = 5;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 24:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 32:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 8;
+               var->transp.offset = 24;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_check_var);
+
+/* this will let fbcon do the mode init */
+int drm_fb_helper_set_par(struct fb_info *info)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+       struct drm_device *dev = fb_helper->dev;
+       struct fb_var_screeninfo *var = &info->var;
+       struct drm_crtc *crtc;
+       int ret;
+       int i;
+
+       if (var->pixclock != -1) {
+               DRM_ERROR("PIXEL CLCOK SET\n");
+               return -EINVAL;
+       }
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+
+               for (i = 0; i < fb_helper->crtc_count; i++) {
+                       if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
+                               break;
+               }
+               if (i == fb_helper->crtc_count)
+                       continue;
+
+               if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) {
+                       mutex_lock(&dev->mode_config.mutex);
+                       ret = crtc->funcs->set_config(&fb_helper->crtc_info->mode_set);
+                       mutex_unlock(&dev->mode_config.mutex);
+                       if (ret)
+                               return ret;
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_set_par);
+
+int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
+                             struct fb_info *info)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+       struct drm_device *dev = fb_helper->dev;
+       struct drm_mode_set *modeset;
+       struct drm_crtc *crtc;
+       int ret = 0;
+       int i;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               for (i = 0; i < fb_helper->crtc_count; i++) {
+                       if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
+                               break;
+               }
+
+               if (i == fb_helper->crtc_count)
+                       continue;
+
+               modeset = &fb_helper->crtc_info[i].mode_set;
+
+               modeset->x = var->xoffset;
+               modeset->y = var->yoffset;
+
+               if (modeset->num_connectors) {
+                       mutex_lock(&dev->mode_config.mutex);
+                       ret = crtc->funcs->set_config(modeset);
+                       mutex_unlock(&dev->mode_config.mutex);
+                       if (!ret) {
+                               info->var.xoffset = var->xoffset;
+                               info->var.yoffset = var->yoffset;
+                       }
+               }
+       }
+       return ret;
+}
+EXPORT_SYMBOL(drm_fb_helper_pan_display);
+
+int drm_fb_helper_single_fb_probe(struct drm_device *dev,
+                                 int (*fb_create)(struct drm_device *dev,
+                                                  uint32_t fb_width,
+                                                  uint32_t fb_height,
+                                                  uint32_t surface_width,
+                                                  uint32_t surface_height,
+                                                  struct drm_framebuffer **fb_ptr))
+{
+       struct drm_crtc *crtc;
+       struct drm_connector *connector;
+       unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
+       unsigned int surface_width = 0, surface_height = 0;
+       int new_fb = 0;
+       int crtc_count = 0;
+       int ret, i, conn_count = 0;
+       struct fb_info *info;
+       struct drm_framebuffer *fb;
+       struct drm_mode_set *modeset = NULL;
+       struct drm_fb_helper *fb_helper;
+
+       /* first up get a count of crtcs now in use and new min/maxes width/heights */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (drm_helper_crtc_in_use(crtc)) {
+                       if (crtc->desired_mode) {
+                               if (crtc->desired_mode->hdisplay < fb_width)
+                                       fb_width = crtc->desired_mode->hdisplay;
+
+                               if (crtc->desired_mode->vdisplay < fb_height)
+                                       fb_height = crtc->desired_mode->vdisplay;
+
+                               if (crtc->desired_mode->hdisplay > surface_width)
+                                       surface_width = crtc->desired_mode->hdisplay;
+
+                               if (crtc->desired_mode->vdisplay > surface_height)
+                                       surface_height = crtc->desired_mode->vdisplay;
+                       }
+                       crtc_count++;
+               }
+       }
+
+       if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
+               /* hmm everyone went away - assume VGA cable just fell out
+                  and will come back later. */
+               return 0;
+       }
+
+       /* do we have an fb already? */
+       if (list_empty(&dev->mode_config.fb_kernel_list)) {
+               ret = (*fb_create)(dev, fb_width, fb_height, surface_width,
+                                  surface_height, &fb);
+               if (ret)
+                       return -EINVAL;
+               new_fb = 1;
+       } else {
+               fb = list_first_entry(&dev->mode_config.fb_kernel_list,
+                                     struct drm_framebuffer, filp_head);
+
+               /* if someone hotplugs something bigger than we have already allocated, we are pwned.
+                  As really we can't resize an fbdev that is in the wild currently due to fbdev
+                  not really being designed for the lower layers moving stuff around under it.
+                  - so in the grand style of things - punt. */
+               if ((fb->width < surface_width) ||
+                   (fb->height < surface_height)) {
+                       DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
+                       return -EINVAL;
+               }
+       }
+
+       info = fb->fbdev;
+       fb_helper = info->par;
+
+       crtc_count = 0;
+       /* okay we need to setup new connector sets in the crtcs */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               modeset = &fb_helper->crtc_info[crtc_count].mode_set;
+               modeset->fb = fb;
+               conn_count = 0;
+               list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+                       if (connector->encoder)
+                               if (connector->encoder->crtc == modeset->crtc) {
+                                       modeset->connectors[conn_count] = connector;
+                                       conn_count++;
+                                       if (conn_count > fb_helper->conn_limit)
+                                               BUG();
+                               }
+               }
+
+               for (i = conn_count; i < fb_helper->conn_limit; i++)
+                       modeset->connectors[i] = NULL;
+
+               modeset->crtc = crtc;
+               crtc_count++;
+
+               modeset->num_connectors = conn_count;
+               if (modeset->crtc->desired_mode) {
+                       if (modeset->mode)
+                               drm_mode_destroy(dev, modeset->mode);
+                       modeset->mode = drm_mode_duplicate(dev,
+                                                          modeset->crtc->desired_mode);
+               }
+       }
+       fb_helper->crtc_count = crtc_count;
+       fb_helper->fb = fb;
+
+       if (new_fb) {
+               info->var.pixclock = -1;
+               if (register_framebuffer(info) < 0)
+                       return -EINVAL;
+       } else {
+               drm_fb_helper_set_par(info);
+       }
+       printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+              info->fix.id);
+
+       /* Switch back to kernel console on panic */
+       /* multi card linked list maybe */
+       if (list_empty(&kernel_fb_helper_list)) {
+               printk(KERN_INFO "registered panic notifier\n");
+               atomic_notifier_chain_register(&panic_notifier_list,
+                                              &paniced);
+               register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
+       }
+       list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
+       return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
+
+void drm_fb_helper_free(struct drm_fb_helper *helper)
+{
+       list_del(&helper->kernel_fb_list);
+       if (list_empty(&kernel_fb_helper_list)) {
+               printk(KERN_INFO "unregistered panic notifier\n");
+               atomic_notifier_chain_unregister(&panic_notifier_list,
+                                                &paniced);
+               unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
+       }
+       drm_fb_helper_crtc_free(helper);
+}
+EXPORT_SYMBOL(drm_fb_helper_free);
+
+void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch)
+{
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->fix.type_aux = 0;
+       info->fix.xpanstep = 1; /* doing it in hw */
+       info->fix.ypanstep = 1; /* doing it in hw */
+       info->fix.ywrapstep = 0;
+       info->fix.accel = FB_ACCEL_NONE;
+       info->fix.type_aux = 0;
+
+       info->fix.line_length = pitch;
+       return;
+}
+EXPORT_SYMBOL(drm_fb_helper_fill_fix);
+
+void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb,
+                           uint32_t fb_width, uint32_t fb_height)
+{
+       info->pseudo_palette = fb->pseudo_palette;
+       info->var.xres_virtual = fb->width;
+       info->var.yres_virtual = fb->height;
+       info->var.bits_per_pixel = fb->bits_per_pixel;
+       info->var.xoffset = 0;
+       info->var.yoffset = 0;
+       info->var.activate = FB_ACTIVATE_NOW;
+       info->var.height = -1;
+       info->var.width = -1;
+
+       switch (fb->depth) {
+       case 8:
+               info->var.red.offset = 0;
+               info->var.green.offset = 0;
+               info->var.blue.offset = 0;
+               info->var.red.length = 8; /* 8bit DAC */
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.transp.offset = 0;
+               info->var.transp.length = 0;
+               break;
+       case 15:
+               info->var.red.offset = 10;
+               info->var.green.offset = 5;
+               info->var.blue.offset = 0;
+               info->var.red.length = 5;
+               info->var.green.length = 5;
+               info->var.blue.length = 5;
+               info->var.transp.offset = 15;
+               info->var.transp.length = 1;
+               break;
+       case 16:
+               info->var.red.offset = 11;
+               info->var.green.offset = 5;
+               info->var.blue.offset = 0;
+               info->var.red.length = 5;
+               info->var.green.length = 6;
+               info->var.blue.length = 5;
+               info->var.transp.offset = 0;
+               break;
+       case 24:
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+               info->var.red.length = 8;
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.transp.offset = 0;
+               info->var.transp.length = 0;
+               break;
+       case 32:
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+               info->var.red.length = 8;
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.transp.offset = 24;
+               info->var.transp.length = 8;
+               break;
+       default:
+               break;
+       }
+
+       info->var.xres = fb_width;
+       info->var.yres = fb_height;
+}
+EXPORT_SYMBOL(drm_fb_helper_fill_var);
index ffe8f43..230c9ff 100644 (file)
@@ -164,7 +164,7 @@ EXPORT_SYMBOL(drm_gem_object_alloc);
  * Removes the mapping from handle to filp for this object.
  */
 static int
-drm_gem_handle_delete(struct drm_file *filp, int handle)
+drm_gem_handle_delete(struct drm_file *filp, u32 handle)
 {
        struct drm_device *dev;
        struct drm_gem_object *obj;
@@ -207,7 +207,7 @@ drm_gem_handle_delete(struct drm_file *filp, int handle)
 int
 drm_gem_handle_create(struct drm_file *file_priv,
                       struct drm_gem_object *obj,
-                      int *handlep)
+                      u32 *handlep)
 {
        int     ret;
 
@@ -221,7 +221,7 @@ again:
 
        /* do the allocation under our spinlock */
        spin_lock(&file_priv->table_lock);
-       ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep);
+       ret = idr_get_new_above(&file_priv->object_idr, obj, 1, (int *)handlep);
        spin_unlock(&file_priv->table_lock);
        if (ret == -EAGAIN)
                goto again;
@@ -237,7 +237,7 @@ EXPORT_SYMBOL(drm_gem_handle_create);
 /** Returns a reference to the object named by the handle. */
 struct drm_gem_object *
 drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
-                     int handle)
+                     u32 handle)
 {
        struct drm_gem_object *obj;
 
@@ -344,7 +344,7 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
        struct drm_gem_open *args = data;
        struct drm_gem_object *obj;
        int ret;
-       int handle;
+       u32 handle;
 
        if (!(dev->driver->driver_features & DRIVER_GEM))
                return -ENODEV;
@@ -539,7 +539,6 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
        vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
        vma->vm_ops = obj->dev->driver->gem_vm_ops;
        vma->vm_private_data = map->handle;
-       /* FIXME: use pgprot_writecombine when available */
        vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 
        /* Take a ref for this mapping of the object, so that the fault
index f85aaf2..0a6f0b3 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <linux/interrupt.h>   /* For task queue support */
 
+#include <linux/vgaarb.h>
 /**
  * Get interrupt from bus id.
  *
@@ -171,6 +172,26 @@ err:
 }
 EXPORT_SYMBOL(drm_vblank_init);
 
+static void drm_irq_vgaarb_nokms(void *cookie, bool state)
+{
+       struct drm_device *dev = cookie;
+
+       if (dev->driver->vgaarb_irq) {
+               dev->driver->vgaarb_irq(dev, state);
+               return;
+       }
+
+       if (!dev->irq_enabled)
+               return;
+
+       if (state)
+               dev->driver->irq_uninstall(dev);
+       else {
+               dev->driver->irq_preinstall(dev);
+               dev->driver->irq_postinstall(dev);
+       }
+}
+
 /**
  * Install IRQ handler.
  *
@@ -231,6 +252,9 @@ int drm_irq_install(struct drm_device *dev)
                return ret;
        }
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL);
+
        /* After installing handler */
        ret = dev->driver->irq_postinstall(dev);
        if (ret < 0) {
@@ -279,6 +303,9 @@ int drm_irq_uninstall(struct drm_device * dev)
 
        DRM_DEBUG("irq=%d\n", dev->pdev->irq);
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               vga_client_register(dev->pdev, NULL, NULL, NULL);
+
        dev->driver->irq_uninstall(dev);
 
        free_irq(dev->pdev->irq, dev);
index 3e47869..c861d80 100644 (file)
@@ -44,6 +44,7 @@
 #include "drmP.h"
 #include "drm_mm.h"
 #include <linux/slab.h>
+#include <linux/seq_file.h>
 
 #define MM_UNUSED_TARGET 4
 
@@ -370,3 +371,23 @@ void drm_mm_takedown(struct drm_mm * mm)
        BUG_ON(mm->num_unused != 0);
 }
 EXPORT_SYMBOL(drm_mm_takedown);
+
+#if defined(CONFIG_DEBUG_FS)
+int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
+{
+       struct drm_mm_node *entry;
+       int total_used = 0, total_free = 0, total = 0;
+
+       list_for_each_entry(entry, &mm->ml_entry, ml_entry) {
+               seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: %s\n", entry->start, entry->start + entry->size, entry->size, entry->free ? "free" : "used");
+               total += entry->size;
+               if (entry->free)
+                       total_free += entry->size;
+               else
+                       total_used += entry->size;
+       }
+       seq_printf(m, "total: %d, used %d free %d\n", total, total_free, total_used);
+       return 0;
+}
+EXPORT_SYMBOL(drm_mm_dump_table);
+#endif
index 7914097..49404ce 100644 (file)
@@ -8,6 +8,8 @@
  * Copyright © 2007 Dave Airlie
  * Copyright © 2007-2008 Intel Corporation
  *   Jesse Barnes <jesse.barnes@intel.com>
+ * Copyright 2005-2006 Luc Verhaegen
+ * Copyright (c) 2001, Andy Ritger  aritger@nvidia.com
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -38,7 +40,6 @@
 #include "drm.h"
 #include "drm_crtc.h"
 
-#define DRM_MODESET_DEBUG      "drm_mode"
 /**
  * drm_mode_debug_printmodeline - debug print a mode
  * @dev: DRM device
@@ -51,8 +52,8 @@
  */
 void drm_mode_debug_printmodeline(struct drm_display_mode *mode)
 {
-       DRM_DEBUG_MODE(DRM_MODESET_DEBUG,
-               "Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
+       DRM_DEBUG_KMS("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d "
+                       "0x%x 0x%x\n",
                mode->base.id, mode->name, mode->vrefresh, mode->clock,
                mode->hdisplay, mode->hsync_start,
                mode->hsync_end, mode->htotal,
@@ -62,6 +63,420 @@ void drm_mode_debug_printmodeline(struct drm_display_mode *mode)
 EXPORT_SYMBOL(drm_mode_debug_printmodeline);
 
 /**
+ * drm_cvt_mode -create a modeline based on CVT algorithm
+ * @dev: DRM device
+ * @hdisplay: hdisplay size
+ * @vdisplay: vdisplay size
+ * @vrefresh  : vrefresh rate
+ * @reduced : Whether the GTF calculation is simplified
+ * @interlaced:Whether the interlace is supported
+ *
+ * LOCKING:
+ * none.
+ *
+ * return the modeline based on CVT algorithm
+ *
+ * This function is called to generate the modeline based on CVT algorithm
+ * according to the hdisplay, vdisplay, vrefresh.
+ * It is based from the VESA(TM) Coordinated Video Timing Generator by
+ * Graham Loveridge April 9, 2003 available at
+ * http://www.vesa.org/public/CVT/CVTd6r1.xls
+ *
+ * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c.
+ * What I have done is to translate it by using integer calculation.
+ */
+#define HV_FACTOR                      1000
+struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
+                                     int vdisplay, int vrefresh,
+                                     bool reduced, bool interlaced)
+{
+       /* 1) top/bottom margin size (% of height) - default: 1.8, */
+#define        CVT_MARGIN_PERCENTAGE           18
+       /* 2) character cell horizontal granularity (pixels) - default 8 */
+#define        CVT_H_GRANULARITY               8
+       /* 3) Minimum vertical porch (lines) - default 3 */
+#define        CVT_MIN_V_PORCH                 3
+       /* 4) Minimum number of vertical back porch lines - default 6 */
+#define        CVT_MIN_V_BPORCH                6
+       /* Pixel Clock step (kHz) */
+#define CVT_CLOCK_STEP                 250
+       struct drm_display_mode *drm_mode;
+       bool margins = false;
+       unsigned int vfieldrate, hperiod;
+       int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync;
+       int interlace;
+
+       /* allocate the drm_display_mode structure. If failure, we will
+        * return directly
+        */
+       drm_mode = drm_mode_create(dev);
+       if (!drm_mode)
+               return NULL;
+
+       /* the CVT default refresh rate is 60Hz */
+       if (!vrefresh)
+               vrefresh = 60;
+
+       /* the required field fresh rate */
+       if (interlaced)
+               vfieldrate = vrefresh * 2;
+       else
+               vfieldrate = vrefresh;
+
+       /* horizontal pixels */
+       hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY);
+
+       /* determine the left&right borders */
+       hmargin = 0;
+       if (margins) {
+               hmargin = hdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
+               hmargin -= hmargin % CVT_H_GRANULARITY;
+       }
+       /* find the total active pixels */
+       drm_mode->hdisplay = hdisplay_rnd + 2 * hmargin;
+
+       /* find the number of lines per field */
+       if (interlaced)
+               vdisplay_rnd = vdisplay / 2;
+       else
+               vdisplay_rnd = vdisplay;
+
+       /* find the top & bottom borders */
+       vmargin = 0;
+       if (margins)
+               vmargin = vdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
+
+       drm_mode->vdisplay = vdisplay + 2 * vmargin;
+
+       /* Interlaced */
+       if (interlaced)
+               interlace = 1;
+       else
+               interlace = 0;
+
+       /* Determine VSync Width from aspect ratio */
+       if (!(vdisplay % 3) && ((vdisplay * 4 / 3) == hdisplay))
+               vsync = 4;
+       else if (!(vdisplay % 9) && ((vdisplay * 16 / 9) == hdisplay))
+               vsync = 5;
+       else if (!(vdisplay % 10) && ((vdisplay * 16 / 10) == hdisplay))
+               vsync = 6;
+       else if (!(vdisplay % 4) && ((vdisplay * 5 / 4) == hdisplay))
+               vsync = 7;
+       else if (!(vdisplay % 9) && ((vdisplay * 15 / 9) == hdisplay))
+               vsync = 7;
+       else /* custom */
+               vsync = 10;
+
+       if (!reduced) {
+               /* simplify the GTF calculation */
+               /* 4) Minimum time of vertical sync + back porch interval (µs)
+                * default 550.0
+                */
+               int tmp1, tmp2;
+#define CVT_MIN_VSYNC_BP       550
+               /* 3) Nominal HSync width (% of line period) - default 8 */
+#define CVT_HSYNC_PERCENTAGE   8
+               unsigned int hblank_percentage;
+               int vsyncandback_porch, vback_porch, hblank;
+
+               /* estimated the horizontal period */
+               tmp1 = HV_FACTOR * 1000000  -
+                               CVT_MIN_VSYNC_BP * HV_FACTOR * vfieldrate;
+               tmp2 = (vdisplay_rnd + 2 * vmargin + CVT_MIN_V_PORCH) * 2 +
+                               interlace;
+               hperiod = tmp1 * 2 / (tmp2 * vfieldrate);
+
+               tmp1 = CVT_MIN_VSYNC_BP * HV_FACTOR / hperiod + 1;
+               /* 9. Find number of lines in sync + backporch */
+               if (tmp1 < (vsync + CVT_MIN_V_PORCH))
+                       vsyncandback_porch = vsync + CVT_MIN_V_PORCH;
+               else
+                       vsyncandback_porch = tmp1;
+               /* 10. Find number of lines in back porch */
+               vback_porch = vsyncandback_porch - vsync;
+               drm_mode->vtotal = vdisplay_rnd + 2 * vmargin +
+                               vsyncandback_porch + CVT_MIN_V_PORCH;
+               /* 5) Definition of Horizontal blanking time limitation */
+               /* Gradient (%/kHz) - default 600 */
+#define CVT_M_FACTOR   600
+               /* Offset (%) - default 40 */
+#define CVT_C_FACTOR   40
+               /* Blanking time scaling factor - default 128 */
+#define CVT_K_FACTOR   128
+               /* Scaling factor weighting - default 20 */
+#define CVT_J_FACTOR   20
+#define CVT_M_PRIME    (CVT_M_FACTOR * CVT_K_FACTOR / 256)
+#define CVT_C_PRIME    ((CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
+                        CVT_J_FACTOR)
+               /* 12. Find ideal blanking duty cycle from formula */
+               hblank_percentage = CVT_C_PRIME * HV_FACTOR - CVT_M_PRIME *
+                                       hperiod / 1000;
+               /* 13. Blanking time */
+               if (hblank_percentage < 20 * HV_FACTOR)
+                       hblank_percentage = 20 * HV_FACTOR;
+               hblank = drm_mode->hdisplay * hblank_percentage /
+                        (100 * HV_FACTOR - hblank_percentage);
+               hblank -= hblank % (2 * CVT_H_GRANULARITY);
+               /* 14. find the total pixes per line */
+               drm_mode->htotal = drm_mode->hdisplay + hblank;
+               drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2;
+               drm_mode->hsync_start = drm_mode->hsync_end -
+                       (drm_mode->htotal * CVT_HSYNC_PERCENTAGE) / 100;
+               drm_mode->hsync_start += CVT_H_GRANULARITY -
+                       drm_mode->hsync_start % CVT_H_GRANULARITY;
+               /* fill the Vsync values */
+               drm_mode->vsync_start = drm_mode->vdisplay + CVT_MIN_V_PORCH;
+               drm_mode->vsync_end = drm_mode->vsync_start + vsync;
+       } else {
+               /* Reduced blanking */
+               /* Minimum vertical blanking interval time (µs)- default 460 */
+#define CVT_RB_MIN_VBLANK      460
+               /* Fixed number of clocks for horizontal sync */
+#define CVT_RB_H_SYNC          32
+               /* Fixed number of clocks for horizontal blanking */
+#define CVT_RB_H_BLANK         160
+               /* Fixed number of lines for vertical front porch - default 3*/
+#define CVT_RB_VFPORCH         3
+               int vbilines;
+               int tmp1, tmp2;
+               /* 8. Estimate Horizontal period. */
+               tmp1 = HV_FACTOR * 1000000 -
+                       CVT_RB_MIN_VBLANK * HV_FACTOR * vfieldrate;
+               tmp2 = vdisplay_rnd + 2 * vmargin;
+               hperiod = tmp1 / (tmp2 * vfieldrate);
+               /* 9. Find number of lines in vertical blanking */
+               vbilines = CVT_RB_MIN_VBLANK * HV_FACTOR / hperiod + 1;
+               /* 10. Check if vertical blanking is sufficient */
+               if (vbilines < (CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH))
+                       vbilines = CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH;
+               /* 11. Find total number of lines in vertical field */
+               drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + vbilines;
+               /* 12. Find total number of pixels in a line */
+               drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK;
+               /* Fill in HSync values */
+               drm_mode->hsync_end = drm_mode->hdisplay + CVT_RB_H_BLANK / 2;
+               drm_mode->hsync_start = drm_mode->hsync_end = CVT_RB_H_SYNC;
+       }
+       /* 15/13. Find pixel clock frequency (kHz for xf86) */
+       drm_mode->clock = drm_mode->htotal * HV_FACTOR * 1000 / hperiod;
+       drm_mode->clock -= drm_mode->clock % CVT_CLOCK_STEP;
+       /* 18/16. Find actual vertical frame frequency */
+       /* ignore - just set the mode flag for interlaced */
+       if (interlaced)
+               drm_mode->vtotal *= 2;
+       /* Fill the mode line name */
+       drm_mode_set_name(drm_mode);
+       if (reduced)
+               drm_mode->flags |= (DRM_MODE_FLAG_PHSYNC |
+                                       DRM_MODE_FLAG_NVSYNC);
+       else
+               drm_mode->flags |= (DRM_MODE_FLAG_PVSYNC |
+                                       DRM_MODE_FLAG_NHSYNC);
+       if (interlaced)
+               drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
+
+    return drm_mode;
+}
+EXPORT_SYMBOL(drm_cvt_mode);
+
+/**
+ * drm_gtf_mode - create the modeline based on GTF algorithm
+ *
+ * @dev                :drm device
+ * @hdisplay   :hdisplay size
+ * @vdisplay   :vdisplay size
+ * @vrefresh   :vrefresh rate.
+ * @interlaced :whether the interlace is supported
+ * @margins    :whether the margin is supported
+ *
+ * LOCKING.
+ * none.
+ *
+ * return the modeline based on GTF algorithm
+ *
+ * This function is to create the modeline based on the GTF algorithm.
+ * Generalized Timing Formula is derived from:
+ *     GTF Spreadsheet by Andy Morrish (1/5/97)
+ *     available at http://www.vesa.org
+ *
+ * And it is copied from the file of xserver/hw/xfree86/modes/xf86gtf.c.
+ * What I have done is to translate it by using integer calculation.
+ * I also refer to the function of fb_get_mode in the file of
+ * drivers/video/fbmon.c
+ */
+struct drm_display_mode *drm_gtf_mode(struct drm_device *dev, int hdisplay,
+                                     int vdisplay, int vrefresh,
+                                     bool interlaced, int margins)
+{
+       /* 1) top/bottom margin size (% of height) - default: 1.8, */
+#define        GTF_MARGIN_PERCENTAGE           18
+       /* 2) character cell horizontal granularity (pixels) - default 8 */
+#define        GTF_CELL_GRAN                   8
+       /* 3) Minimum vertical porch (lines) - default 3 */
+#define        GTF_MIN_V_PORCH                 1
+       /* width of vsync in lines */
+#define V_SYNC_RQD                     3
+       /* width of hsync as % of total line */
+#define H_SYNC_PERCENT                 8
+       /* min time of vsync + back porch (microsec) */
+#define MIN_VSYNC_PLUS_BP              550
+       /* blanking formula gradient */
+#define GTF_M                          600
+       /* blanking formula offset */
+#define GTF_C                          40
+       /* blanking formula scaling factor */
+#define GTF_K                          128
+       /* blanking formula scaling factor */
+#define GTF_J                          20
+       /* C' and M' are part of the Blanking Duty Cycle computation */
+#define GTF_C_PRIME            (((GTF_C - GTF_J) * GTF_K / 256) + GTF_J)
+#define GTF_M_PRIME            (GTF_K * GTF_M / 256)
+       struct drm_display_mode *drm_mode;
+       unsigned int hdisplay_rnd, vdisplay_rnd, vfieldrate_rqd;
+       int top_margin, bottom_margin;
+       int interlace;
+       unsigned int hfreq_est;
+       int vsync_plus_bp, vback_porch;
+       unsigned int vtotal_lines, vfieldrate_est, hperiod;
+       unsigned int vfield_rate, vframe_rate;
+       int left_margin, right_margin;
+       unsigned int total_active_pixels, ideal_duty_cycle;
+       unsigned int hblank, total_pixels, pixel_freq;
+       int hsync, hfront_porch, vodd_front_porch_lines;
+       unsigned int tmp1, tmp2;
+
+       drm_mode = drm_mode_create(dev);
+       if (!drm_mode)
+               return NULL;
+
+       /* 1. In order to give correct results, the number of horizontal
+        * pixels requested is first processed to ensure that it is divisible
+        * by the character size, by rounding it to the nearest character
+        * cell boundary:
+        */
+       hdisplay_rnd = (hdisplay + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
+       hdisplay_rnd = hdisplay_rnd * GTF_CELL_GRAN;
+
+       /* 2. If interlace is requested, the number of vertical lines assumed
+        * by the calculation must be halved, as the computation calculates
+        * the number of vertical lines per field.
+        */
+       if (interlaced)
+               vdisplay_rnd = vdisplay / 2;
+       else
+               vdisplay_rnd = vdisplay;
+
+       /* 3. Find the frame rate required: */
+       if (interlaced)
+               vfieldrate_rqd = vrefresh * 2;
+       else
+               vfieldrate_rqd = vrefresh;
+
+       /* 4. Find number of lines in Top margin: */
+       top_margin = 0;
+       if (margins)
+               top_margin = (vdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
+                               1000;
+       /* 5. Find number of lines in bottom margin: */
+       bottom_margin = top_margin;
+
+       /* 6. If interlace is required, then set variable interlace: */
+       if (interlaced)
+               interlace = 1;
+       else
+               interlace = 0;
+
+       /* 7. Estimate the Horizontal frequency */
+       {
+               tmp1 = (1000000  - MIN_VSYNC_PLUS_BP * vfieldrate_rqd) / 500;
+               tmp2 = (vdisplay_rnd + 2 * top_margin + GTF_MIN_V_PORCH) *
+                               2 + interlace;
+               hfreq_est = (tmp2 * 1000 * vfieldrate_rqd) / tmp1;
+       }
+
+       /* 8. Find the number of lines in V sync + back porch */
+       /* [V SYNC+BP] = RINT(([MIN VSYNC+BP] * hfreq_est / 1000000)) */
+       vsync_plus_bp = MIN_VSYNC_PLUS_BP * hfreq_est / 1000;
+       vsync_plus_bp = (vsync_plus_bp + 500) / 1000;
+       /*  9. Find the number of lines in V back porch alone: */
+       vback_porch = vsync_plus_bp - V_SYNC_RQD;
+       /*  10. Find the total number of lines in Vertical field period: */
+       vtotal_lines = vdisplay_rnd + top_margin + bottom_margin +
+                       vsync_plus_bp + GTF_MIN_V_PORCH;
+       /*  11. Estimate the Vertical field frequency: */
+       vfieldrate_est = hfreq_est / vtotal_lines;
+       /*  12. Find the actual horizontal period: */
+       hperiod = 1000000 / (vfieldrate_rqd * vtotal_lines);
+
+       /*  13. Find the actual Vertical field frequency: */
+       vfield_rate = hfreq_est / vtotal_lines;
+       /*  14. Find the Vertical frame frequency: */
+       if (interlaced)
+               vframe_rate = vfield_rate / 2;
+       else
+               vframe_rate = vfield_rate;
+       /*  15. Find number of pixels in left margin: */
+       if (margins)
+               left_margin = (hdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
+                               1000;
+       else
+               left_margin = 0;
+
+       /* 16.Find number of pixels in right margin: */
+       right_margin = left_margin;
+       /* 17.Find total number of active pixels in image and left and right */
+       total_active_pixels = hdisplay_rnd + left_margin + right_margin;
+       /* 18.Find the ideal blanking duty cycle from blanking duty cycle */
+       ideal_duty_cycle = GTF_C_PRIME * 1000 -
+                               (GTF_M_PRIME * 1000000 / hfreq_est);
+       /* 19.Find the number of pixels in the blanking time to the nearest
+        * double character cell: */
+       hblank = total_active_pixels * ideal_duty_cycle /
+                       (100000 - ideal_duty_cycle);
+       hblank = (hblank + GTF_CELL_GRAN) / (2 * GTF_CELL_GRAN);
+       hblank = hblank * 2 * GTF_CELL_GRAN;
+       /* 20.Find total number of pixels: */
+       total_pixels = total_active_pixels + hblank;
+       /* 21.Find pixel clock frequency: */
+       pixel_freq = total_pixels * hfreq_est / 1000;
+       /* Stage 1 computations are now complete; I should really pass
+        * the results to another function and do the Stage 2 computations,
+        * but I only need a few more values so I'll just append the
+        * computations here for now */
+       /* 17. Find the number of pixels in the horizontal sync period: */
+       hsync = H_SYNC_PERCENT * total_pixels / 100;
+       hsync = (hsync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
+       hsync = hsync * GTF_CELL_GRAN;
+       /* 18. Find the number of pixels in horizontal front porch period */
+       hfront_porch = hblank / 2 - hsync;
+       /*  36. Find the number of lines in the odd front porch period: */
+       vodd_front_porch_lines = GTF_MIN_V_PORCH ;
+
+       /* finally, pack the results in the mode struct */
+       drm_mode->hdisplay = hdisplay_rnd;
+       drm_mode->hsync_start = hdisplay_rnd + hfront_porch;
+       drm_mode->hsync_end = drm_mode->hsync_start + hsync;
+       drm_mode->htotal = total_pixels;
+       drm_mode->vdisplay = vdisplay_rnd;
+       drm_mode->vsync_start = vdisplay_rnd + vodd_front_porch_lines;
+       drm_mode->vsync_end = drm_mode->vsync_start + V_SYNC_RQD;
+       drm_mode->vtotal = vtotal_lines;
+
+       drm_mode->clock = pixel_freq;
+
+       drm_mode_set_name(drm_mode);
+       drm_mode->flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC;
+
+       if (interlaced) {
+               drm_mode->vtotal *= 2;
+               drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
+       }
+
+       return drm_mode;
+}
+EXPORT_SYMBOL(drm_gtf_mode);
+/**
  * drm_mode_set_name - set the name on a mode
  * @mode: name will be set in this mode
  *
@@ -151,7 +566,9 @@ EXPORT_SYMBOL(drm_mode_height);
  * FIXME: why is this needed?  shouldn't vrefresh be set already?
  *
  * RETURNS:
- * Vertical refresh rate of @mode x 1000. For precision reasons.
+ * Vertical refresh rate. It will be the result of actual value plus 0.5.
+ * If it is 70.288, it will return 70Hz.
+ * If it is 59.6, it will return 60Hz.
  */
 int drm_mode_vrefresh(struct drm_display_mode *mode)
 {
@@ -161,14 +578,13 @@ int drm_mode_vrefresh(struct drm_display_mode *mode)
        if (mode->vrefresh > 0)
                refresh = mode->vrefresh;
        else if (mode->htotal > 0 && mode->vtotal > 0) {
+               int vtotal;
+               vtotal = mode->vtotal;
                /* work out vrefresh the value will be x1000 */
                calc_val = (mode->clock * 1000);
-
                calc_val /= mode->htotal;
-               calc_val *= 1000;
-               calc_val /= mode->vtotal;
+               refresh = (calc_val + vtotal / 2) / vtotal;
 
-               refresh = calc_val;
                if (mode->flags & DRM_MODE_FLAG_INTERLACE)
                        refresh *= 2;
                if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
@@ -403,8 +819,7 @@ void drm_mode_prune_invalid(struct drm_device *dev,
                        list_del(&mode->head);
                        if (verbose) {
                                drm_mode_debug_printmodeline(mode);
-                               DRM_DEBUG_MODE(DRM_MODESET_DEBUG,
-                                       "Not using %s mode %d\n",
+                               DRM_DEBUG_KMS("Not using %s mode %d\n",
                                        mode->name, mode->status);
                        }
                        drm_mode_destroy(dev, mode);
index bbd4b3d..d379c4f 100644 (file)
@@ -106,20 +106,25 @@ int drm_proc_create_files(struct drm_info_list *files, int count,
                        continue;
 
                tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL);
-               ent = create_proc_entry(files[i].name, S_IFREG | S_IRUGO, root);
+               if (tmp == NULL) {
+                       ret = -1;
+                       goto fail;
+               }
+               tmp->minor = minor;
+               tmp->info_ent = &files[i];
+               list_add(&tmp->list, &minor->proc_nodes.list);
+
+               ent = proc_create_data(files[i].name, S_IRUGO, root,
+                                      &drm_proc_fops, tmp);
                if (!ent) {
                        DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
                                  name, files[i].name);
+                       list_del(&tmp->list);
                        kfree(tmp);
                        ret = -1;
                        goto fail;
                }
 
-               ent->proc_fops = &drm_proc_fops;
-               ent->data = tmp;
-               tmp->minor = minor;
-               tmp->info_ent = &files[i];
-               list_add(&(tmp->list), &(minor->proc_nodes.list));
        }
        return 0;
 
index 5301f22..7e42b7e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kdev_t.h>
 #include <linux/err.h>
 
+#include "drm_sysfs.h"
 #include "drm_core.h"
 #include "drmP.h"
 
@@ -253,6 +254,7 @@ static ssize_t subconnector_show(struct device *device,
                case DRM_MODE_CONNECTOR_Composite:
                case DRM_MODE_CONNECTOR_SVIDEO:
                case DRM_MODE_CONNECTOR_Component:
+               case DRM_MODE_CONNECTOR_TV:
                        prop = dev->mode_config.tv_subconnector_property;
                        is_tv = 1;
                        break;
@@ -293,6 +295,7 @@ static ssize_t select_subconnector_show(struct device *device,
                case DRM_MODE_CONNECTOR_Composite:
                case DRM_MODE_CONNECTOR_SVIDEO:
                case DRM_MODE_CONNECTOR_Component:
+               case DRM_MODE_CONNECTOR_TV:
                        prop = dev->mode_config.tv_select_subconnector_property;
                        is_tv = 1;
                        break;
@@ -391,6 +394,7 @@ int drm_sysfs_connector_add(struct drm_connector *connector)
                case DRM_MODE_CONNECTOR_Composite:
                case DRM_MODE_CONNECTOR_SVIDEO:
                case DRM_MODE_CONNECTOR_Component:
+               case DRM_MODE_CONNECTOR_TV:
                        for (i = 0; i < ARRAY_SIZE(connector_attrs_opt1); i++) {
                                ret = device_create_file(&connector->kdev, &connector_attrs_opt1[i]);
                                if (ret)
@@ -519,3 +523,27 @@ void drm_sysfs_device_remove(struct drm_minor *minor)
 {
        device_unregister(&minor->kdev);
 }
+
+
+/**
+ * drm_class_device_register - Register a struct device in the drm class.
+ *
+ * @dev: pointer to struct device to register.
+ *
+ * @dev should have all relevant members pre-filled with the exception
+ * of the class member. In particular, the device_type member must
+ * be set.
+ */
+
+int drm_class_device_register(struct device *dev)
+{
+       dev->class = drm_class;
+       return device_register(dev);
+}
+EXPORT_SYMBOL_GPL(drm_class_device_register);
+
+void drm_class_device_unregister(struct device *dev)
+{
+       return device_unregister(dev);
+}
+EXPORT_SYMBOL_GPL(drm_class_device_unregister);
index 30d6b99..5269dfa 100644 (file)
@@ -4,10 +4,10 @@
 
 ccflags-y := -Iinclude/drm
 i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
+         i915_debugfs.o \
           i915_suspend.o \
          i915_gem.o \
          i915_gem_debug.o \
-         i915_gem_debugfs.o \
          i915_gem_tiling.o \
          intel_display.o \
          intel_crt.o \
similarity index 79%
rename from drivers/gpu/drm/i915/i915_gem_debugfs.c
rename to drivers/gpu/drm/i915/i915_debugfs.c
index cb3b974..1e3bdce 100644 (file)
@@ -158,16 +158,37 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
-       seq_printf(m, "Interrupt enable:    %08x\n",
-                  I915_READ(IER));
-       seq_printf(m, "Interrupt identity:  %08x\n",
-                  I915_READ(IIR));
-       seq_printf(m, "Interrupt mask:      %08x\n",
-                  I915_READ(IMR));
-       seq_printf(m, "Pipe A stat:         %08x\n",
-                  I915_READ(PIPEASTAT));
-       seq_printf(m, "Pipe B stat:         %08x\n",
-                  I915_READ(PIPEBSTAT));
+       if (!IS_IGDNG(dev)) {
+               seq_printf(m, "Interrupt enable:    %08x\n",
+                          I915_READ(IER));
+               seq_printf(m, "Interrupt identity:  %08x\n",
+                          I915_READ(IIR));
+               seq_printf(m, "Interrupt mask:      %08x\n",
+                          I915_READ(IMR));
+               seq_printf(m, "Pipe A stat:         %08x\n",
+                          I915_READ(PIPEASTAT));
+               seq_printf(m, "Pipe B stat:         %08x\n",
+                          I915_READ(PIPEBSTAT));
+       } else {
+               seq_printf(m, "North Display Interrupt enable:          %08x\n",
+                          I915_READ(DEIER));
+               seq_printf(m, "North Display Interrupt identity:        %08x\n",
+                          I915_READ(DEIIR));
+               seq_printf(m, "North Display Interrupt mask:            %08x\n",
+                          I915_READ(DEIMR));
+               seq_printf(m, "South Display Interrupt enable:          %08x\n",
+                          I915_READ(SDEIER));
+               seq_printf(m, "South Display Interrupt identity:        %08x\n",
+                          I915_READ(SDEIIR));
+               seq_printf(m, "South Display Interrupt mask:            %08x\n",
+                          I915_READ(SDEIMR));
+               seq_printf(m, "Graphics Interrupt enable:               %08x\n",
+                          I915_READ(GTIER));
+               seq_printf(m, "Graphics Interrupt identity:             %08x\n",
+                          I915_READ(GTIIR));
+               seq_printf(m, "Graphics Interrupt mask:         %08x\n",
+                          I915_READ(GTIMR));
+       }
        seq_printf(m, "Interrupts received: %d\n",
                   atomic_read(&dev_priv->irq_received));
        if (dev_priv->hw_status_page != NULL) {
@@ -312,15 +333,13 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       unsigned int head, tail, mask;
+       unsigned int head, tail;
 
        head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
        tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
-       mask = dev_priv->ring.tail_mask;
 
        seq_printf(m, "RingHead :  %08x\n", head);
        seq_printf(m, "RingTail :  %08x\n", tail);
-       seq_printf(m, "RingMask :  %08x\n", mask);
        seq_printf(m, "RingSize :  %08lx\n", dev_priv->ring.Size);
        seq_printf(m, "Acthd :     %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD));
 
@@ -363,7 +382,37 @@ out:
        return 0;
 }
 
-static struct drm_info_list i915_gem_debugfs_list[] = {
+static int i915_registers_info(struct seq_file *m, void *data) {
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       uint32_t reg;
+
+#define DUMP_RANGE(start, end) \
+       for (reg=start; reg < end; reg += 4) \
+       seq_printf(m, "%08x\t%08x\n", reg, I915_READ(reg));
+
+       DUMP_RANGE(0x00000, 0x00fff);   /* VGA registers */
+       DUMP_RANGE(0x02000, 0x02fff);   /* instruction, memory, interrupt control registers */
+       DUMP_RANGE(0x03000, 0x031ff);   /* FENCE and PPGTT control registers */
+       DUMP_RANGE(0x03200, 0x03fff);   /* frame buffer compression registers */
+       DUMP_RANGE(0x05000, 0x05fff);   /* I/O control registers */
+       DUMP_RANGE(0x06000, 0x06fff);   /* clock control registers */
+       DUMP_RANGE(0x07000, 0x07fff);   /* 3D internal debug registers */
+       DUMP_RANGE(0x07400, 0x088ff);   /* GPE debug registers */
+       DUMP_RANGE(0x0a000, 0x0afff);   /* display palette registers */
+       DUMP_RANGE(0x10000, 0x13fff);   /* MMIO MCHBAR */
+       DUMP_RANGE(0x30000, 0x3ffff);   /* overlay registers */
+       DUMP_RANGE(0x60000, 0x6ffff);   /* display engine pipeline registers */
+       DUMP_RANGE(0x70000, 0x72fff);   /* display and cursor registers */
+       DUMP_RANGE(0x73000, 0x73fff);   /* performance counters */
+
+       return 0;
+}
+
+
+static struct drm_info_list i915_debugfs_list[] = {
+       {"i915_regs", i915_registers_info, 0},
        {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
        {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST},
        {"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST},
@@ -377,19 +426,19 @@ static struct drm_info_list i915_gem_debugfs_list[] = {
        {"i915_batchbuffers", i915_batchbuffer_info, 0},
        {"i915_error_state", i915_error_state, 0},
 };
-#define I915_GEM_DEBUGFS_ENTRIES ARRAY_SIZE(i915_gem_debugfs_list)
+#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
-int i915_gem_debugfs_init(struct drm_minor *minor)
+int i915_debugfs_init(struct drm_minor *minor)
 {
-       return drm_debugfs_create_files(i915_gem_debugfs_list,
-                                       I915_GEM_DEBUGFS_ENTRIES,
+       return drm_debugfs_create_files(i915_debugfs_list,
+                                       I915_DEBUGFS_ENTRIES,
                                        minor->debugfs_root, minor);
 }
 
-void i915_gem_debugfs_cleanup(struct drm_minor *minor)
+void i915_debugfs_cleanup(struct drm_minor *minor)
 {
-       drm_debugfs_remove_files(i915_gem_debugfs_list,
-                                I915_GEM_DEBUGFS_ENTRIES, minor);
+       drm_debugfs_remove_files(i915_debugfs_list,
+                                I915_DEBUGFS_ENTRIES, minor);
 }
 
 #endif /* CONFIG_DEBUG_FS */
index 50d1f78..5a49a18 100644 (file)
 #include "drmP.h"
 #include "drm.h"
 #include "drm_crtc_helper.h"
+#include "drm_fb_helper.h"
 #include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
-
-#define I915_DRV       "i915_drv"
+#include <linux/vgaarb.h>
 
 /* Really want an OS-independent resettable timer.  Would like to have
  * this loop run for (eg) 3 sec, but have the timer reset every time
@@ -80,6 +80,34 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
        return -EBUSY;
 }
 
+/* As a ringbuffer is only allowed to wrap between instructions, fill
+ * the tail with NOOPs.
+ */
+int i915_wrap_ring(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       volatile unsigned int *virt;
+       int rem;
+
+       rem = dev_priv->ring.Size - dev_priv->ring.tail;
+       if (dev_priv->ring.space < rem) {
+               int ret = i915_wait_ring(dev, rem, __func__);
+               if (ret)
+                       return ret;
+       }
+       dev_priv->ring.space -= rem;
+
+       virt = (unsigned int *)
+               (dev_priv->ring.virtual_start + dev_priv->ring.tail);
+       rem /= 4;
+       while (rem--)
+               *virt++ = MI_NOOP;
+
+       dev_priv->ring.tail = 0;
+
+       return 0;
+}
+
 /**
  * Sets up the hardware status page for devices that need a physical address
  * in the register.
@@ -101,7 +129,7 @@ static int i915_init_phys_hws(struct drm_device *dev)
        memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
 
        I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
-       DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n");
+       DRM_DEBUG_DRIVER("Enabled hardware status page\n");
        return 0;
 }
 
@@ -187,8 +215,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
                master_priv->sarea_priv = (drm_i915_sarea_t *)
                        ((u8 *)master_priv->sarea->handle + init->sarea_priv_offset);
        } else {
-               DRM_DEBUG_DRIVER(I915_DRV,
-                               "sarea not found assuming DRI2 userspace\n");
+               DRM_DEBUG_DRIVER("sarea not found assuming DRI2 userspace\n");
        }
 
        if (init->ring_size != 0) {
@@ -200,7 +227,6 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
                }
 
                dev_priv->ring.Size = init->ring_size;
-               dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
 
                dev_priv->ring.map.offset = init->ring_start;
                dev_priv->ring.map.size = init->ring_size;
@@ -238,7 +264,7 @@ static int i915_dma_resume(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
-       DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__);
+       DRM_DEBUG_DRIVER("%s\n", __func__);
 
        if (dev_priv->ring.map.handle == NULL) {
                DRM_ERROR("can not ioremap virtual address for"
@@ -251,14 +277,14 @@ static int i915_dma_resume(struct drm_device * dev)
                DRM_ERROR("Can not find hardware status page\n");
                return -EINVAL;
        }
-       DRM_DEBUG_DRIVER(I915_DRV, "hw status page @ %p\n",
+       DRM_DEBUG_DRIVER("hw status page @ %p\n",
                                dev_priv->hw_status_page);
 
        if (dev_priv->status_gfx_addr != 0)
                I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
        else
                I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
-       DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n");
+       DRM_DEBUG_DRIVER("Enabled hardware status page\n");
 
        return 0;
 }
@@ -552,7 +578,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
        if (!master_priv->sarea_priv)
                return -EINVAL;
 
-       DRM_DEBUG_DRIVER(I915_DRV, "%s: page=%d pfCurrentPage=%d\n",
+       DRM_DEBUG_DRIVER("%s: page=%d pfCurrentPage=%d\n",
                          __func__,
                         dev_priv->current_page,
                         master_priv->sarea_priv->pf_current_page);
@@ -633,8 +659,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       DRM_DEBUG_DRIVER(I915_DRV,
-                       "i915 batchbuffer, start %x used %d cliprects %d\n",
+       DRM_DEBUG_DRIVER("i915 batchbuffer, start %x used %d cliprects %d\n",
                        batch->start, batch->used, batch->num_cliprects);
 
        RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -681,8 +706,7 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
        void *batch_data;
        int ret;
 
-       DRM_DEBUG_DRIVER(I915_DRV,
-                       "i915 cmdbuffer, buf %p sz %d cliprects %d\n",
+       DRM_DEBUG_DRIVER("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
                        cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
 
        RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -735,7 +759,7 @@ static int i915_flip_bufs(struct drm_device *dev, void *data,
 {
        int ret;
 
-       DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__);
+       DRM_DEBUG_DRIVER("%s\n", __func__);
 
        RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
@@ -778,7 +802,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
                value = dev_priv->num_fence_regs - dev_priv->fence_reg_start;
                break;
        default:
-               DRM_DEBUG_DRIVER(I915_DRV, "Unknown parameter %d\n",
+               DRM_DEBUG_DRIVER("Unknown parameter %d\n",
                                        param->param);
                return -EINVAL;
        }
@@ -819,7 +843,7 @@ static int i915_setparam(struct drm_device *dev, void *data,
                dev_priv->fence_reg_start = param->value;
                break;
        default:
-               DRM_DEBUG_DRIVER(I915_DRV, "unknown parameter %d\n",
+               DRM_DEBUG_DRIVER("unknown parameter %d\n",
                                        param->param);
                return -EINVAL;
        }
@@ -846,7 +870,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
                return 0;
        }
 
-       DRM_DEBUG("set status page addr 0x%08x\n", (u32)hws->addr);
+       DRM_DEBUG_DRIVER("set status page addr 0x%08x\n", (u32)hws->addr);
 
        dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
 
@@ -868,13 +892,25 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
 
        memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
        I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
-       DRM_DEBUG_DRIVER(I915_DRV, "load hws HWS_PGA with gfx mem 0x%x\n",
+       DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n",
                                dev_priv->status_gfx_addr);
-       DRM_DEBUG_DRIVER(I915_DRV, "load hws at %p\n",
+       DRM_DEBUG_DRIVER("load hws at %p\n",
                                dev_priv->hw_status_page);
        return 0;
 }
 
+static int i915_get_bridge_dev(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       dev_priv->bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
+       if (!dev_priv->bridge_dev) {
+               DRM_ERROR("bridge device not found\n");
+               return -1;
+       }
+       return 0;
+}
+
 /**
  * i915_probe_agp - get AGP bootup configuration
  * @pdev: PCI device
@@ -888,20 +924,13 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
 static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
                          uint32_t *preallocated_size)
 {
-       struct pci_dev *bridge_dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u16 tmp = 0;
        unsigned long overhead;
        unsigned long stolen;
 
-       bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
-       if (!bridge_dev) {
-               DRM_ERROR("bridge device not found\n");
-               return -1;
-       }
-
        /* Get the fb aperture size and "stolen" memory amount. */
-       pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
-       pci_dev_put(bridge_dev);
+       pci_read_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, &tmp);
 
        *aperture_size = 1024 * 1024;
        *preallocated_size = 1024 * 1024;
@@ -984,6 +1013,19 @@ static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
        return 0;
 }
 
+/* true = enable decode, false = disable decoder */
+static unsigned int i915_vga_set_decode(void *cookie, bool state)
+{
+       struct drm_device *dev = cookie;
+
+       intel_modeset_vga_set_state(dev, state);
+       if (state)
+               return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
+                      VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+       else
+               return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+}
+
 static int i915_load_modeset_init(struct drm_device *dev,
                                  unsigned long prealloc_size,
                                  unsigned long agp_size)
@@ -1029,6 +1071,11 @@ static int i915_load_modeset_init(struct drm_device *dev,
        if (ret)
                DRM_INFO("failed to find VBIOS tables\n");
 
+       /* if we have > 1 VGA cards, then disable the radeon VGA resources */
+       ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
+       if (ret)
+               goto destroy_ringbuffer;
+
        ret = drm_irq_install(dev);
        if (ret)
                goto destroy_ringbuffer;
@@ -1153,11 +1200,16 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        base = drm_get_resource_start(dev, mmio_bar);
        size = drm_get_resource_len(dev, mmio_bar);
 
+       if (i915_get_bridge_dev(dev)) {
+               ret = -EIO;
+               goto free_priv;
+       }
+
        dev_priv->regs = ioremap(base, size);
        if (!dev_priv->regs) {
                DRM_ERROR("failed to map registers\n");
                ret = -EIO;
-               goto free_priv;
+               goto put_bridge;
        }
 
         dev_priv->mm.gtt_mapping =
@@ -1269,6 +1321,8 @@ out_iomapfree:
        io_mapping_free(dev_priv->mm.gtt_mapping);
 out_rmmap:
        iounmap(dev_priv->regs);
+put_bridge:
+       pci_dev_put(dev_priv->bridge_dev);
 free_priv:
        kfree(dev_priv);
        return ret;
@@ -1289,6 +1343,7 @@ int i915_driver_unload(struct drm_device *dev)
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                drm_irq_uninstall(dev);
+               vga_client_register(dev->pdev, NULL, NULL, NULL);
        }
 
        if (dev->pdev->msi_enabled)
@@ -1312,6 +1367,7 @@ int i915_driver_unload(struct drm_device *dev)
                i915_gem_lastclose(dev);
        }
 
+       pci_dev_put(dev_priv->bridge_dev);
        kfree(dev->dev_private);
 
        return 0;
@@ -1321,7 +1377,7 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
 {
        struct drm_i915_file_private *i915_file_priv;
 
-       DRM_DEBUG_DRIVER(I915_DRV, "\n");
+       DRM_DEBUG_DRIVER("\n");
        i915_file_priv = (struct drm_i915_file_private *)
            kmalloc(sizeof(*i915_file_priv), GFP_KERNEL);
 
@@ -1352,7 +1408,7 @@ void i915_driver_lastclose(struct drm_device * dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) {
-               intelfb_restore();
+               drm_fb_helper_restore();
                return;
        }
 
index fc4b68a..dbe568c 100644 (file)
 #include <linux/console.h>
 #include "drm_crtc_helper.h"
 
-static unsigned int i915_modeset = -1;
+static int i915_modeset = -1;
 module_param_named(modeset, i915_modeset, int, 0400);
 
 unsigned int i915_fbpercrtc = 0;
 module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
 
+unsigned int i915_powersave = 1;
+module_param_named(powersave, i915_powersave, int, 0400);
+
 static struct drm_driver driver;
 
 static struct pci_device_id pciidlist[] = {
@@ -188,8 +191,8 @@ static struct drm_driver driver = {
        .master_create = i915_master_create,
        .master_destroy = i915_master_destroy,
 #if defined(CONFIG_DEBUG_FS)
-       .debugfs_init = i915_gem_debugfs_init,
-       .debugfs_cleanup = i915_gem_debugfs_cleanup,
+       .debugfs_init = i915_debugfs_init,
+       .debugfs_cleanup = i915_debugfs_cleanup,
 #endif
        .gem_init_object = i915_gem_init_object,
        .gem_free_object = i915_gem_free_object,
index 5b4f87e..a0632f8 100644 (file)
@@ -85,7 +85,6 @@ struct drm_i915_gem_phys_object {
 };
 
 typedef struct _drm_i915_ring_buffer {
-       int tail_mask;
        unsigned long Size;
        u8 *virtual_start;
        int head;
@@ -156,6 +155,7 @@ typedef struct drm_i915_private {
 
        void __iomem *regs;
 
+       struct pci_dev *bridge_dev;
        drm_i915_ring_buffer_t ring;
 
        drm_dma_handle_t *status_page_dmah;
@@ -311,7 +311,7 @@ typedef struct drm_i915_private {
        u32 saveIMR;
        u32 saveCACHE_MODE_0;
        u32 saveD_STATE;
-       u32 saveCG_2D_DIS;
+       u32 saveDSPCLK_GATE_D;
        u32 saveMI_ARB_STATE;
        u32 saveSWF0[16];
        u32 saveSWF1[16];
@@ -443,6 +443,14 @@ typedef struct drm_i915_private {
                struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
        } mm;
        struct sdvo_device_mapping sdvo_mappings[2];
+
+       /* Reclocking support */
+       bool render_reclock_avail;
+       bool lvds_downclock_avail;
+       struct work_struct idle_work;
+       struct timer_list idle_timer;
+       bool busy;
+       u16 orig_clock;
 } drm_i915_private_t;
 
 /** driver private structure attached to each drm_gem_object */
@@ -575,6 +583,7 @@ enum intel_chip_family {
 extern struct drm_ioctl_desc i915_ioctls[];
 extern int i915_max_ioctl;
 extern unsigned int i915_fbpercrtc;
+extern unsigned int i915_powersave;
 
 extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
 extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master);
@@ -730,8 +739,8 @@ void i915_gem_dump_object(struct drm_gem_object *obj, int len,
 void i915_dump_lru(struct drm_device *dev, const char *where);
 
 /* i915_debugfs.c */
-int i915_gem_debugfs_init(struct drm_minor *minor);
-void i915_gem_debugfs_cleanup(struct drm_minor *minor);
+int i915_debugfs_init(struct drm_minor *minor);
+void i915_debugfs_cleanup(struct drm_minor *minor);
 
 /* i915_suspend.c */
 extern int i915_save_state(struct drm_device *dev);
@@ -757,6 +766,7 @@ static inline void opregion_enable_asle(struct drm_device *dev) { return; }
 /* modesetting */
 extern void intel_modeset_init(struct drm_device *dev);
 extern void intel_modeset_cleanup(struct drm_device *dev);
+extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
 
 /**
  * Lock test for when it's just for synchronization of ring access.
@@ -781,33 +791,32 @@ extern void intel_modeset_cleanup(struct drm_device *dev);
 
 #define I915_VERBOSE 0
 
-#define RING_LOCALS    unsigned int outring, ringmask, outcount; \
-                        volatile char *virt;
-
-#define BEGIN_LP_RING(n) do {                          \
-       if (I915_VERBOSE)                               \
-               DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n));  \
-       if (dev_priv->ring.space < (n)*4)               \
-               i915_wait_ring(dev, (n)*4, __func__);           \
-       outcount = 0;                                   \
-       outring = dev_priv->ring.tail;                  \
-       ringmask = dev_priv->ring.tail_mask;            \
-       virt = dev_priv->ring.virtual_start;            \
+#define RING_LOCALS    volatile unsigned int *ring_virt__;
+
+#define BEGIN_LP_RING(n) do {                                          \
+       int bytes__ = 4*(n);                                            \
+       if (I915_VERBOSE) DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n));        \
+       /* a wrap must occur between instructions so pad beforehand */  \
+       if (unlikely (dev_priv->ring.tail + bytes__ > dev_priv->ring.Size)) \
+               i915_wrap_ring(dev);                                    \
+       if (unlikely (dev_priv->ring.space < bytes__))                  \
+               i915_wait_ring(dev, bytes__, __func__);                 \
+       ring_virt__ = (unsigned int *)                                  \
+               (dev_priv->ring.virtual_start + dev_priv->ring.tail);   \
+       dev_priv->ring.tail += bytes__;                                 \
+       dev_priv->ring.tail &= dev_priv->ring.Size - 1;                 \
+       dev_priv->ring.space -= bytes__;                                \
 } while (0)
 
-#define OUT_RING(n) do {                                       \
+#define OUT_RING(n) do {                                               \
        if (I915_VERBOSE) DRM_DEBUG("   OUT_RING %x\n", (int)(n));      \
-       *(volatile unsigned int *)(virt + outring) = (n);       \
-        outcount++;                                            \
-       outring += 4;                                           \
-       outring &= ringmask;                                    \
+       *ring_virt__++ = (n);                                           \
 } while (0)
 
 #define ADVANCE_LP_RING() do {                                         \
-       if (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring);   \
-       dev_priv->ring.tail = outring;                                  \
-       dev_priv->ring.space -= outcount * 4;                           \
-       I915_WRITE(PRB0_TAIL, outring);                 \
+       if (I915_VERBOSE)                                               \
+               DRM_DEBUG("ADVANCE_LP_RING %x\n", dev_priv->ring.tail); \
+       I915_WRITE(PRB0_TAIL, dev_priv->ring.tail);                     \
 } while(0)
 
 /**
@@ -830,6 +839,7 @@ extern void intel_modeset_cleanup(struct drm_device *dev);
 #define I915_GEM_HWS_INDEX             0x20
 #define I915_BREADCRUMB_INDEX          0x21
 
+extern int i915_wrap_ring(struct drm_device * dev);
 extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 
 #define IS_I830(dev) ((dev)->pci_device == 0x3577)
@@ -903,6 +913,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 /* dsparb controlled by hw only */
 #define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IGDNG(dev))
 
+#define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IGDNG(dev))
+#define HAS_PIPE_CXSR(dev) (IS_G4X(dev) || IS_IGDNG(dev))
+
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
 
 #endif
index 80e5ba4..c673171 100644 (file)
@@ -29,6 +29,7 @@
 #include "drm.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include "intel_drv.h"
 #include <linux/swap.h>
 #include <linux/pci.h>
 
@@ -111,7 +112,8 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
 {
        struct drm_i915_gem_create *args = data;
        struct drm_gem_object *obj;
-       int handle, ret;
+       int ret;
+       u32 handle;
 
        args->size = roundup(args->size, PAGE_SIZE);
 
@@ -981,6 +983,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_set_domain *args = data;
        struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
        uint32_t read_domains = args->read_domains;
        uint32_t write_domain = args->write_domain;
        int ret;
@@ -1004,15 +1007,17 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL)
                return -EBADF;
+       obj_priv = obj->driver_private;
 
        mutex_lock(&dev->struct_mutex);
+
+       intel_mark_busy(dev, obj);
+
 #if WATCH_BUF
        DRM_INFO("set_domain_ioctl %p(%zd), %08x %08x\n",
                 obj, obj->size, read_domains, write_domain);
 #endif
        if (read_domains & I915_GEM_DOMAIN_GTT) {
-               struct drm_i915_gem_object *obj_priv = obj->driver_private;
-
                ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
 
                /* Update the LRU on the fence for the CPU access that's
@@ -2776,6 +2781,8 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
        BUG_ON(obj->pending_read_domains & I915_GEM_DOMAIN_CPU);
        BUG_ON(obj->pending_write_domain == I915_GEM_DOMAIN_CPU);
 
+       intel_mark_busy(dev, obj);
+
 #if WATCH_BUF
        DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n",
                 __func__, obj,
@@ -4093,7 +4100,6 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
 
        /* Set up the kernel mapping for the ring. */
        ring->Size = obj->size;
-       ring->tail_mask = obj->size - 1;
 
        ring->map.offset = dev->agp->base + obj_priv->gtt_offset;
        ring->map.size = obj->size;
index a2d527b..200e398 100644 (file)
 static int
 intel_alloc_mchbar_resource(struct drm_device *dev)
 {
-       struct pci_dev *bridge_dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
        u32 temp_lo, temp_hi = 0;
        u64 mchbar_addr;
        int ret = 0;
 
-       bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
-       if (!bridge_dev) {
-               DRM_DEBUG("no bridge dev?!\n");
-               ret = -ENODEV;
-               goto out;
-       }
-
        if (IS_I965G(dev))
-               pci_read_config_dword(bridge_dev, reg + 4, &temp_hi);
-       pci_read_config_dword(bridge_dev, reg, &temp_lo);
+               pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
+       pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
        mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
 
        /* If ACPI doesn't have it, assume we need to allocate it ourselves */
@@ -118,30 +110,28 @@ intel_alloc_mchbar_resource(struct drm_device *dev)
        if (mchbar_addr &&
            pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
                ret = 0;
-               goto out_put;
+               goto out;
        }
 #endif
 
        /* Get some space for it */
-       ret = pci_bus_alloc_resource(bridge_dev->bus, &dev_priv->mch_res,
+       ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus, &dev_priv->mch_res,
                                     MCHBAR_SIZE, MCHBAR_SIZE,
                                     PCIBIOS_MIN_MEM,
                                     0,   pcibios_align_resource,
-                                    bridge_dev);
+                                    dev_priv->bridge_dev);
        if (ret) {
                DRM_DEBUG("failed bus alloc: %d\n", ret);
                dev_priv->mch_res.start = 0;
-               goto out_put;
+               goto out;
        }
 
        if (IS_I965G(dev))
-               pci_write_config_dword(bridge_dev, reg + 4,
+               pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
                                       upper_32_bits(dev_priv->mch_res.start));
 
-       pci_write_config_dword(bridge_dev, reg,
+       pci_write_config_dword(dev_priv->bridge_dev, reg,
                               lower_32_bits(dev_priv->mch_res.start));
-out_put:
-       pci_dev_put(bridge_dev);
 out:
        return ret;
 }
@@ -150,44 +140,36 @@ out:
 static bool
 intel_setup_mchbar(struct drm_device *dev)
 {
-       struct pci_dev *bridge_dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
        int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
        u32 temp;
        bool need_disable = false, enabled;
 
-       bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
-       if (!bridge_dev) {
-               DRM_DEBUG("no bridge dev?!\n");
-               goto out;
-       }
-
        if (IS_I915G(dev) || IS_I915GM(dev)) {
-               pci_read_config_dword(bridge_dev, DEVEN_REG, &temp);
+               pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
                enabled = !!(temp & DEVEN_MCHBAR_EN);
        } else {
-               pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
+               pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
                enabled = temp & 1;
        }
 
        /* If it's already enabled, don't have to do anything */
        if (enabled)
-               goto out_put;
+               goto out;
 
        if (intel_alloc_mchbar_resource(dev))
-               goto out_put;
+               goto out;
 
        need_disable = true;
 
        /* Space is allocated or reserved, so enable it. */
        if (IS_I915G(dev) || IS_I915GM(dev)) {
-               pci_write_config_dword(bridge_dev, DEVEN_REG,
+               pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG,
                                       temp | DEVEN_MCHBAR_EN);
        } else {
-               pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
-               pci_write_config_dword(bridge_dev, mchbar_reg, temp | 1);
+               pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
+               pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp | 1);
        }
-out_put:
-       pci_dev_put(bridge_dev);
 out:
        return need_disable;
 }
@@ -196,25 +178,18 @@ static void
 intel_teardown_mchbar(struct drm_device *dev, bool disable)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct pci_dev *bridge_dev;
        int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
        u32 temp;
 
-       bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
-       if (!bridge_dev) {
-               DRM_DEBUG("no bridge dev?!\n");
-               return;
-       }
-
        if (disable) {
                if (IS_I915G(dev) || IS_I915GM(dev)) {
-                       pci_read_config_dword(bridge_dev, DEVEN_REG, &temp);
+                       pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
                        temp &= ~DEVEN_MCHBAR_EN;
-                       pci_write_config_dword(bridge_dev, DEVEN_REG, temp);
+                       pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG, temp);
                } else {
-                       pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
+                       pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
                        temp &= ~1;
-                       pci_write_config_dword(bridge_dev, mchbar_reg, temp);
+                       pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp);
                }
        }
 
@@ -234,7 +209,13 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
        uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
        bool need_disable;
 
-       if (!IS_I9XX(dev)) {
+       if (IS_IGDNG(dev)) {
+               /* On IGDNG whatever DRAM config, GPU always do
+                * same swizzling setup.
+                */
+               swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+               swizzle_y = I915_BIT_6_SWIZZLE_9;
+       } else if (!IS_I9XX(dev)) {
                /* As far as we know, the 865 doesn't have these bit 6
                 * swizzling issues.
                 */
@@ -317,13 +298,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
                }
        }
 
-       /* FIXME: check with memory config on IGDNG */
-       if (IS_IGDNG(dev)) {
-               DRM_ERROR("disable tiling on IGDNG...\n");
-               swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
-               swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
-       }
-
        dev_priv->mm.bit_6_swizzle_x = swizzle_x;
        dev_priv->mm.bit_6_swizzle_y = swizzle_y;
 }
index 7ebc84c..6c89f2f 100644 (file)
@@ -565,6 +565,27 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 
                        I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
                        I915_READ(PORT_HOTPLUG_STAT);
+
+                       /* EOS interrupts occurs */
+                       if (IS_IGD(dev) &&
+                               (hotplug_status & CRT_EOS_INT_STATUS)) {
+                               u32 temp;
+
+                               DRM_DEBUG("EOS interrupt occurs\n");
+                               /* status is already cleared */
+                               temp = I915_READ(ADPA);
+                               temp &= ~ADPA_DAC_ENABLE;
+                               I915_WRITE(ADPA, temp);
+
+                               temp = I915_READ(PORT_HOTPLUG_EN);
+                               temp &= ~CRT_EOS_INT_EN;
+                               I915_WRITE(PORT_HOTPLUG_EN, temp);
+
+                               temp = I915_READ(PORT_HOTPLUG_STAT);
+                               if (temp & CRT_EOS_INT_STATUS)
+                                       I915_WRITE(PORT_HOTPLUG_STAT,
+                                               CRT_EOS_INT_STATUS);
+                       }
                }
 
                I915_WRITE(IIR, iir);
index 2955083..3f79635 100644 (file)
@@ -30,6 +30,7 @@
  * fb aperture size and the amount of pre-reserved memory.
  */
 #define INTEL_GMCH_CTRL                0x52
+#define INTEL_GMCH_VGA_DISABLE  (1 << 1)
 #define INTEL_GMCH_ENABLED     0x4
 #define INTEL_GMCH_MEM_MASK    0x1
 #define INTEL_GMCH_MEM_64M     0x1
@@ -55,7 +56,7 @@
 /* PCI config space */
 
 #define HPLLCC 0xc0 /* 855 only */
-#define   GC_CLOCK_CONTROL_MASK                (3 << 0)
+#define   GC_CLOCK_CONTROL_MASK                (0xf << 0)
 #define   GC_CLOCK_133_200             (0 << 0)
 #define   GC_CLOCK_100_200             (1 << 0)
 #define   GC_CLOCK_100_133             (2 << 0)
 #define   GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4)
 #define   GC_DISPLAY_CLOCK_333_MHZ     (4 << 4)
 #define   GC_DISPLAY_CLOCK_MASK                (7 << 4)
+#define   GM45_GC_RENDER_CLOCK_MASK    (0xf << 0)
+#define   GM45_GC_RENDER_CLOCK_266_MHZ (8 << 0)
+#define   GM45_GC_RENDER_CLOCK_320_MHZ (9 << 0)
+#define   GM45_GC_RENDER_CLOCK_400_MHZ (0xb << 0)
+#define   GM45_GC_RENDER_CLOCK_533_MHZ (0xc << 0)
+#define   I965_GC_RENDER_CLOCK_MASK    (0xf << 0)
+#define   I965_GC_RENDER_CLOCK_267_MHZ (2 << 0)
+#define   I965_GC_RENDER_CLOCK_333_MHZ (3 << 0)
+#define   I965_GC_RENDER_CLOCK_444_MHZ (4 << 0)
+#define   I965_GC_RENDER_CLOCK_533_MHZ (5 << 0)
+#define   I945_GC_RENDER_CLOCK_MASK    (7 << 0)
+#define   I945_GC_RENDER_CLOCK_166_MHZ (0 << 0)
+#define   I945_GC_RENDER_CLOCK_200_MHZ (1 << 0)
+#define   I945_GC_RENDER_CLOCK_250_MHZ (3 << 0)
+#define   I945_GC_RENDER_CLOCK_400_MHZ (5 << 0)
+#define   I915_GC_RENDER_CLOCK_MASK    (7 << 0)
+#define   I915_GC_RENDER_CLOCK_166_MHZ (0 << 0)
+#define   I915_GC_RENDER_CLOCK_200_MHZ (1 << 0)
+#define   I915_GC_RENDER_CLOCK_333_MHZ (4 << 0)
 #define LBB    0xf4
 
 /* VGA stuff */
 #define   DPLLA_TEST_M_BYPASS          (1 << 2)
 #define   DPLLA_INPUT_BUFFER_ENABLE    (1 << 0)
 #define D_STATE                0x6104
-#define CG_2D_DIS      0x6200
-#define DPCUNIT_CLOCK_GATE_DISABLE     (1 << 24)
-#define CG_3D_DIS      0x6204
+#define  DSTATE_PLL_D3_OFF                     (1<<3)
+#define  DSTATE_GFX_CLOCK_GATING               (1<<1)
+#define  DSTATE_DOT_CLOCK_GATING               (1<<0)
+#define DSPCLK_GATE_D          0x6200
+# define DPUNIT_B_CLOCK_GATE_DISABLE           (1 << 30) /* 965 */
+# define VSUNIT_CLOCK_GATE_DISABLE             (1 << 29) /* 965 */
+# define VRHUNIT_CLOCK_GATE_DISABLE            (1 << 28) /* 965 */
+# define VRDUNIT_CLOCK_GATE_DISABLE            (1 << 27) /* 965 */
+# define AUDUNIT_CLOCK_GATE_DISABLE            (1 << 26) /* 965 */
+# define DPUNIT_A_CLOCK_GATE_DISABLE           (1 << 25) /* 965 */
+# define DPCUNIT_CLOCK_GATE_DISABLE            (1 << 24) /* 965 */
+# define TVRUNIT_CLOCK_GATE_DISABLE            (1 << 23) /* 915-945 */
+# define TVCUNIT_CLOCK_GATE_DISABLE            (1 << 22) /* 915-945 */
+# define TVFUNIT_CLOCK_GATE_DISABLE            (1 << 21) /* 915-945 */
+# define TVEUNIT_CLOCK_GATE_DISABLE            (1 << 20) /* 915-945 */
+# define DVSUNIT_CLOCK_GATE_DISABLE            (1 << 19) /* 915-945 */
+# define DSSUNIT_CLOCK_GATE_DISABLE            (1 << 18) /* 915-945 */
+# define DDBUNIT_CLOCK_GATE_DISABLE            (1 << 17) /* 915-945 */
+# define DPRUNIT_CLOCK_GATE_DISABLE            (1 << 16) /* 915-945 */
+# define DPFUNIT_CLOCK_GATE_DISABLE            (1 << 15) /* 915-945 */
+# define DPBMUNIT_CLOCK_GATE_DISABLE           (1 << 14) /* 915-945 */
+# define DPLSUNIT_CLOCK_GATE_DISABLE           (1 << 13) /* 915-945 */
+# define DPLUNIT_CLOCK_GATE_DISABLE            (1 << 12) /* 915-945 */
+# define DPOUNIT_CLOCK_GATE_DISABLE            (1 << 11)
+# define DPBUNIT_CLOCK_GATE_DISABLE            (1 << 10)
+# define DCUNIT_CLOCK_GATE_DISABLE             (1 << 9)
+# define DPUNIT_CLOCK_GATE_DISABLE             (1 << 8)
+# define VRUNIT_CLOCK_GATE_DISABLE             (1 << 7) /* 915+: reserved */
+# define OVHUNIT_CLOCK_GATE_DISABLE            (1 << 6) /* 830-865 */
+# define DPIOUNIT_CLOCK_GATE_DISABLE           (1 << 6) /* 915-945 */
+# define OVFUNIT_CLOCK_GATE_DISABLE            (1 << 5)
+# define OVBUNIT_CLOCK_GATE_DISABLE            (1 << 4)
+/**
+ * This bit must be set on the 830 to prevent hangs when turning off the
+ * overlay scaler.
+ */
+# define OVRUNIT_CLOCK_GATE_DISABLE            (1 << 3)
+# define OVCUNIT_CLOCK_GATE_DISABLE            (1 << 2)
+# define OVUUNIT_CLOCK_GATE_DISABLE            (1 << 1)
+# define ZVUNIT_CLOCK_GATE_DISABLE             (1 << 0) /* 830 */
+# define OVLUNIT_CLOCK_GATE_DISABLE            (1 << 0) /* 845,865 */
+
+#define RENCLK_GATE_D1         0x6204
+# define BLITTER_CLOCK_GATE_DISABLE            (1 << 13) /* 945GM only */
+# define MPEG_CLOCK_GATE_DISABLE               (1 << 12) /* 945GM only */
+# define PC_FE_CLOCK_GATE_DISABLE              (1 << 11)
+# define PC_BE_CLOCK_GATE_DISABLE              (1 << 10)
+# define WINDOWER_CLOCK_GATE_DISABLE           (1 << 9)
+# define INTERPOLATOR_CLOCK_GATE_DISABLE       (1 << 8)
+# define COLOR_CALCULATOR_CLOCK_GATE_DISABLE   (1 << 7)
+# define MOTION_COMP_CLOCK_GATE_DISABLE                (1 << 6)
+# define MAG_CLOCK_GATE_DISABLE                        (1 << 5)
+/** This bit must be unset on 855,865 */
+# define MECI_CLOCK_GATE_DISABLE               (1 << 4)
+# define DCMP_CLOCK_GATE_DISABLE               (1 << 3)
+# define MEC_CLOCK_GATE_DISABLE                        (1 << 2)
+# define MECO_CLOCK_GATE_DISABLE               (1 << 1)
+/** This bit must be set on 855,865. */
+# define SV_CLOCK_GATE_DISABLE                 (1 << 0)
+# define I915_MPEG_CLOCK_GATE_DISABLE          (1 << 16)
+# define I915_VLD_IP_PR_CLOCK_GATE_DISABLE     (1 << 15)
+# define I915_MOTION_COMP_CLOCK_GATE_DISABLE   (1 << 14)
+# define I915_BD_BF_CLOCK_GATE_DISABLE         (1 << 13)
+# define I915_SF_SE_CLOCK_GATE_DISABLE         (1 << 12)
+# define I915_WM_CLOCK_GATE_DISABLE            (1 << 11)
+# define I915_IZ_CLOCK_GATE_DISABLE            (1 << 10)
+# define I915_PI_CLOCK_GATE_DISABLE            (1 << 9)
+# define I915_DI_CLOCK_GATE_DISABLE            (1 << 8)
+# define I915_SH_SV_CLOCK_GATE_DISABLE         (1 << 7)
+# define I915_PL_DG_QC_FT_CLOCK_GATE_DISABLE   (1 << 6)
+# define I915_SC_CLOCK_GATE_DISABLE            (1 << 5)
+# define I915_FL_CLOCK_GATE_DISABLE            (1 << 4)
+# define I915_DM_CLOCK_GATE_DISABLE            (1 << 3)
+# define I915_PS_CLOCK_GATE_DISABLE            (1 << 2)
+# define I915_CC_CLOCK_GATE_DISABLE            (1 << 1)
+# define I915_BY_CLOCK_GATE_DISABLE            (1 << 0)
+
+# define I965_RCZ_CLOCK_GATE_DISABLE           (1 << 30)
+/** This bit must always be set on 965G/965GM */
+# define I965_RCC_CLOCK_GATE_DISABLE           (1 << 29)
+# define I965_RCPB_CLOCK_GATE_DISABLE          (1 << 28)
+# define I965_DAP_CLOCK_GATE_DISABLE           (1 << 27)
+# define I965_ROC_CLOCK_GATE_DISABLE           (1 << 26)
+# define I965_GW_CLOCK_GATE_DISABLE            (1 << 25)
+# define I965_TD_CLOCK_GATE_DISABLE            (1 << 24)
+/** This bit must always be set on 965G */
+# define I965_ISC_CLOCK_GATE_DISABLE           (1 << 23)
+# define I965_IC_CLOCK_GATE_DISABLE            (1 << 22)
+# define I965_EU_CLOCK_GATE_DISABLE            (1 << 21)
+# define I965_IF_CLOCK_GATE_DISABLE            (1 << 20)
+# define I965_TC_CLOCK_GATE_DISABLE            (1 << 19)
+# define I965_SO_CLOCK_GATE_DISABLE            (1 << 17)
+# define I965_FBC_CLOCK_GATE_DISABLE           (1 << 16)
+# define I965_MARI_CLOCK_GATE_DISABLE          (1 << 15)
+# define I965_MASF_CLOCK_GATE_DISABLE          (1 << 14)
+# define I965_MAWB_CLOCK_GATE_DISABLE          (1 << 13)
+# define I965_EM_CLOCK_GATE_DISABLE            (1 << 12)
+# define I965_UC_CLOCK_GATE_DISABLE            (1 << 11)
+# define I965_SI_CLOCK_GATE_DISABLE            (1 << 6)
+# define I965_MT_CLOCK_GATE_DISABLE            (1 << 5)
+# define I965_PL_CLOCK_GATE_DISABLE            (1 << 4)
+# define I965_DG_CLOCK_GATE_DISABLE            (1 << 3)
+# define I965_QC_CLOCK_GATE_DISABLE            (1 << 2)
+# define I965_FT_CLOCK_GATE_DISABLE            (1 << 1)
+# define I965_DM_CLOCK_GATE_DISABLE            (1 << 0)
+
+#define RENCLK_GATE_D2         0x6208
+#define VF_UNIT_CLOCK_GATE_DISABLE             (1 << 9)
+#define GS_UNIT_CLOCK_GATE_DISABLE             (1 << 7)
+#define CL_UNIT_CLOCK_GATE_DISABLE             (1 << 6)
+#define RAMCLK_GATE_D          0x6210          /* CRL only */
+#define DEUC                   0x6214          /* CRL only */
 
 /*
  * Palette regs
 #define   SDVOB_HOTPLUG_INT_EN                 (1 << 26)
 #define   SDVOC_HOTPLUG_INT_EN                 (1 << 25)
 #define   TV_HOTPLUG_INT_EN                    (1 << 18)
+#define   CRT_EOS_INT_EN                       (1 << 10)
 #define   CRT_HOTPLUG_INT_EN                   (1 << 9)
 #define   CRT_HOTPLUG_FORCE_DETECT             (1 << 3)
 #define CRT_HOTPLUG_ACTIVATION_PERIOD_32       (0 << 8)
 #define   DPC_HOTPLUG_INT_STATUS               (1 << 28)
 #define   HDMID_HOTPLUG_INT_STATUS             (1 << 27)
 #define   DPD_HOTPLUG_INT_STATUS               (1 << 27)
+#define   CRT_EOS_INT_STATUS                   (1 << 12)
 #define   CRT_HOTPLUG_INT_STATUS               (1 << 11)
 #define   TV_HOTPLUG_INT_STATUS                        (1 << 10)
 #define   CRT_HOTPLUG_MONITOR_MASK             (3 << 8)
 #define   PIPECONF_PROGRESSIVE (0 << 21)
 #define   PIPECONF_INTERLACE_W_FIELD_INDICATION        (6 << 21)
 #define   PIPECONF_INTERLACE_FIELD_0_ONLY              (7 << 21)
+#define   PIPECONF_CXSR_DOWNCLOCK      (1<<16)
 #define PIPEASTAT              0x70024
 #define   PIPE_FIFO_UNDERRUN_STATUS            (1UL<<31)
 #define   PIPE_CRC_ERROR_ENABLE                        (1UL<<29)
 #define   DISPPLANE_NO_LINE_DOUBLE             0
 #define   DISPPLANE_STEREO_POLARITY_FIRST      0
 #define   DISPPLANE_STEREO_POLARITY_SECOND     (1<<18)
+#define   DISPPLANE_TRICKLE_FEED_DISABLE       (1<<14) /* IGDNG */
 #define   DISPPLANE_TILED                      (1<<10)
 #define DSPAADDR               0x70184
 #define DSPASTRIDE             0x70188
 #define GTIIR   0x44018
 #define GTIER   0x4401c
 
+#define DISP_ARB_CTL   0x45000
+#define  DISP_TILE_SURFACE_SWIZZLING   (1<<13)
+
 /* PCH */
 
 /* south display engine interrupt */
index 1d04e19..20d4d19 100644 (file)
@@ -461,7 +461,7 @@ int i915_save_state(struct drm_device *dev)
 
        /* Clock gating state */
        dev_priv->saveD_STATE = I915_READ(D_STATE);
-       dev_priv->saveCG_2D_DIS = I915_READ(CG_2D_DIS);
+       dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D);
 
        /* Cache mode state */
        dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
@@ -588,7 +588,7 @@ int i915_restore_state(struct drm_device *dev)
 
        /* Clock gating state */
        I915_WRITE (D_STATE, dev_priv->saveD_STATE);
-       I915_WRITE (CG_2D_DIS, dev_priv->saveCG_2D_DIS);
+       I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D);
 
        /* Cache mode state */
        I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
index f806fcc..1e28c16 100644 (file)
@@ -355,8 +355,14 @@ parse_driver_features(struct drm_i915_private *dev_priv,
        }
 
        driver = find_section(bdb, BDB_DRIVER_FEATURES);
-       if (driver && driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
+       if (!driver)
+               return;
+
+       if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
                dev_priv->edp_support = 1;
+
+       if (driver->dual_frequency)
+               dev_priv->render_reclock_avail = true;
 }
 
 /**
index 590f81c..88814fa 100644 (file)
@@ -64,6 +64,34 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
        }
 
        I915_WRITE(reg, temp);
+
+       if (IS_IGD(dev)) {
+               if (mode == DRM_MODE_DPMS_OFF) {
+                       /* turn off DAC */
+                       temp = I915_READ(PORT_HOTPLUG_EN);
+                       temp &= ~CRT_EOS_INT_EN;
+                       I915_WRITE(PORT_HOTPLUG_EN, temp);
+
+                       temp = I915_READ(PORT_HOTPLUG_STAT);
+                       if (temp & CRT_EOS_INT_STATUS)
+                               I915_WRITE(PORT_HOTPLUG_STAT,
+                                       CRT_EOS_INT_STATUS);
+               } else {
+                       /* turn on DAC. EOS interrupt must be enabled after DAC
+                        * is enabled, so it sounds not good to enable it in
+                        * i915_driver_irq_postinstall()
+                        * wait 12.5ms after DAC is enabled
+                        */
+                       msleep(13);
+                       temp = I915_READ(PORT_HOTPLUG_STAT);
+                       if (temp & CRT_EOS_INT_STATUS)
+                               I915_WRITE(PORT_HOTPLUG_STAT,
+                                       CRT_EOS_INT_STATUS);
+                       temp = I915_READ(PORT_HOTPLUG_EN);
+                       temp |= CRT_EOS_INT_EN;
+                       I915_WRITE(PORT_HOTPLUG_EN, temp);
+               }
+       }
 }
 
 static int intel_crt_mode_valid(struct drm_connector *connector,
index 748ed50..0227b16 100644 (file)
@@ -38,6 +38,7 @@
 
 bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
 static void intel_update_watermarks(struct drm_device *dev);
+static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule);
 
 typedef struct {
     /* given values */
@@ -67,6 +68,8 @@ struct intel_limit {
     intel_p2_t     p2;
     bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
                      int, int, intel_clock_t *);
+    bool (* find_reduced_pll)(const intel_limit_t *, struct drm_crtc *,
+                             int, int, intel_clock_t *);
 };
 
 #define I8XX_DOT_MIN             25000
@@ -261,6 +264,9 @@ static bool
 intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                    int target, int refclk, intel_clock_t *best_clock);
 static bool
+intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
+                           int target, int refclk, intel_clock_t *best_clock);
+static bool
 intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                        int target, int refclk, intel_clock_t *best_clock);
 static bool
@@ -286,6 +292,7 @@ static const intel_limit_t intel_limits_i8xx_dvo = {
        .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
                 .p2_slow = I8XX_P2_SLOW,       .p2_fast = I8XX_P2_FAST },
        .find_pll = intel_find_best_PLL,
+       .find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
 static const intel_limit_t intel_limits_i8xx_lvds = {
@@ -300,6 +307,7 @@ static const intel_limit_t intel_limits_i8xx_lvds = {
        .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
                 .p2_slow = I8XX_P2_LVDS_SLOW,  .p2_fast = I8XX_P2_LVDS_FAST },
        .find_pll = intel_find_best_PLL,
+       .find_reduced_pll = intel_find_best_reduced_PLL,
 };
        
 static const intel_limit_t intel_limits_i9xx_sdvo = {
@@ -314,6 +322,7 @@ static const intel_limit_t intel_limits_i9xx_sdvo = {
        .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
        .find_pll = intel_find_best_PLL,
+       .find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
 static const intel_limit_t intel_limits_i9xx_lvds = {
@@ -331,6 +340,7 @@ static const intel_limit_t intel_limits_i9xx_lvds = {
        .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_FAST },
        .find_pll = intel_find_best_PLL,
+       .find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
     /* below parameter and function is for G4X Chipset Family*/
@@ -348,6 +358,7 @@ static const intel_limit_t intel_limits_g4x_sdvo = {
                 .p2_fast = G4X_P2_SDVO_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
+       .find_reduced_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_hdmi = {
@@ -364,6 +375,7 @@ static const intel_limit_t intel_limits_g4x_hdmi = {
                 .p2_fast = G4X_P2_HDMI_DAC_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
+       .find_reduced_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
@@ -388,6 +400,7 @@ static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
                 .p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
+       .find_reduced_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
@@ -412,6 +425,7 @@ static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
                 .p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
+       .find_reduced_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_display_port = {
@@ -449,6 +463,7 @@ static const intel_limit_t intel_limits_igd_sdvo = {
        .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
        .find_pll = intel_find_best_PLL,
+       .find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
 static const intel_limit_t intel_limits_igd_lvds = {
@@ -464,6 +479,7 @@ static const intel_limit_t intel_limits_igd_lvds = {
        .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_SLOW },
        .find_pll = intel_find_best_PLL,
+       .find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
 static const intel_limit_t intel_limits_igdng_sdvo = {
@@ -688,15 +704,16 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
 
        memset (best_clock, 0, sizeof (*best_clock));
 
-       for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
-               for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++) {
-                       /* m1 is always 0 in IGD */
-                       if (clock.m2 >= clock.m1 && !IS_IGD(dev))
-                               break;
-                       for (clock.n = limit->n.min; clock.n <= limit->n.max;
-                            clock.n++) {
-                               for (clock.p1 = limit->p1.min;
-                                    clock.p1 <= limit->p1.max; clock.p1++) {
+       for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
+               for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
+                    clock.m1++) {
+                       for (clock.m2 = limit->m2.min;
+                            clock.m2 <= limit->m2.max; clock.m2++) {
+                               /* m1 is always 0 in IGD */
+                               if (clock.m2 >= clock.m1 && !IS_IGD(dev))
+                                       break;
+                               for (clock.n = limit->n.min;
+                                    clock.n <= limit->n.max; clock.n++) {
                                        int this_err;
 
                                        intel_clock(dev, refclk, &clock);
@@ -717,6 +734,46 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
        return (err != target);
 }
 
+
+static bool
+intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
+                           int target, int refclk, intel_clock_t *best_clock)
+
+{
+       struct drm_device *dev = crtc->dev;
+       intel_clock_t clock;
+       int err = target;
+       bool found = false;
+
+       memcpy(&clock, best_clock, sizeof(intel_clock_t));
+
+       for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
+               for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++) {
+                       /* m1 is always 0 in IGD */
+                       if (clock.m2 >= clock.m1 && !IS_IGD(dev))
+                               break;
+                       for (clock.n = limit->n.min; clock.n <= limit->n.max;
+                            clock.n++) {
+                               int this_err;
+
+                               intel_clock(dev, refclk, &clock);
+
+                               if (!intel_PLL_is_valid(crtc, &clock))
+                                       continue;
+
+                               this_err = abs(clock.dot - target);
+                               if (this_err < err) {
+                                       *best_clock = clock;
+                                       err = this_err;
+                                       found = true;
+                               }
+                       }
+               }
+       }
+
+       return found;
+}
+
 static bool
 intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                        int target, int refclk, intel_clock_t *best_clock)
@@ -747,7 +804,7 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
        max_n = limit->n.max;
        /* based on hardware requriment prefer smaller n to precision */
        for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
-               /* based on hardware requirment prefere larger m1,m2, p1 */
+               /* based on hardware requirment prefere larger m1,m2 */
                for (clock.m1 = limit->m1.max;
                     clock.m1 >= limit->m1.min; clock.m1--) {
                        for (clock.m2 = limit->m2.max;
@@ -832,15 +889,14 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
 
        memset(best_clock, 0, sizeof(*best_clock));
        max_n = limit->n.max;
-       /* based on hardware requriment prefer smaller n to precision */
-       for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
-               /* based on hardware requirment prefere larger m1,m2, p1 */
-               for (clock.m1 = limit->m1.max;
-                    clock.m1 >= limit->m1.min; clock.m1--) {
-                       for (clock.m2 = limit->m2.max;
-                            clock.m2 >= limit->m2.min; clock.m2--) {
-                               for (clock.p1 = limit->p1.max;
-                                    clock.p1 >= limit->p1.min; clock.p1--) {
+       for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
+               /* based on hardware requriment prefer smaller n to precision */
+               for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
+                       /* based on hardware requirment prefere larger m1,m2 */
+                       for (clock.m1 = limit->m1.max;
+                            clock.m1 >= limit->m1.min; clock.m1--) {
+                               for (clock.m2 = limit->m2.max;
+                                    clock.m2 >= limit->m2.min; clock.m2--) {
                                        int this_err;
 
                                        intel_clock(dev, refclk, &clock);
@@ -1008,6 +1064,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                        dspcntr &= ~DISPPLANE_TILED;
        }
 
+       if (IS_IGDNG(dev))
+               /* must disable */
+               dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
+
        I915_WRITE(dspcntr_reg, dspcntr);
 
        Start = obj_priv->gtt_offset;
@@ -1030,8 +1090,11 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 
        if (old_fb) {
                intel_fb = to_intel_framebuffer(old_fb);
+               obj_priv = intel_fb->obj->driver_private;
                i915_gem_object_unpin(intel_fb->obj);
        }
+       intel_increase_pllclock(crtc, true);
+
        mutex_unlock(&dev->struct_mutex);
 
        if (!dev->primary->master)
@@ -1581,6 +1644,8 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
        else
                i9xx_crtc_dpms(crtc, mode);
 
+       intel_crtc->dpms_mode = mode;
+
        if (!dev->primary->master)
                return;
 
@@ -1603,8 +1668,6 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
                DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
                break;
        }
-
-       intel_crtc->dpms_mode = mode;
 }
 
 static void intel_crtc_prepare (struct drm_crtc *crtc)
@@ -2054,6 +2117,18 @@ static int intel_get_fifo_size(struct drm_device *dev, int plane)
        return size;
 }
 
+static void g4x_update_wm(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 fw_blc_self = I915_READ(FW_BLC_SELF);
+
+       if (i915_powersave)
+               fw_blc_self |= FW_BLC_SELF_EN;
+       else
+               fw_blc_self &= ~FW_BLC_SELF_EN;
+       I915_WRITE(FW_BLC_SELF, fw_blc_self);
+}
+
 static void i965_update_wm(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2105,7 +2180,8 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
        cwm = 2;
 
        /* Calc sr entries for one plane configs */
-       if (sr_hdisplay && (!planea_clock || !planeb_clock)) {
+       if (HAS_FW_BLC(dev) && sr_hdisplay &&
+           (!planea_clock || !planeb_clock)) {
                /* self-refresh has much higher latency */
                const static int sr_latency_ns = 6000;
 
@@ -2120,8 +2196,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
                srwm = total_size - sr_entries;
                if (srwm < 0)
                        srwm = 1;
-               if (IS_I9XX(dev))
-                       I915_WRITE(FW_BLC_SELF, (srwm & 0x3f));
+               I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f));
        }
 
        DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
@@ -2195,9 +2270,6 @@ static void intel_update_watermarks(struct drm_device *dev)
        unsigned long planea_clock = 0, planeb_clock = 0, sr_clock = 0;
        int enabled = 0, pixel_size = 0;
 
-       if (DSPARB_HWCONTROL(dev))
-               return;
-
        /* Get the clock config from both planes */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                intel_crtc = to_intel_crtc(crtc);
@@ -2230,7 +2302,9 @@ static void intel_update_watermarks(struct drm_device *dev)
        else if (IS_IGD(dev))
                igd_disable_cxsr(dev);
 
-       if (IS_I965G(dev))
+       if (IS_G4X(dev))
+               g4x_update_wm(dev);
+       else if (IS_I965G(dev))
                i965_update_wm(dev);
        else if (IS_I9XX(dev) || IS_MOBILE(dev))
                i9xx_update_wm(dev, planea_clock, planeb_clock, sr_hdisplay,
@@ -2264,9 +2338,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
        int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
        int refclk, num_outputs = 0;
-       intel_clock_t clock;
-       u32 dpll = 0, fp = 0, dspcntr, pipeconf;
-       bool ok, is_sdvo = false, is_dvo = false;
+       intel_clock_t clock, reduced_clock;
+       u32 dpll = 0, fp = 0, fp2 = 0, dspcntr, pipeconf;
+       bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
        bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
        bool is_edp = false;
        struct drm_mode_config *mode_config = &dev->mode_config;
@@ -2349,6 +2423,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
+       if (limit->find_reduced_pll && dev_priv->lvds_downclock_avail) {
+               memcpy(&reduced_clock, &clock, sizeof(intel_clock_t));
+               has_reduced_clock = limit->find_reduced_pll(limit, crtc,
+                                                           (adjusted_mode->clock*3/4),
+                                                           refclk,
+                                                           &reduced_clock);
+       }
+
        /* SDVO TV has fixed PLL values depend on its clock range,
           this mirrors vbios setting. */
        if (is_sdvo && is_tv) {
@@ -2394,10 +2476,17 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                  link_bw, &m_n);
        }
 
-       if (IS_IGD(dev))
+       if (IS_IGD(dev)) {
                fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
-       else
+               if (has_reduced_clock)
+                       fp2 = (1 << reduced_clock.n) << 16 |
+                               reduced_clock.m1 << 8 | reduced_clock.m2;
+       } else {
                fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
+               if (has_reduced_clock)
+                       fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
+                               reduced_clock.m2;
+       }
 
        if (!IS_IGDNG(dev))
                dpll = DPLL_VGA_MODE_DIS;
@@ -2426,6 +2515,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        /* also FPA1 */
                        if (IS_IGDNG(dev))
                                dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+                       if (IS_G4X(dev) && has_reduced_clock)
+                               dpll |= (1 << (reduced_clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
                }
                switch (clock.p2) {
                case 5:
@@ -2573,6 +2664,22 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                udelay(150);
        }
 
+       if (is_lvds && has_reduced_clock && i915_powersave) {
+               I915_WRITE(fp_reg + 4, fp2);
+               intel_crtc->lowfreq_avail = true;
+               if (HAS_PIPE_CXSR(dev)) {
+                       DRM_DEBUG("enabling CxSR downclocking\n");
+                       pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
+               }
+       } else {
+               I915_WRITE(fp_reg + 4, fp);
+               intel_crtc->lowfreq_avail = false;
+               if (HAS_PIPE_CXSR(dev)) {
+                       DRM_DEBUG("disabling CxSR downclocking\n");
+                       pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
+               }
+       }
+
        I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
                   ((adjusted_mode->crtc_htotal - 1) << 16));
        I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
@@ -2616,6 +2723,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        intel_wait_for_vblank(dev);
 
+       if (IS_IGDNG(dev)) {
+               /* enable address swizzle for tiling buffer */
+               temp = I915_READ(DISP_ARB_CTL);
+               I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
+       }
+
        I915_WRITE(dspcntr_reg, dspcntr);
 
        /* Flush the plane changes */
@@ -2769,10 +2882,16 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, 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;
        int pipe = intel_crtc->pipe;
        uint32_t temp = 0;
        uint32_t adder;
 
+       if (crtc->fb) {
+               intel_fb = to_intel_framebuffer(crtc->fb);
+               intel_mark_busy(dev, intel_fb->obj);
+       }
+
        if (x < 0) {
                temp |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
                x = -x;
@@ -3070,12 +3189,319 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
        return mode;
 }
 
+#define GPU_IDLE_TIMEOUT 500 /* ms */
+
+/* When this timer fires, we've been idle for awhile */
+static void intel_gpu_idle_timer(unsigned long arg)
+{
+       struct drm_device *dev = (struct drm_device *)arg;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       DRM_DEBUG("idle timer fired, downclocking\n");
+
+       dev_priv->busy = false;
+
+       queue_work(dev_priv->wq, &dev_priv->idle_work);
+}
+
+void intel_increase_renderclock(struct drm_device *dev, bool schedule)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       if (IS_IGDNG(dev))
+               return;
+
+       if (!dev_priv->render_reclock_avail) {
+               DRM_DEBUG("not reclocking render clock\n");
+               return;
+       }
+
+       /* Restore render clock frequency to original value */
+       if (IS_G4X(dev) || IS_I9XX(dev))
+               pci_write_config_word(dev->pdev, GCFGC, dev_priv->orig_clock);
+       else if (IS_I85X(dev))
+               pci_write_config_word(dev->pdev, HPLLCC, dev_priv->orig_clock);
+       DRM_DEBUG("increasing render clock frequency\n");
+
+       /* Schedule downclock */
+       if (schedule)
+               mod_timer(&dev_priv->idle_timer, jiffies +
+                         msecs_to_jiffies(GPU_IDLE_TIMEOUT));
+}
+
+void intel_decrease_renderclock(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       if (IS_IGDNG(dev))
+               return;
+
+       if (!dev_priv->render_reclock_avail) {
+               DRM_DEBUG("not reclocking render clock\n");
+               return;
+       }
+
+       if (IS_G4X(dev)) {
+               u16 gcfgc;
+
+               /* Adjust render clock... */
+               pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
+
+               /* Down to minimum... */
+               gcfgc &= ~GM45_GC_RENDER_CLOCK_MASK;
+               gcfgc |= GM45_GC_RENDER_CLOCK_266_MHZ;
+
+               pci_write_config_word(dev->pdev, GCFGC, gcfgc);
+       } else if (IS_I965G(dev)) {
+               u16 gcfgc;
+
+               /* Adjust render clock... */
+               pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
+
+               /* Down to minimum... */
+               gcfgc &= ~I965_GC_RENDER_CLOCK_MASK;
+               gcfgc |= I965_GC_RENDER_CLOCK_267_MHZ;
+
+               pci_write_config_word(dev->pdev, GCFGC, gcfgc);
+       } else if (IS_I945G(dev) || IS_I945GM(dev)) {
+               u16 gcfgc;
+
+               /* Adjust render clock... */
+               pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
+
+               /* Down to minimum... */
+               gcfgc &= ~I945_GC_RENDER_CLOCK_MASK;
+               gcfgc |= I945_GC_RENDER_CLOCK_166_MHZ;
+
+               pci_write_config_word(dev->pdev, GCFGC, gcfgc);
+       } else if (IS_I915G(dev)) {
+               u16 gcfgc;
+
+               /* Adjust render clock... */
+               pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
+
+               /* Down to minimum... */
+               gcfgc &= ~I915_GC_RENDER_CLOCK_MASK;
+               gcfgc |= I915_GC_RENDER_CLOCK_166_MHZ;
+
+               pci_write_config_word(dev->pdev, GCFGC, gcfgc);
+       } else if (IS_I85X(dev)) {
+               u16 hpllcc;
+
+               /* Adjust render clock... */
+               pci_read_config_word(dev->pdev, HPLLCC, &hpllcc);
+
+               /* Up to maximum... */
+               hpllcc &= ~GC_CLOCK_CONTROL_MASK;
+               hpllcc |= GC_CLOCK_133_200;
+
+               pci_write_config_word(dev->pdev, HPLLCC, hpllcc);
+       }
+       DRM_DEBUG("decreasing render clock frequency\n");
+}
+
+/* Note that no increase function is needed for this - increase_renderclock()
+ *  will also rewrite these bits
+ */
+void intel_decrease_displayclock(struct drm_device *dev)
+{
+       if (IS_IGDNG(dev))
+               return;
+
+       if (IS_I945G(dev) || IS_I945GM(dev) || IS_I915G(dev) ||
+           IS_I915GM(dev)) {
+               u16 gcfgc;
+
+               /* Adjust render clock... */
+               pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
+
+               /* Down to minimum... */
+               gcfgc &= ~0xf0;
+               gcfgc |= 0x80;
+
+               pci_write_config_word(dev->pdev, GCFGC, gcfgc);
+       }
+}
+
+#define CRTC_IDLE_TIMEOUT 1000 /* ms */
+
+static void intel_crtc_idle_timer(unsigned long arg)
+{
+       struct intel_crtc *intel_crtc = (struct intel_crtc *)arg;
+       struct drm_crtc *crtc = &intel_crtc->base;
+       drm_i915_private_t *dev_priv = crtc->dev->dev_private;
+
+       DRM_DEBUG("idle timer fired, downclocking\n");
+
+       intel_crtc->busy = false;
+
+       queue_work(dev_priv->wq, &dev_priv->idle_work);
+}
+
+static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
+{
+       struct drm_device *dev = crtc->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+       int dpll = I915_READ(dpll_reg);
+
+       if (IS_IGDNG(dev))
+               return;
+
+       if (!dev_priv->lvds_downclock_avail)
+               return;
+
+       if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) {
+               DRM_DEBUG("upclocking LVDS\n");
+
+               /* Unlock panel regs */
+               I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | (0xabcd << 16));
+
+               dpll &= ~DISPLAY_RATE_SELECT_FPA1;
+               I915_WRITE(dpll_reg, dpll);
+               dpll = I915_READ(dpll_reg);
+               intel_wait_for_vblank(dev);
+               dpll = I915_READ(dpll_reg);
+               if (dpll & DISPLAY_RATE_SELECT_FPA1)
+                       DRM_DEBUG("failed to upclock LVDS!\n");
+
+               /* ...and lock them again */
+               I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
+       }
+
+       /* Schedule downclock */
+       if (schedule)
+               mod_timer(&intel_crtc->idle_timer, jiffies +
+                         msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+}
+
+static void intel_decrease_pllclock(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+       int dpll = I915_READ(dpll_reg);
+
+       if (IS_IGDNG(dev))
+               return;
+
+       if (!dev_priv->lvds_downclock_avail)
+               return;
+
+       /*
+        * Since this is called by a timer, we should never get here in
+        * the manual case.
+        */
+       if (!HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) {
+               DRM_DEBUG("downclocking LVDS\n");
+
+               /* Unlock panel regs */
+               I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | (0xabcd << 16));
+
+               dpll |= DISPLAY_RATE_SELECT_FPA1;
+               I915_WRITE(dpll_reg, dpll);
+               dpll = I915_READ(dpll_reg);
+               intel_wait_for_vblank(dev);
+               dpll = I915_READ(dpll_reg);
+               if (!(dpll & DISPLAY_RATE_SELECT_FPA1))
+                       DRM_DEBUG("failed to downclock LVDS!\n");
+
+               /* ...and lock them again */
+               I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
+       }
+
+}
+
+/**
+ * intel_idle_update - adjust clocks for idleness
+ * @work: work struct
+ *
+ * Either the GPU or display (or both) went idle.  Check the busy status
+ * here and adjust the CRTC and GPU clocks as necessary.
+ */
+static void intel_idle_update(struct work_struct *work)
+{
+       drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+                                                   idle_work);
+       struct drm_device *dev = dev_priv->dev;
+       struct drm_crtc *crtc;
+       struct intel_crtc *intel_crtc;
+
+       if (!i915_powersave)
+               return;
+
+       mutex_lock(&dev->struct_mutex);
+
+       /* GPU isn't processing, downclock it. */
+       if (!dev_priv->busy) {
+               intel_decrease_renderclock(dev);
+               intel_decrease_displayclock(dev);
+       }
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               /* Skip inactive CRTCs */
+               if (!crtc->fb)
+                       continue;
+
+               intel_crtc = to_intel_crtc(crtc);
+               if (!intel_crtc->busy)
+                       intel_decrease_pllclock(crtc);
+       }
+
+       mutex_unlock(&dev->struct_mutex);
+}
+
+/**
+ * intel_mark_busy - mark the GPU and possibly the display busy
+ * @dev: drm device
+ * @obj: object we're operating on
+ *
+ * Callers can use this function to indicate that the GPU is busy processing
+ * commands.  If @obj matches one of the CRTC objects (i.e. it's a scanout
+ * buffer), we'll also mark the display as busy, so we know to increase its
+ * clock frequency.
+ */
+void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = NULL;
+       struct intel_framebuffer *intel_fb;
+       struct intel_crtc *intel_crtc;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return;
+
+       dev_priv->busy = true;
+       intel_increase_renderclock(dev, true);
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (!crtc->fb)
+                       continue;
+
+               intel_crtc = to_intel_crtc(crtc);
+               intel_fb = to_intel_framebuffer(crtc->fb);
+               if (intel_fb->obj == obj) {
+                       if (!intel_crtc->busy) {
+                               /* Non-busy -> busy, upclock */
+                               intel_increase_pllclock(crtc, true);
+                               intel_crtc->busy = true;
+                       } else {
+                               /* Busy -> busy, put off timer */
+                               mod_timer(&intel_crtc->idle_timer, jiffies +
+                                         msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+                       }
+               }
+       }
+}
+
 static void intel_crtc_destroy(struct drm_crtc *crtc)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       if (intel_crtc->mode_set.mode)
-               drm_mode_destroy(crtc->dev, intel_crtc->mode_set.mode);
        drm_crtc_cleanup(crtc);
        kfree(intel_crtc);
 }
@@ -3122,15 +3548,10 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF;
        drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
 
-       intel_crtc->mode_set.crtc = &intel_crtc->base;
-       intel_crtc->mode_set.connectors = (struct drm_connector **)(intel_crtc + 1);
-       intel_crtc->mode_set.num_connectors = 0;
-
-       if (i915_fbpercrtc) {
+       intel_crtc->busy = false;
 
-
-
-       }
+       setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
+                   (unsigned long)intel_crtc);
 }
 
 int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
@@ -3138,30 +3559,26 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_get_pipe_from_crtc_id *pipe_from_crtc_id = data;
-       struct drm_crtc *crtc = NULL;
-       int pipe = -1;
+       struct drm_mode_object *drmmode_obj;
+       struct intel_crtc *crtc;
 
        if (!dev_priv) {
                DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-               if (crtc->base.id == pipe_from_crtc_id->crtc_id) {
-                       pipe = intel_crtc->pipe;
-                       break;
-               }
-       }
+       drmmode_obj = drm_mode_object_find(dev, pipe_from_crtc_id->crtc_id,
+                       DRM_MODE_OBJECT_CRTC);
 
-       if (pipe == -1) {
+       if (!drmmode_obj) {
                DRM_ERROR("no such CRTC id\n");
                return -EINVAL;
        }
 
-       pipe_from_crtc_id->pipe = pipe;
+       crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
+       pipe_from_crtc_id->pipe = crtc->pipe;
 
-       return 0;
+       return 0;
 }
 
 struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
@@ -3362,8 +3779,56 @@ static const struct drm_mode_config_funcs intel_mode_funcs = {
        .fb_changed = intelfb_probe,
 };
 
+void intel_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /*
+        * Disable clock gating reported to work incorrectly according to the
+        * specs, but enable as much else as we can.
+        */
+       if (IS_G4X(dev)) {
+               uint32_t dspclk_gate;
+               I915_WRITE(RENCLK_GATE_D1, 0);
+               I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
+                      GS_UNIT_CLOCK_GATE_DISABLE |
+                      CL_UNIT_CLOCK_GATE_DISABLE);
+               I915_WRITE(RAMCLK_GATE_D, 0);
+               dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
+                       OVRUNIT_CLOCK_GATE_DISABLE |
+                       OVCUNIT_CLOCK_GATE_DISABLE;
+               if (IS_GM45(dev))
+                       dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
+               I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
+       } else if (IS_I965GM(dev)) {
+               I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
+               I915_WRITE(RENCLK_GATE_D2, 0);
+               I915_WRITE(DSPCLK_GATE_D, 0);
+               I915_WRITE(RAMCLK_GATE_D, 0);
+               I915_WRITE16(DEUC, 0);
+       } else if (IS_I965G(dev)) {
+               I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
+                      I965_RCC_CLOCK_GATE_DISABLE |
+                      I965_RCPB_CLOCK_GATE_DISABLE |
+                      I965_ISC_CLOCK_GATE_DISABLE |
+                      I965_FBC_CLOCK_GATE_DISABLE);
+               I915_WRITE(RENCLK_GATE_D2, 0);
+       } else if (IS_I9XX(dev)) {
+               u32 dstate = I915_READ(D_STATE);
+
+               dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
+                       DSTATE_DOT_CLOCK_GATING;
+               I915_WRITE(D_STATE, dstate);
+       } else if (IS_I855(dev) || IS_I865G(dev)) {
+               I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
+       } else if (IS_I830(dev)) {
+               I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
+       }
+}
+
 void intel_modeset_init(struct drm_device *dev)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int num_pipe;
        int i;
 
@@ -3398,15 +3863,47 @@ void intel_modeset_init(struct drm_device *dev)
        DRM_DEBUG("%d display pipe%s available.\n",
                  num_pipe, num_pipe > 1 ? "s" : "");
 
+       if (IS_I85X(dev))
+               pci_read_config_word(dev->pdev, HPLLCC, &dev_priv->orig_clock);
+       else if (IS_I9XX(dev) || IS_G4X(dev))
+               pci_read_config_word(dev->pdev, GCFGC, &dev_priv->orig_clock);
+
        for (i = 0; i < num_pipe; i++) {
                intel_crtc_init(dev, i);
        }
 
        intel_setup_outputs(dev);
+
+       intel_init_clock_gating(dev);
+
+       INIT_WORK(&dev_priv->idle_work, intel_idle_update);
+       setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
+                   (unsigned long)dev);
 }
 
 void intel_modeset_cleanup(struct drm_device *dev)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc;
+       struct intel_crtc *intel_crtc;
+
+       mutex_lock(&dev->struct_mutex);
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               /* Skip inactive CRTCs */
+               if (!crtc->fb)
+                       continue;
+
+               intel_crtc = to_intel_crtc(crtc);
+               intel_increase_pllclock(crtc, false);
+               del_timer_sync(&intel_crtc->idle_timer);
+       }
+
+       intel_increase_renderclock(dev, false);
+       del_timer_sync(&dev_priv->idle_timer);
+
+       mutex_unlock(&dev->struct_mutex);
+
        drm_mode_config_cleanup(dev);
 }
 
@@ -3420,3 +3917,20 @@ struct drm_encoder *intel_best_encoder(struct drm_connector *connector)
 
        return &intel_output->enc;
 }
+
+/*
+ * set vga decode state - true == enable VGA decode
+ */
+int intel_modeset_vga_set_state(struct drm_device *dev, bool state)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u16 gmch_ctrl;
+
+       pci_read_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, &gmch_ctrl);
+       if (state)
+               gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE;
+       else
+               gmch_ctrl |= INTEL_GMCH_VGA_DISABLE;
+       pci_write_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, gmch_ctrl);
+       return 0;
+}
index 26a6227..3ebbbab 100644 (file)
@@ -117,9 +117,9 @@ struct intel_crtc {
        uint32_t cursor_addr;
        u8 lut_r[256], lut_g[256], lut_b[256];
        int dpms_mode;
-       struct intel_framebuffer *fbdev_fb;
-       /* a mode_set for fbdev users on this crtc */
-       struct drm_mode_set mode_set;
+       bool busy; /* is scanout buffer being updated frequently? */
+       struct timer_list idle_timer;
+       bool lowfreq_avail;
 };
 
 #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
@@ -138,6 +138,7 @@ extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
 extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
 extern void intel_dvo_init(struct drm_device *dev);
 extern void intel_tv_init(struct drm_device *dev);
+extern void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj);
 extern void intel_lvds_init(struct drm_device *dev);
 extern void intel_dp_init(struct drm_device *dev, int dp_reg);
 void
@@ -178,4 +179,5 @@ extern int intel_framebuffer_create(struct drm_device *dev,
                                    struct drm_mode_fb_cmd *mode_cmd,
                                    struct drm_framebuffer **fb,
                                    struct drm_gem_object *obj);
+
 #endif /* __INTEL_DRV_H__ */
index 1d30802..7ba4a23 100644 (file)
 #include "drmP.h"
 #include "drm.h"
 #include "drm_crtc.h"
+#include "drm_fb_helper.h"
 #include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
 
 struct intelfb_par {
-       struct drm_device *dev;
-       struct drm_display_mode *our_mode;
+       struct drm_fb_helper helper;
        struct intel_framebuffer *intel_fb;
-       int crtc_count;
-       /* crtc currently bound to this */
-       uint32_t crtc_ids[2];
+       struct drm_display_mode *our_mode;
 };
 
-static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                       unsigned blue, unsigned transp,
-                       struct fb_info *info)
-{
-       struct intelfb_par *par = info->par;
-       struct drm_device *dev = par->dev;
-       struct drm_crtc *crtc;
-       int i;
-
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-               struct drm_mode_set *modeset = &intel_crtc->mode_set;
-               struct drm_framebuffer *fb = modeset->fb;
-
-               for (i = 0; i < par->crtc_count; i++)
-                       if (crtc->base.id == par->crtc_ids[i])
-                               break;
-
-               if (i == par->crtc_count)
-                       continue;
-
-
-               if (regno > 255)
-                       return 1;
-
-               if (fb->depth == 8) {
-                       intel_crtc_fb_gamma_set(crtc, red, green, blue, regno);
-                       return 0;
-               }
-
-               if (regno < 16) {
-                       switch (fb->depth) {
-                       case 15:
-                               fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
-                                       ((green & 0xf800) >>  6) |
-                                       ((blue & 0xf800) >> 11);
-                               break;
-                       case 16:
-                               fb->pseudo_palette[regno] = (red & 0xf800) |
-                                       ((green & 0xfc00) >>  5) |
-                                       ((blue  & 0xf800) >> 11);
-                               break;
-                       case 24:
-                       case 32:
-                               fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
-                                       (green & 0xff00) |
-                                       ((blue  & 0xff00) >> 8);
-                               break;
-                       }
-               }
-       }
-       return 0;
-}
-
-static int intelfb_check_var(struct fb_var_screeninfo *var,
-                       struct fb_info *info)
-{
-       struct intelfb_par *par = info->par;
-       struct intel_framebuffer *intel_fb = par->intel_fb;
-       struct drm_framebuffer *fb = &intel_fb->base;
-       int depth;
-
-       if (var->pixclock == -1 || !var->pixclock)
-               return -EINVAL;
-
-       /* Need to resize the fb object !!! */
-       if (var->xres > fb->width || var->yres > fb->height) {
-               DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height);
-               DRM_ERROR("Need resizing code.\n");
-               return -EINVAL;
-       }
-
-       switch (var->bits_per_pixel) {
-       case 16:
-               depth = (var->green.length == 6) ? 16 : 15;
-               break;
-       case 32:
-               depth = (var->transp.length > 0) ? 32 : 24;
-               break;
-       default:
-               depth = var->bits_per_pixel;
-               break;
-       }
-
-       switch (depth) {
-       case 8:
-               var->red.offset = 0;
-               var->green.offset = 0;
-               var->blue.offset = 0;
-               var->red.length = 8;
-               var->green.length = 8;
-               var->blue.length = 8;
-               var->transp.length = 0;
-               var->transp.offset = 0;
-               break;
-       case 15:
-               var->red.offset = 10;
-               var->green.offset = 5;
-               var->blue.offset = 0;
-               var->red.length = 5;
-               var->green.length = 5;
-               var->blue.length = 5;
-               var->transp.length = 1;
-               var->transp.offset = 15;
-               break;
-       case 16:
-               var->red.offset = 11;
-               var->green.offset = 5;
-               var->blue.offset = 0;
-               var->red.length = 5;
-               var->green.length = 6;
-               var->blue.length = 5;
-               var->transp.length = 0;
-               var->transp.offset = 0;
-               break;
-       case 24:
-               var->red.offset = 16;
-               var->green.offset = 8;
-               var->blue.offset = 0;
-               var->red.length = 8;
-               var->green.length = 8;
-               var->blue.length = 8;
-               var->transp.length = 0;
-               var->transp.offset = 0;
-               break;
-       case 32:
-               var->red.offset = 16;
-               var->green.offset = 8;
-               var->blue.offset = 0;
-               var->red.length = 8;
-               var->green.length = 8;
-               var->blue.length = 8;
-               var->transp.length = 8;
-               var->transp.offset = 24;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* this will let fbcon do the mode init */
-/* FIXME: take mode config lock? */
-static int intelfb_set_par(struct fb_info *info)
-{
-       struct intelfb_par *par = info->par;
-       struct drm_device *dev = par->dev;
-       struct fb_var_screeninfo *var = &info->var;
-       int i;
-
-       DRM_DEBUG("%d %d\n", var->xres, var->pixclock);
-
-       if (var->pixclock != -1) {
-
-               DRM_ERROR("PIXEL CLOCK SET\n");
-               return -EINVAL;
-       } else {
-               struct drm_crtc *crtc;
-               int ret;
-
-               list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-                       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-                       for (i = 0; i < par->crtc_count; i++)
-                               if (crtc->base.id == par->crtc_ids[i])
-                                       break;
-
-                       if (i == par->crtc_count)
-                               continue;
-
-                       if (crtc->fb == intel_crtc->mode_set.fb) {
-                               mutex_lock(&dev->mode_config.mutex);
-                               ret = crtc->funcs->set_config(&intel_crtc->mode_set);
-                               mutex_unlock(&dev->mode_config.mutex);
-                               if (ret)
-                                       return ret;
-                       }
-               }
-               return 0;
-       }
-}
-
-static int intelfb_pan_display(struct fb_var_screeninfo *var,
-                               struct fb_info *info)
-{
-       struct intelfb_par *par = info->par;
-       struct drm_device *dev = par->dev;
-       struct drm_mode_set *modeset;
-       struct drm_crtc *crtc;
-       struct intel_crtc *intel_crtc;
-       int ret = 0;
-       int i;
-
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               for (i = 0; i < par->crtc_count; i++)
-                       if (crtc->base.id == par->crtc_ids[i])
-                               break;
-
-               if (i == par->crtc_count)
-                       continue;
-
-               intel_crtc = to_intel_crtc(crtc);
-               modeset = &intel_crtc->mode_set;
-
-               modeset->x = var->xoffset;
-               modeset->y = var->yoffset;
-
-               if (modeset->num_connectors) {
-                       mutex_lock(&dev->mode_config.mutex);
-                       ret = crtc->funcs->set_config(modeset);
-                       mutex_unlock(&dev->mode_config.mutex);
-                       if (!ret) {
-                               info->var.xoffset = var->xoffset;
-                               info->var.yoffset = var->yoffset;
-                       }
-               }
-       }
-
-       return ret;
-}
-
-static void intelfb_on(struct fb_info *info)
-{
-       struct intelfb_par *par = info->par;
-       struct drm_device *dev = par->dev;
-       struct drm_crtc *crtc;
-       struct drm_encoder *encoder;
-       int i;
-
-       /*
-        * For each CRTC in this fb, find all associated encoders
-        * and turn them off, then turn off the CRTC.
-        */
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-
-               for (i = 0; i < par->crtc_count; i++)
-                       if (crtc->base.id == par->crtc_ids[i])
-                               break;
-
-               crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
-
-               /* Found a CRTC on this fb, now find encoders */
-               list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-                       if (encoder->crtc == crtc) {
-                               struct drm_encoder_helper_funcs *encoder_funcs;
-                               encoder_funcs = encoder->helper_private;
-                               encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
-                       }
-               }
-       }
-}
-
-static void intelfb_off(struct fb_info *info, int dpms_mode)
-{
-       struct intelfb_par *par = info->par;
-       struct drm_device *dev = par->dev;
-       struct drm_crtc *crtc;
-       struct drm_encoder *encoder;
-       int i;
-
-       /*
-        * For each CRTC in this fb, find all associated encoders
-        * and turn them off, then turn off the CRTC.
-        */
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-
-               for (i = 0; i < par->crtc_count; i++)
-                       if (crtc->base.id == par->crtc_ids[i])
-                               break;
-
-               /* Found a CRTC on this fb, now find encoders */
-               list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-                       if (encoder->crtc == crtc) {
-                               struct drm_encoder_helper_funcs *encoder_funcs;
-                               encoder_funcs = encoder->helper_private;
-                               encoder_funcs->dpms(encoder, dpms_mode);
-                       }
-               }
-               if (dpms_mode == DRM_MODE_DPMS_OFF)
-                       crtc_funcs->dpms(crtc, dpms_mode);
-       }
-}
-
-static int intelfb_blank(int blank, struct fb_info *info)
-{
-       switch (blank) {
-       case FB_BLANK_UNBLANK:
-               intelfb_on(info);
-               break;
-       case FB_BLANK_NORMAL:
-               intelfb_off(info, DRM_MODE_DPMS_STANDBY);
-               break;
-       case FB_BLANK_HSYNC_SUSPEND:
-               intelfb_off(info, DRM_MODE_DPMS_STANDBY);
-               break;
-       case FB_BLANK_VSYNC_SUSPEND:
-               intelfb_off(info, DRM_MODE_DPMS_SUSPEND);
-               break;
-       case FB_BLANK_POWERDOWN:
-               intelfb_off(info, DRM_MODE_DPMS_OFF);
-               break;
-       }
-       return 0;
-}
-
 static struct fb_ops intelfb_ops = {
        .owner = THIS_MODULE,
-       .fb_check_var = intelfb_check_var,
-       .fb_set_par = intelfb_set_par,
-       .fb_setcolreg = intelfb_setcolreg,
+       .fb_check_var = drm_fb_helper_check_var,
+       .fb_set_par = drm_fb_helper_set_par,
+       .fb_setcolreg = drm_fb_helper_setcolreg,
        .fb_fillrect = cfb_fillrect,
        .fb_copyarea = cfb_copyarea,
        .fb_imageblit = cfb_imageblit,
-       .fb_pan_display = intelfb_pan_display,
-       .fb_blank = intelfb_blank,
+       .fb_pan_display = drm_fb_helper_pan_display,
+       .fb_blank = drm_fb_helper_blank,
 };
 
+static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
+       .gamma_set = intel_crtc_fb_gamma_set,
+};
+
+
 /**
  * Curretly it is assumed that the old framebuffer is reused.
  *
@@ -412,25 +107,10 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(intelfb_resize);
 
-static struct drm_mode_set kernelfb_mode;
-
-static int intelfb_panic(struct notifier_block *n, unsigned long ununsed,
-                        void *panic_str)
-{
-       DRM_ERROR("panic occurred, switching back to text console\n");
-
-       intelfb_restore();
-       return 0;
-}
-
-static struct notifier_block paniced = {
-       .notifier_call = intelfb_panic,
-};
-
 static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
                          uint32_t fb_height, uint32_t surface_width,
                          uint32_t surface_height,
-                         struct intel_framebuffer **intel_fb_p)
+                         struct drm_framebuffer **fb_p)
 {
        struct fb_info *info;
        struct intelfb_par *par;
@@ -479,7 +159,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
        list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
 
        intel_fb = to_intel_framebuffer(fb);
-       *intel_fb_p = intel_fb;
+       *fb_p = fb;
 
        info = framebuffer_alloc(sizeof(struct intelfb_par), device);
        if (!info) {
@@ -489,21 +169,19 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
 
        par = info->par;
 
+       par->helper.funcs = &intel_fb_helper_funcs;
+       par->helper.dev = dev;
+       ret = drm_fb_helper_init_crtc_count(&par->helper, 2,
+                                           INTELFB_CONN_LIMIT);
+       if (ret)
+               goto out_unref;
+
        strcpy(info->fix.id, "inteldrmfb");
-       info->fix.type = FB_TYPE_PACKED_PIXELS;
-       info->fix.visual = FB_VISUAL_TRUECOLOR;
-       info->fix.type_aux = 0;
-       info->fix.xpanstep = 1; /* doing it in hw */
-       info->fix.ypanstep = 1; /* doing it in hw */
-       info->fix.ywrapstep = 0;
-       info->fix.accel = FB_ACCEL_I830;
-       info->fix.type_aux = 0;
 
        info->flags = FBINFO_DEFAULT;
 
        info->fbops = &intelfb_ops;
 
-       info->fix.line_length = fb->pitch;
 
        /* setup aperture base/size for vesafb takeover */
        info->aperture_base = dev->mode_config.fb_base;
@@ -527,18 +205,8 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
 
 //     memset(info->screen_base, 0, size);
 
-       info->pseudo_palette = fb->pseudo_palette;
-       info->var.xres_virtual = fb->width;
-       info->var.yres_virtual = fb->height;
-       info->var.bits_per_pixel = fb->bits_per_pixel;
-       info->var.xoffset = 0;
-       info->var.yoffset = 0;
-       info->var.activate = FB_ACTIVATE_NOW;
-       info->var.height = -1;
-       info->var.width = -1;
-
-       info->var.xres = fb_width;
-       info->var.yres = fb_height;
+       drm_fb_helper_fill_fix(info, fb->pitch);
+       drm_fb_helper_fill_var(info, fb, fb_width, fb_height);
 
        /* FIXME: we really shouldn't expose mmio space at all */
        info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar);
@@ -550,64 +218,9 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
        info->pixmap.flags = FB_PIXMAP_SYSTEM;
        info->pixmap.scan_align = 1;
 
-       switch(fb->depth) {
-       case 8:
-               info->var.red.offset = 0;
-               info->var.green.offset = 0;
-               info->var.blue.offset = 0;
-               info->var.red.length = 8; /* 8bit DAC */
-               info->var.green.length = 8;
-               info->var.blue.length = 8;
-               info->var.transp.offset = 0;
-               info->var.transp.length = 0;
-               break;
-       case 15:
-               info->var.red.offset = 10;
-               info->var.green.offset = 5;
-               info->var.blue.offset = 0;
-               info->var.red.length = 5;
-               info->var.green.length = 5;
-               info->var.blue.length = 5;
-               info->var.transp.offset = 15;
-               info->var.transp.length = 1;
-               break;
-       case 16:
-               info->var.red.offset = 11;
-               info->var.green.offset = 5;
-               info->var.blue.offset = 0;
-               info->var.red.length = 5;
-               info->var.green.length = 6;
-               info->var.blue.length = 5;
-               info->var.transp.offset = 0;
-               break;
-       case 24:
-               info->var.red.offset = 16;
-               info->var.green.offset = 8;
-               info->var.blue.offset = 0;
-               info->var.red.length = 8;
-               info->var.green.length = 8;
-               info->var.blue.length = 8;
-               info->var.transp.offset = 0;
-               info->var.transp.length = 0;
-               break;
-       case 32:
-               info->var.red.offset = 16;
-               info->var.green.offset = 8;
-               info->var.blue.offset = 0;
-               info->var.red.length = 8;
-               info->var.green.length = 8;
-               info->var.blue.length = 8;
-               info->var.transp.offset = 24;
-               info->var.transp.length = 8;
-               break;
-       default:
-               break;
-       }
-
        fb->fbdev = info;
 
        par->intel_fb = intel_fb;
-       par->dev = dev;
 
        /* To allow resizeing without swapping buffers */
        DRM_DEBUG("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width,
@@ -625,307 +238,12 @@ out:
        return ret;
 }
 
-static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc)
-{
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_framebuffer *intel_fb;
-       struct drm_framebuffer *fb;
-       struct drm_connector *connector;
-       struct fb_info *info;
-       struct intelfb_par *par;
-       struct drm_mode_set *modeset;
-       unsigned int width, height;
-       int new_fb = 0;
-       int ret, i, conn_count;
-
-       if (!drm_helper_crtc_in_use(crtc))
-               return 0;
-
-       if (!crtc->desired_mode)
-               return 0;
-
-       width = crtc->desired_mode->hdisplay;
-       height = crtc->desired_mode->vdisplay;
-
-       /* is there an fb bound to this crtc already */
-       if (!intel_crtc->mode_set.fb) {
-               ret = intelfb_create(dev, width, height, width, height, &intel_fb);
-               if (ret)
-                       return -EINVAL;
-               new_fb = 1;
-       } else {
-               fb = intel_crtc->mode_set.fb;
-               intel_fb = to_intel_framebuffer(fb);
-               if ((intel_fb->base.width < width) || (intel_fb->base.height < height))
-                       return -EINVAL;
-       }
-
-       info = intel_fb->base.fbdev;
-       par = info->par;
-
-       modeset = &intel_crtc->mode_set;
-       modeset->fb = &intel_fb->base;
-       conn_count = 0;
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               if (connector->encoder)
-                       if (connector->encoder->crtc == modeset->crtc) {
-                               modeset->connectors[conn_count] = connector;
-                               conn_count++;
-                               if (conn_count > INTELFB_CONN_LIMIT)
-                                       BUG();
-                       }
-       }
-
-       for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
-               modeset->connectors[i] = NULL;
-
-       par->crtc_ids[0] = crtc->base.id;
-
-       modeset->num_connectors = conn_count;
-       if (modeset->crtc->desired_mode) {
-               if (modeset->mode)
-                       drm_mode_destroy(dev, modeset->mode);
-               modeset->mode = drm_mode_duplicate(dev,
-                                                  modeset->crtc->desired_mode);
-       }
-
-       par->crtc_count = 1;
-
-       if (new_fb) {
-               info->var.pixclock = -1;
-               if (register_framebuffer(info) < 0)
-                       return -EINVAL;
-       } else
-               intelfb_set_par(info);
-
-       DRM_INFO("fb%d: %s frame buffer device\n", info->node,
-              info->fix.id);
-
-       /* Switch back to kernel console on panic */
-       kernelfb_mode = *modeset;
-       atomic_notifier_chain_register(&panic_notifier_list, &paniced);
-       DRM_DEBUG("registered panic notifier\n");
-
-       return 0;
-}
-
-static int intelfb_multi_fb_probe(struct drm_device *dev)
-{
-
-       struct drm_crtc *crtc;
-       int ret = 0;
-
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               ret = intelfb_multi_fb_probe_crtc(dev, crtc);
-               if (ret)
-                       return ret;
-       }
-       return ret;
-}
-
-static int intelfb_single_fb_probe(struct drm_device *dev)
-{
-       struct drm_crtc *crtc;
-       struct drm_connector *connector;
-       unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
-       unsigned int surface_width = 0, surface_height = 0;
-       int new_fb = 0;
-       int crtc_count = 0;
-       int ret, i, conn_count = 0;
-       struct intel_framebuffer *intel_fb;
-       struct fb_info *info;
-       struct intelfb_par *par;
-       struct drm_mode_set *modeset = NULL;
-
-       DRM_DEBUG("\n");
-
-       /* Get a count of crtcs now in use and new min/maxes width/heights */
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               if (!drm_helper_crtc_in_use(crtc))
-                       continue;
-
-               crtc_count++;
-               if (!crtc->desired_mode)
-                       continue;
-
-               /* Smallest mode determines console size... */
-               if (crtc->desired_mode->hdisplay < fb_width)
-                       fb_width = crtc->desired_mode->hdisplay;
-
-               if (crtc->desired_mode->vdisplay < fb_height)
-                       fb_height = crtc->desired_mode->vdisplay;
-
-               /* ... but largest for memory allocation dimensions */
-               if (crtc->desired_mode->hdisplay > surface_width)
-                       surface_width = crtc->desired_mode->hdisplay;
-
-               if (crtc->desired_mode->vdisplay > surface_height)
-                       surface_height = crtc->desired_mode->vdisplay;
-       }
-
-       if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
-               /* hmm everyone went away - assume VGA cable just fell out
-                  and will come back later. */
-               DRM_DEBUG("no CRTCs available?\n");
-               return 0;
-       }
-
-//fail
-       /* Find the fb for our new config */
-       if (list_empty(&dev->mode_config.fb_kernel_list)) {
-               DRM_DEBUG("creating new fb (console size %dx%d, "
-                         "buffer size %dx%d)\n", fb_width, fb_height,
-                         surface_width, surface_height);
-               ret = intelfb_create(dev, fb_width, fb_height, surface_width,
-                                    surface_height, &intel_fb);
-               if (ret)
-                       return -EINVAL;
-               new_fb = 1;
-       } else {
-               struct drm_framebuffer *fb;
-
-               fb = list_first_entry(&dev->mode_config.fb_kernel_list,
-                                     struct drm_framebuffer, filp_head);
-               intel_fb = to_intel_framebuffer(fb);
-
-               /* if someone hotplugs something bigger than we have already
-                * allocated, we are pwned.  As really we can't resize an
-                * fbdev that is in the wild currently due to fbdev not really
-                * being designed for the lower layers moving stuff around
-                * under it.
-                * - so in the grand style of things - punt.
-                */
-               if ((fb->width < surface_width) ||
-                   (fb->height < surface_height)) {
-                       DRM_ERROR("fb not large enough for console\n");
-                       return -EINVAL;
-               }
-       }
-// fail
-
-       info = intel_fb->base.fbdev;
-       par = info->par;
-
-       crtc_count = 0;
-       /*
-        * For each CRTC, set up the connector list for the CRTC's mode
-        * set configuration.
-        */
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-               modeset = &intel_crtc->mode_set;
-               modeset->fb = &intel_fb->base;
-               conn_count = 0;
-               list_for_each_entry(connector, &dev->mode_config.connector_list,
-                                   head) {
-                       if (!connector->encoder)
-                               continue;
-
-                       if(connector->encoder->crtc == modeset->crtc) {
-                               modeset->connectors[conn_count++] = connector;
-                               if (conn_count > INTELFB_CONN_LIMIT)
-                                       BUG();
-                       }
-               }
-
-               /* Zero out remaining connector pointers */
-               for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
-                       modeset->connectors[i] = NULL;
-
-               par->crtc_ids[crtc_count++] = crtc->base.id;
-
-               modeset->num_connectors = conn_count;
-               if (modeset->crtc->desired_mode) {
-                       if (modeset->mode)
-                               drm_mode_destroy(dev, modeset->mode);
-                       modeset->mode = drm_mode_duplicate(dev,
-                                                          modeset->crtc->desired_mode);
-               }
-       }
-       par->crtc_count = crtc_count;
-
-       if (new_fb) {
-               info->var.pixclock = -1;
-               if (register_framebuffer(info) < 0)
-                       return -EINVAL;
-       } else
-               intelfb_set_par(info);
-
-       DRM_INFO("fb%d: %s frame buffer device\n", info->node,
-              info->fix.id);
-
-       /* Switch back to kernel console on panic */
-       kernelfb_mode = *modeset;
-       atomic_notifier_chain_register(&panic_notifier_list, &paniced);
-       DRM_DEBUG("registered panic notifier\n");
-
-       return 0;
-}
-
-/**
- * intelfb_restore - restore the framebuffer console (kernel) config
- *
- * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
- */
-void intelfb_restore(void)
-{
-       int ret;
-       if ((ret = drm_crtc_helper_set_config(&kernelfb_mode)) != 0) {
-               DRM_ERROR("Failed to restore crtc configuration: %d\n",
-                         ret);
-       }
-}
-
-static void intelfb_restore_work_fn(struct work_struct *ignored)
-{
-       intelfb_restore();
-}
-static DECLARE_WORK(intelfb_restore_work, intelfb_restore_work_fn);
-
-static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3)
-{
-        schedule_work(&intelfb_restore_work);
-}
-
-static struct sysrq_key_op sysrq_intelfb_restore_op = {
-        .handler = intelfb_sysrq,
-        .help_msg = "force-fb(V)",
-        .action_msg = "Restore framebuffer console",
-};
-
 int intelfb_probe(struct drm_device *dev)
 {
        int ret;
 
        DRM_DEBUG("\n");
-
-       /* something has changed in the lower levels of hell - deal with it
-          here */
-
-       /* two modes : a) 1 fb to rule all crtcs.
-                      b) one fb per crtc.
-          two actions 1) new connected device
-                      2) device removed.
-          case a/1 : if the fb surface isn't big enough - resize the surface fb.
-                     if the fb size isn't big enough - resize fb into surface.
-                     if everything big enough configure the new crtc/etc.
-          case a/2 : undo the configuration
-                     possibly resize down the fb to fit the new configuration.
-           case b/1 : see if it is on a new crtc - setup a new fb and add it.
-          case b/2 : teardown the new fb.
-       */
-
-       /* mode a first */
-       /* search for an fb */
-       if (i915_fbpercrtc == 1) {
-               ret = intelfb_multi_fb_probe(dev);
-       } else {
-               ret = intelfb_single_fb_probe(dev);
-       }
-
-       register_sysrq_key('v', &sysrq_intelfb_restore_op);
-
+       ret = drm_fb_helper_single_fb_probe(dev, intelfb_create);
        return ret;
 }
 EXPORT_SYMBOL(intelfb_probe);
@@ -940,13 +258,14 @@ int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
        info = fb->fbdev;
 
        if (info) {
+               struct intelfb_par *par = info->par;
                unregister_framebuffer(info);
                iounmap(info->screen_base);
+               if (info->par)
+                       drm_fb_helper_free(&par->helper);
                framebuffer_release(info);
        }
 
-       atomic_notifier_chain_unregister(&panic_notifier_list, &paniced);
-       memset(&kernelfb_mode, 0, sizeof(struct drm_mode_set));
        return 0;
 }
 EXPORT_SYMBOL(intelfb_remove);
index 62b8bea..c7eab72 100644 (file)
@@ -42,11 +42,11 @@ void intel_i2c_quirk_set(struct drm_device *dev, bool enable)
        if (!IS_IGD(dev))
                return;
        if (enable)
-               I915_WRITE(CG_2D_DIS,
-                       I915_READ(CG_2D_DIS) | DPCUNIT_CLOCK_GATE_DISABLE);
+               I915_WRITE(DSPCLK_GATE_D,
+                       I915_READ(DSPCLK_GATE_D) | DPCUNIT_CLOCK_GATE_DISABLE);
        else
-               I915_WRITE(CG_2D_DIS,
-                       I915_READ(CG_2D_DIS) & (~DPCUNIT_CLOCK_GATE_DISABLE));
+               I915_WRITE(DSPCLK_GATE_D,
+                       I915_READ(DSPCLK_GATE_D) & (~DPCUNIT_CLOCK_GATE_DISABLE));
 }
 
 /*
index 8df02ef..dafc0da 100644 (file)
 #include "i915_drv.h"
 #include <linux/acpi.h>
 
-#define I915_LVDS "i915_lvds"
-
-/*
- * the following four scaling options are defined.
- * #define DRM_MODE_SCALE_NON_GPU      0
- * #define DRM_MODE_SCALE_FULLSCREEN   1
- * #define DRM_MODE_SCALE_NO_SCALE     2
- * #define DRM_MODE_SCALE_ASPECT       3
- */
-
 /* Private structure for the integrated LVDS support */
 struct intel_lvds_priv {
        int fitting_mode;
@@ -336,7 +326,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
        I915_WRITE(BCLRPAT_B, 0);
 
        switch (lvds_priv->fitting_mode) {
-       case DRM_MODE_SCALE_NO_SCALE:
+       case DRM_MODE_SCALE_CENTER:
                /*
                 * For centered modes, we have to calculate border widths &
                 * heights and modify the values programmed into the CRTC.
@@ -672,9 +662,8 @@ static int intel_lvds_set_property(struct drm_connector *connector,
                                connector->encoder) {
                struct drm_crtc *crtc = connector->encoder->crtc;
                struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
-               if (value == DRM_MODE_SCALE_NON_GPU) {
-                       DRM_DEBUG_KMS(I915_LVDS,
-                                       "non_GPU property is unsupported\n");
+               if (value == DRM_MODE_SCALE_NONE) {
+                       DRM_DEBUG_KMS("no scaling not supported\n");
                        return 0;
                }
                if (lvds_priv->fitting_mode == value) {
@@ -731,8 +720,7 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
 
 static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
 {
-       DRM_DEBUG_KMS(I915_LVDS,
-                     "Skipping LVDS initialization for %s\n", id->ident);
+       DRM_DEBUG_KMS("Skipping LVDS initialization for %s\n", id->ident);
        return 1;
 }
 
@@ -1027,7 +1015,7 @@ out:
        return;
 
 failed:
-       DRM_DEBUG_KMS(I915_LVDS, "No LVDS modes found, disabling.\n");
+       DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
        if (intel_output->ddc_bus)
                intel_i2c_destroy(intel_output->ddc_bus);
        drm_connector_cleanup(connector);
index d3b74ba..0bf28ef 100644 (file)
 #include "intel_sdvo_regs.h"
 
 #undef SDVO_DEBUG
-#define I915_SDVO      "i915_sdvo"
+
+static char *tv_format_names[] = {
+       "NTSC_M"   , "NTSC_J"  , "NTSC_443",
+       "PAL_B"    , "PAL_D"   , "PAL_G"   ,
+       "PAL_H"    , "PAL_I"   , "PAL_M"   ,
+       "PAL_N"    , "PAL_NC"  , "PAL_60"  ,
+       "SECAM_B"  , "SECAM_D" , "SECAM_G" ,
+       "SECAM_K"  , "SECAM_K1", "SECAM_L" ,
+       "SECAM_60"
+};
+
+#define TV_FORMAT_NUM  (sizeof(tv_format_names) / sizeof(*tv_format_names))
+
 struct intel_sdvo_priv {
        u8 slave_addr;
 
@@ -71,6 +83,15 @@ struct intel_sdvo_priv {
         */
        bool is_tv;
 
+       /* This is for current tv format name */
+       char *tv_format_name;
+
+       /* This contains all current supported TV format */
+       char *tv_format_supported[TV_FORMAT_NUM];
+       int   format_supported_num;
+       struct drm_property *tv_format_property;
+       struct drm_property *tv_format_name_property[TV_FORMAT_NUM];
+
        /**
         * This is set if we treat the device as HDMI, instead of DVI.
         */
@@ -97,14 +118,6 @@ struct intel_sdvo_priv {