Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 4 Oct 2012 06:29:23 +0000 (23:29 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 4 Oct 2012 06:29:23 +0000 (23:29 -0700)
Pull drm merge (part 1) from Dave Airlie:
 "So first of all my tree and uapi stuff has a conflict mess, its my
  fault as the nouveau stuff didn't hit -next as were trying to rebase
  regressions out of it before we merged.

  Highlights:
   - SH mobile modesetting driver and associated helpers
   - some DRM core documentation
   - i915 modesetting rework, haswell hdmi, haswell and vlv fixes, write
     combined pte writing, ilk rc6 support,
   - nouveau: major driver rework into a hw core driver, makes features
     like SLI a lot saner to implement,
   - psb: add eDP/DP support for Cedarview
   - radeon: 2 layer page tables, async VM pte updates, better PLL
     selection for > 2 screens, better ACPI interactions

  The rest is general grab bag of fixes.

  So why part 1? well I have the exynos pull req which came in a bit
  late but was waiting for me to do something they shouldn't have and it
  looks fairly safe, and David Howells has some more header cleanups
  he'd like me to pull, that seem like a good idea, but I'd like to get
  this merge out of the way so -next dosen't get blocked."

Tons of conflicts mostly due to silly include line changes, but mostly
mindless.  A few other small semantic conflicts too, noted from Dave's
pre-merged branch.

* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (447 commits)
  drm/nv98/crypt: fix fuc build with latest envyas
  drm/nouveau/devinit: fixup various issues with subdev ctor/init ordering
  drm/nv41/vm: fix and enable use of "real" pciegart
  drm/nv44/vm: fix and enable use of "real" pciegart
  drm/nv04/dmaobj: fixup vm target handling in preparation for nv4x pcie
  drm/nouveau: store supported dma mask in vmmgr
  drm/nvc0/ibus: initial implementation of subdev
  drm/nouveau/therm: add support for fan-control modes
  drm/nouveau/hwmon: rename pwm0* to pmw1* to follow hwmon's rules
  drm/nouveau/therm: calculate the pwm divisor on nv50+
  drm/nouveau/fan: rewrite the fan tachometer driver to get more precision, faster
  drm/nouveau/therm: move thermal-related functions to the therm subdev
  drm/nouveau/bios: parse the pwm divisor from the perf table
  drm/nouveau/therm: use the EXTDEV table to detect i2c monitoring devices
  drm/nouveau/therm: rework thermal table parsing
  drm/nouveau/gpio: expose the PWM/TOGGLE parameter found in the gpio vbios table
  drm/nouveau: fix pm initialization order
  drm/nouveau/bios: check that fixed tvdac gpio data is valid before using it
  drm/nouveau: log channel debug/error messages from client object rather than drm client
  drm/nouveau: have drm debugging macros build on top of core macros
  ...

148 files changed:
1  2 
drivers/gpu/drm/ast/ast_drv.h
drivers/gpu/drm/ast/ast_mode.c
drivers/gpu/drm/cirrus/cirrus_drv.h
drivers/gpu/drm/drm_cache.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_edid_load.c
drivers/gpu/drm/drm_edid_modes.h
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/exynos/exynos_drm_connector.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/gma500/cdv_device.c
drivers/gpu/drm/gma500/cdv_intel_dp.c
drivers/gpu/drm/gma500/gem.c
drivers/gpu/drm/gma500/intel_bios.c
drivers/gpu/drm/gma500/mid_bios.c
drivers/gpu/drm/gma500/psb_device.c
drivers/gpu/drm/gma500/psb_drv.h
drivers/gpu/drm/gma500/psb_intel_sdvo.c
drivers/gpu/drm/i915/dvo.h
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_dmabuf.c
drivers/gpu/drm/i915/i915_gem_evict.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_modes.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/mgag200/mgag200_drv.h
drivers/gpu/drm/mgag200/mgag200_mode.c
drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_calc.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_connector.h
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_dp.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drm.h
drivers/gpu/drm/nouveau/nouveau_encoder.h
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_fbcon.h
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_gem.h
drivers/gpu/drm/nouveau/nouveau_hdmi.c
drivers/gpu/drm/nouveau/nouveau_hw.c
drivers/gpu/drm/nouveau/nouveau_hw.h
drivers/gpu/drm/nouveau/nouveau_ioc32.c
drivers/gpu/drm/nouveau/nouveau_perf.c
drivers/gpu/drm/nouveau/nouveau_pm.c
drivers/gpu/drm/nouveau/nouveau_prime.c
drivers/gpu/drm/nouveau/nouveau_vga.c
drivers/gpu/drm/nouveau/nouveau_volt.c
drivers/gpu/drm/nouveau/nv04_crtc.c
drivers/gpu/drm/nouveau/nv04_cursor.c
drivers/gpu/drm/nouveau/nv04_dac.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv04_display.c
drivers/gpu/drm/nouveau/nv04_pm.c
drivers/gpu/drm/nouveau/nv04_tv.c
drivers/gpu/drm/nouveau/nv17_tv.c
drivers/gpu/drm/nouveau/nv17_tv_modes.c
drivers/gpu/drm/nouveau/nv40_pm.c
drivers/gpu/drm/nouveau/nv50_crtc.c
drivers/gpu/drm/nouveau/nv50_cursor.c
drivers/gpu/drm/nouveau/nv50_dac.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_evo.c
drivers/gpu/drm/nouveau/nv50_pm.c
drivers/gpu/drm/nouveau/nv50_sor.c
drivers/gpu/drm/nouveau/nva3_pm.c
drivers/gpu/drm/nouveau/nvd0_display.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_cs.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r520.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_blit.c
drivers/gpu/drm/radeon/r600_blit_kms.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/r600_hdmi.c
drivers/gpu/drm/radeon/radeon_acpi.c
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_drv.c
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_gem.c
drivers/gpu/drm/radeon/radeon_ioc32.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_legacy_encoders.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_sa.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/savage/savage_bci.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
drivers/gpu/drm/ttm/ttm_tt.c
drivers/gpu/drm/udl/udl_connector.c
drivers/gpu/drm/udl/udl_encoder.c
drivers/gpu/drm/udl/udl_fb.c
drivers/gpu/drm/udl/udl_gem.c
drivers/gpu/drm/udl/udl_main.c
drivers/gpu/drm/udl/udl_modeset.c
drivers/gpu/drm/udl/udl_transfer.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_sarea.h
include/drm/i915_drm.h

  #ifndef __AST_DRV_H__
  #define __AST_DRV_H__
  
 -#include "drm_fb_helper.h"
 +#include <drm/drm_fb_helper.h>
  
 -#include "ttm/ttm_bo_api.h"
 -#include "ttm/ttm_bo_driver.h"
 -#include "ttm/ttm_placement.h"
 -#include "ttm/ttm_memory.h"
 -#include "ttm/ttm_module.h"
 +#include <drm/ttm/ttm_bo_api.h>
 +#include <drm/ttm/ttm_bo_driver.h>
 +#include <drm/ttm/ttm_placement.h>
 +#include <drm/ttm/ttm_memory.h>
 +#include <drm/ttm/ttm_module.h>
  
  #include <linux/i2c.h>
  #include <linux/i2c-algo-bit.h>
@@@ -94,7 -94,6 +94,6 @@@ struct ast_private 
                struct drm_global_reference mem_global_ref;
                struct ttm_bo_global_ref bo_global_ref;
                struct ttm_bo_device bdev;
-               atomic_t validate_sequence;
        } ttm;
  
        struct drm_gem_object *cursor_cache;
@@@ -28,9 -28,9 +28,9 @@@
   * Authors: Dave Airlie <airlied@redhat.com>
   */
  #include <linux/export.h>
 -#include "drmP.h"
 -#include "drm_crtc.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_crtc_helper.h>
  #include "ast_drv.h"
  
  #include "ast_tables.h"
@@@ -582,7 -582,6 +582,6 @@@ static const struct drm_crtc_helper_fun
        .mode_set_base = ast_crtc_mode_set_base,
        .disable = ast_crtc_disable,
        .load_lut = ast_crtc_load_lut,
-       .disable = ast_crtc_disable,
        .prepare = ast_crtc_prepare,
        .commit = ast_crtc_commit,
  
@@@ -737,6 -736,7 +736,7 @@@ static int ast_get_modes(struct drm_con
        if (edid) {
                drm_mode_connector_update_edid_property(&ast_connector->base, edid);
                ret = drm_add_edid_modes(connector, edid);
+               kfree(edid);
                return ret;
        } else
                drm_mode_connector_update_edid_property(&ast_connector->base, NULL);
  
  #include <drm/drm_fb_helper.h>
  
 -#include "ttm/ttm_bo_api.h"
 -#include "ttm/ttm_bo_driver.h"
 -#include "ttm/ttm_placement.h"
 -#include "ttm/ttm_memory.h"
 -#include "ttm/ttm_module.h"
 +#include <drm/ttm/ttm_bo_api.h>
 +#include <drm/ttm/ttm_bo_driver.h>
 +#include <drm/ttm/ttm_placement.h>
 +#include <drm/ttm/ttm_memory.h>
 +#include <drm/ttm/ttm_module.h>
  
  #define DRIVER_AUTHOR         "Matthew Garrett"
  
@@@ -143,7 -143,6 +143,6 @@@ struct cirrus_device 
                struct drm_global_reference mem_global_ref;
                struct ttm_bo_global_ref bo_global_ref;
                struct ttm_bo_device bdev;
-               atomic_t validate_sequence;
        } ttm;
        bool mm_inited;
  };
@@@ -29,7 -29,7 +29,7 @@@
   */
  
  #include <linux/export.h>
 -#include "drmP.h"
 +#include <drm/drmP.h>
  
  #if defined(CONFIG_X86)
  static void
@@@ -37,12 -37,13 +37,13 @@@ drm_clflush_page(struct page *page
  {
        uint8_t *page_virtual;
        unsigned int i;
+       const int size = boot_cpu_data.x86_clflush_size;
  
        if (unlikely(page == NULL))
                return;
  
        page_virtual = kmap_atomic(page);
-       for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)
+       for (i = 0; i < PAGE_SIZE; i += size)
                clflush(page_virtual + i);
        kunmap_atomic(page_virtual);
  }
@@@ -100,6 -101,31 +101,31 @@@ drm_clflush_pages(struct page *pages[]
  EXPORT_SYMBOL(drm_clflush_pages);
  
  void
+ drm_clflush_sg(struct sg_table *st)
+ {
+ #if defined(CONFIG_X86)
+       if (cpu_has_clflush) {
+               struct scatterlist *sg;
+               int i;
+               mb();
+               for_each_sg(st->sgl, sg, st->nents, i)
+                       drm_clflush_page(sg_page(sg));
+               mb();
+               return;
+       }
+       if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0)
+               printk(KERN_ERR "Timed out waiting for cache flush.\n");
+ #else
+       printk(KERN_ERR "Architecture has no drm_cache.c support\n");
+       WARN_ON_ONCE(1);
+ #endif
+ }
+ EXPORT_SYMBOL(drm_clflush_sg);
+ void
  drm_clflush_virt_range(char *addr, unsigned long length)
  {
  #if defined(CONFIG_X86)
  #include <linux/list.h>
  #include <linux/slab.h>
  #include <linux/export.h>
 -#include "drm.h"
 -#include "drmP.h"
 -#include "drm_crtc.h"
 -#include "drm_edid.h"
 -#include "drm_fourcc.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_edid.h>
 +#include <drm/drm_fourcc.h>
  
  /* Avoid boilerplate.  I'm tired of typing. */
  #define DRM_ENUM_NAME_FN(fnname, list)                                \
@@@ -293,6 -294,8 +293,8 @@@ int drm_framebuffer_init(struct drm_dev
  {
        int ret;
  
+       kref_init(&fb->refcount);
        ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
        if (ret)
                return ret;
  }
  EXPORT_SYMBOL(drm_framebuffer_init);
  
+ static void drm_framebuffer_free(struct kref *kref)
+ {
+       struct drm_framebuffer *fb =
+                       container_of(kref, struct drm_framebuffer, refcount);
+       fb->funcs->destroy(fb);
+ }
+ /**
+  * drm_framebuffer_unreference - unref a framebuffer
+  *
+  * LOCKING:
+  * Caller must hold mode config lock.
+  */
+ void drm_framebuffer_unreference(struct drm_framebuffer *fb)
+ {
+       struct drm_device *dev = fb->dev;
+       DRM_DEBUG("FB ID: %d\n", fb->base.id);
+       WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+       kref_put(&fb->refcount, drm_framebuffer_free);
+ }
+ EXPORT_SYMBOL(drm_framebuffer_unreference);
+ /**
+  * drm_framebuffer_reference - incr the fb refcnt
+  */
+ void drm_framebuffer_reference(struct drm_framebuffer *fb)
+ {
+       DRM_DEBUG("FB ID: %d\n", fb->base.id);
+       kref_get(&fb->refcount);
+ }
+ EXPORT_SYMBOL(drm_framebuffer_reference);
  /**
   * drm_framebuffer_cleanup - remove a framebuffer object
   * @fb: framebuffer to remove
  void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
  {
        struct drm_device *dev = fb->dev;
+       /*
+        * This could be moved to drm_framebuffer_remove(), but for
+        * debugging is nice to keep around the list of fb's that are
+        * no longer associated w/ a drm_file but are not unreferenced
+        * yet.  (i915 and omapdrm have debugfs files which will show
+        * this.)
+        */
+       drm_mode_object_put(dev, &fb->base);
+       list_del(&fb->head);
+       dev->mode_config.num_fb--;
+ }
+ EXPORT_SYMBOL(drm_framebuffer_cleanup);
+ /**
+  * drm_framebuffer_remove - remove and unreference a framebuffer object
+  * @fb: framebuffer to remove
+  *
+  * LOCKING:
+  * Caller must hold mode config lock.
+  *
+  * Scans all the CRTCs and planes in @dev's mode_config.  If they're
+  * using @fb, removes it, setting it to NULL.
+  */
+ void drm_framebuffer_remove(struct drm_framebuffer *fb)
+ {
+       struct drm_device *dev = fb->dev;
        struct drm_crtc *crtc;
        struct drm_plane *plane;
        struct drm_mode_set set;
                }
        }
  
-       drm_mode_object_put(dev, &fb->base);
-       list_del(&fb->head);
-       dev->mode_config.num_fb--;
+       list_del(&fb->filp_head);
+       drm_framebuffer_unreference(fb);
  }
- EXPORT_SYMBOL(drm_framebuffer_cleanup);
+ EXPORT_SYMBOL(drm_framebuffer_remove);
  
  /**
   * drm_crtc_init - Initialise a new CRTC object
@@@ -376,6 -437,7 +436,7 @@@ int drm_crtc_init(struct drm_device *de
  
        crtc->dev = dev;
        crtc->funcs = funcs;
+       crtc->invert_dimensions = false;
  
        mutex_lock(&dev->mode_config.mutex);
  
@@@ -1030,11 -1092,7 +1091,7 @@@ void drm_mode_config_cleanup(struct drm
        }
  
        list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
-               fb->funcs->destroy(fb);
-       }
-       list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
-               crtc->funcs->destroy(crtc);
+               drm_framebuffer_remove(fb);
        }
  
        list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
                plane->funcs->destroy(plane);
        }
  
+       list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
+               crtc->funcs->destroy(crtc);
+       }
        idr_remove_all(&dev->mode_config.crtc_idr);
        idr_destroy(&dev->mode_config.crtc_idr);
  }
@@@ -1851,6 -1913,7 +1912,7 @@@ int drm_mode_setcrtc(struct drm_device 
        DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
  
        if (crtc_req->mode_valid) {
+               int hdisplay, vdisplay;
                /* If we have a mode we need a framebuffer. */
                /* If we pass -1, set the mode with the currently bound fb */
                if (crtc_req->fb_id == -1) {
  
                drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
  
-               if (mode->hdisplay > fb->width ||
-                   mode->vdisplay > fb->height ||
-                   crtc_req->x > fb->width - mode->hdisplay ||
-                   crtc_req->y > fb->height - mode->vdisplay) {
-                       DRM_DEBUG_KMS("Invalid CRTC viewport %ux%u+%u+%u for fb size %ux%u.\n",
-                                     mode->hdisplay, mode->vdisplay,
-                                     crtc_req->x, crtc_req->y,
-                                     fb->width, fb->height);
+               hdisplay = mode->hdisplay;
+               vdisplay = mode->vdisplay;
+               if (crtc->invert_dimensions)
+                       swap(hdisplay, vdisplay);
+               if (hdisplay > fb->width ||
+                   vdisplay > fb->height ||
+                   crtc_req->x > fb->width - hdisplay ||
+                   crtc_req->y > fb->height - vdisplay) {
+                       DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
+                                     fb->width, fb->height,
+                                     hdisplay, vdisplay, crtc_req->x, crtc_req->y,
+                                     crtc->invert_dimensions ? " (inverted)" : "");
                        ret = -ENOSPC;
                        goto out;
                }
@@@ -2168,6 -2237,8 +2236,8 @@@ static int format_check(const struct dr
        case DRM_FORMAT_NV21:
        case DRM_FORMAT_NV16:
        case DRM_FORMAT_NV61:
+       case DRM_FORMAT_NV24:
+       case DRM_FORMAT_NV42:
        case DRM_FORMAT_YUV410:
        case DRM_FORMAT_YVU410:
        case DRM_FORMAT_YUV411:
@@@ -2334,11 -2405,7 +2404,7 @@@ int drm_mode_rmfb(struct drm_device *de
                goto out;
        }
  
-       /* TODO release all crtc connected to the framebuffer */
-       /* TODO unhock the destructor from the buffer object */
-       list_del(&fb->filp_head);
-       fb->funcs->destroy(fb);
+       drm_framebuffer_remove(fb);
  
  out:
        mutex_unlock(&dev->mode_config.mutex);
@@@ -2488,8 -2555,7 +2554,7 @@@ void drm_fb_release(struct drm_file *pr
  
        mutex_lock(&dev->mode_config.mutex);
        list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
-               list_del(&fb->filp_head);
-               fb->funcs->destroy(fb);
+               drm_framebuffer_remove(fb);
        }
        mutex_unlock(&dev->mode_config.mutex);
  }
@@@ -3488,6 -3554,7 +3553,7 @@@ int drm_mode_page_flip_ioctl(struct drm
        struct drm_framebuffer *fb;
        struct drm_pending_vblank_event *e = NULL;
        unsigned long flags;
+       int hdisplay, vdisplay;
        int ret = -EINVAL;
  
        if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
                goto out;
        fb = obj_to_fb(obj);
  
-       if (crtc->mode.hdisplay > fb->width ||
-           crtc->mode.vdisplay > fb->height ||
-           crtc->x > fb->width - crtc->mode.hdisplay ||
-           crtc->y > fb->height - crtc->mode.vdisplay) {
-               DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d.\n",
-                             fb->width, fb->height,
-                             crtc->mode.hdisplay, crtc->mode.vdisplay,
-                             crtc->x, crtc->y);
+       hdisplay = crtc->mode.hdisplay;
+       vdisplay = crtc->mode.vdisplay;
+       if (crtc->invert_dimensions)
+               swap(hdisplay, vdisplay);
+       if (hdisplay > fb->width ||
+           vdisplay > fb->height ||
+           crtc->x > fb->width - hdisplay ||
+           crtc->y > fb->height - vdisplay) {
+               DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
+                             fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y,
+                             crtc->invert_dimensions ? " (inverted)" : "");
                ret = -ENOSPC;
                goto out;
        }
@@@ -3717,6 -3789,8 +3788,8 @@@ int drm_format_num_planes(uint32_t form
        case DRM_FORMAT_NV21:
        case DRM_FORMAT_NV16:
        case DRM_FORMAT_NV61:
+       case DRM_FORMAT_NV24:
+       case DRM_FORMAT_NV42:
                return 2;
        default:
                return 1;
@@@ -3750,6 -3824,8 +3823,8 @@@ int drm_format_plane_cpp(uint32_t forma
        case DRM_FORMAT_NV21:
        case DRM_FORMAT_NV16:
        case DRM_FORMAT_NV61:
+       case DRM_FORMAT_NV24:
+       case DRM_FORMAT_NV42:
                return plane ? 2 : 1;
        case DRM_FORMAT_YUV410:
        case DRM_FORMAT_YVU410:
@@@ -49,8 -49,8 +49,8 @@@
  #include <linux/debugfs.h>
  #include <linux/slab.h>
  #include <linux/export.h>
 -#include "drmP.h"
 -#include "drm_core.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_core.h>
  
  
  static int drm_version(struct drm_device *dev, void *data,
@@@ -140,10 -140,10 +140,10 @@@ static struct drm_ioctl_desc drm_ioctls
        DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED),
  
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
  };
  
@@@ -31,8 -31,8 +31,8 @@@
  #include <linux/slab.h>
  #include <linux/i2c.h>
  #include <linux/module.h>
 -#include "drmP.h"
 -#include "drm_edid.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_edid.h>
  #include "drm_edid_modes.h"
  
  #define version_greater(edid, maj, min) \
@@@ -161,7 -161,7 +161,7 @@@ MODULE_PARM_DESC(edid_fixup
   * Sanity check the EDID block (base or extension).  Return 0 if the block
   * doesn't check out, or 1 if it's valid.
   */
- bool drm_edid_block_valid(u8 *raw_edid, int block)
+ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
  {
        int i;
        u8 csum = 0;
        for (i = 0; i < EDID_LENGTH; i++)
                csum += raw_edid[i];
        if (csum) {
-               DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum);
+               if (print_bad_edid) {
+                       DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum);
+               }
  
                /* allow CEA to slide through, switches mangle this */
                if (raw_edid[0] != 0x02)
        return 1;
  
  bad:
-       if (raw_edid) {
+       if (raw_edid && print_bad_edid) {
                printk(KERN_ERR "Raw EDID:\n");
                print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1,
                               raw_edid, EDID_LENGTH, false);
@@@ -234,7 -236,7 +236,7 @@@ bool drm_edid_is_valid(struct edid *edi
                return false;
  
        for (i = 0; i <= edid->extensions; i++)
-               if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i))
+               if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i, true))
                        return false;
  
        return true;
@@@ -257,6 -259,8 +259,8 @@@ drm_do_probe_ddc_edid(struct i2c_adapte
                      int block, int len)
  {
        unsigned char start = block * EDID_LENGTH;
+       unsigned char segment = block >> 1;
+       unsigned char xfers = segment ? 3 : 2;
        int ret, retries = 5;
  
        /* The core i2c driver will automatically retry the transfer if the
        do {
                struct i2c_msg msgs[] = {
                        {
+                               .addr   = DDC_SEGMENT_ADDR,
+                               .flags  = 0,
+                               .len    = 1,
+                               .buf    = &segment,
+                       }, {
                                .addr   = DDC_ADDR,
                                .flags  = 0,
                                .len    = 1,
                                .buf    = buf,
                        }
                };
-               ret = i2c_transfer(adapter, msgs, 2);
+       /*
+        * Avoid sending the segment addr to not upset non-compliant ddc
+        * monitors.
+        */
+               ret = i2c_transfer(adapter, &msgs[3 - xfers], xfers);
                if (ret == -ENXIO) {
                        DRM_DEBUG_KMS("drm: skipping non-existent adapter %s\n",
                                        adapter->name);
                        break;
                }
-       } while (ret != 2 && --retries);
+       } while (ret != xfers && --retries);
  
-       return ret == 2 ? 0 : -1;
+       return ret == xfers ? 0 : -1;
  }
  
  static bool drm_edid_is_zero(u8 *in_edid, int length)
@@@ -306,6 -321,7 +321,7 @@@ drm_do_get_edid(struct drm_connector *c
  {
        int i, j = 0, valid_extensions = 0;
        u8 *block, *new;
+       bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
  
        if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
                return NULL;
        for (i = 0; i < 4; i++) {
                if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH))
                        goto out;
-               if (drm_edid_block_valid(block, 0))
+               if (drm_edid_block_valid(block, 0, print_bad_edid))
                        break;
                if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) {
                        connector->null_edid_counter++;
                                  block + (valid_extensions + 1) * EDID_LENGTH,
                                  j, EDID_LENGTH))
                                goto out;
-                       if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j)) {
+                       if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j, print_bad_edid)) {
                                valid_extensions++;
                                break;
                        }
        return block;
  
  carp:
-       dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n",
-                drm_get_connector_name(connector), j);
+       if (print_bad_edid) {
+               dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n",
+                        drm_get_connector_name(connector), j);
+       }
+       connector->bad_edid_counter++;
  
  out:
        kfree(block);
@@@ -402,10 -421,7 +421,7 @@@ struct edid *drm_get_edid(struct drm_co
        if (drm_probe_ddc(adapter))
                edid = (struct edid *)drm_do_get_edid(connector, adapter);
  
-       connector->display_info.raw_edid = (char *)edid;
        return edid;
  }
  EXPORT_SYMBOL(drm_get_edid);
  
@@@ -1523,16 -1539,57 +1539,57 @@@ do_cea_modes (struct drm_connector *con
  }
  
  static int
+ cea_db_payload_len(const u8 *db)
+ {
+       return db[0] & 0x1f;
+ }
+ static int
+ cea_db_tag(const u8 *db)
+ {
+       return db[0] >> 5;
+ }
+ static int
+ cea_revision(const u8 *cea)
+ {
+       return cea[1];
+ }
+ static int
+ cea_db_offsets(const u8 *cea, int *start, int *end)
+ {
+       /* Data block offset in CEA extension block */
+       *start = 4;
+       *end = cea[2];
+       if (*end == 0)
+               *end = 127;
+       if (*end < 4 || *end > 127)
+               return -ERANGE;
+       return 0;
+ }
+ #define for_each_cea_db(cea, i, start, end) \
+       for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1)
+ static int
  add_cea_modes(struct drm_connector *connector, struct edid *edid)
  {
        u8 * cea = drm_find_cea_extension(edid);
        u8 * db, dbl;
        int modes = 0;
  
-       if (cea && cea[1] >= 3) {
-               for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) {
-                       dbl = db[0] & 0x1f;
-                       if (((db[0] & 0xe0) >> 5) == VIDEO_BLOCK)
+       if (cea && cea_revision(cea) >= 3) {
+               int i, start, end;
+               if (cea_db_offsets(cea, &start, &end))
+                       return 0;
+               for_each_cea_db(cea, i, start, end) {
+                       db = &cea[i];
+                       dbl = cea_db_payload_len(db);
+                       if (cea_db_tag(db) == VIDEO_BLOCK)
                                modes += do_cea_modes (connector, db+1, dbl);
                }
        }
  }
  
  static void
- parse_hdmi_vsdb(struct drm_connector *connector, uint8_t *db)
+ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
  {
-       connector->eld[5] |= (db[6] >> 7) << 1;  /* Supports_AI */
-       connector->dvi_dual = db[6] & 1;
-       connector->max_tmds_clock = db[7] * 5;
+       u8 len = cea_db_payload_len(db);
  
-       connector->latency_present[0] = db[8] >> 7;
-       connector->latency_present[1] = (db[8] >> 6) & 1;
-       connector->video_latency[0] = db[9];
-       connector->audio_latency[0] = db[10];
-       connector->video_latency[1] = db[11];
-       connector->audio_latency[1] = db[12];
+       if (len >= 6) {
+               connector->eld[5] |= (db[6] >> 7) << 1;  /* Supports_AI */
+               connector->dvi_dual = db[6] & 1;
+       }
+       if (len >= 7)
+               connector->max_tmds_clock = db[7] * 5;
+       if (len >= 8) {
+               connector->latency_present[0] = db[8] >> 7;
+               connector->latency_present[1] = (db[8] >> 6) & 1;
+       }
+       if (len >= 9)
+               connector->video_latency[0] = db[9];
+       if (len >= 10)
+               connector->audio_latency[0] = db[10];
+       if (len >= 11)
+               connector->video_latency[1] = db[11];
+       if (len >= 12)
+               connector->audio_latency[1] = db[12];
  
        DRM_LOG_KMS("HDMI: DVI dual %d, "
                    "max TMDS clock %d, "
@@@ -1577,6 -1643,21 +1643,21 @@@ monitor_name(struct detailed_timing *t
                *(u8 **)data = t->data.other_data.data.str.str;
  }
  
+ static bool cea_db_is_hdmi_vsdb(const u8 *db)
+ {
+       int hdmi_id;
+       if (cea_db_tag(db) != VENDOR_BLOCK)
+               return false;
+       if (cea_db_payload_len(db) < 5)
+               return false;
+       hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16);
+       return hdmi_id == HDMI_IDENTIFIER;
+ }
  /**
   * drm_edid_to_eld - build ELD from EDID
   * @connector: connector corresponding to the HDMI/DP sink
@@@ -1623,29 -1704,40 +1704,40 @@@ void drm_edid_to_eld(struct drm_connect
        eld[18] = edid->prod_code[0];
        eld[19] = edid->prod_code[1];
  
-       if (cea[1] >= 3)
-               for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) {
-                       dbl = db[0] & 0x1f;
-                       
-                       switch ((db[0] & 0xe0) >> 5) {
+       if (cea_revision(cea) >= 3) {
+               int i, start, end;
+               if (cea_db_offsets(cea, &start, &end)) {
+                       start = 0;
+                       end = 0;
+               }
+               for_each_cea_db(cea, i, start, end) {
+                       db = &cea[i];
+                       dbl = cea_db_payload_len(db);
+                       switch (cea_db_tag(db)) {
                        case AUDIO_BLOCK:
                                /* Audio Data Block, contains SADs */
                                sad_count = dbl / 3;
-                               memcpy(eld + 20 + mnl, &db[1], dbl);
+                               if (dbl >= 1)
+                                       memcpy(eld + 20 + mnl, &db[1], dbl);
                                break;
                        case SPEAKER_BLOCK:
-                                 /* Speaker Allocation Data Block */
-                               eld[7] = db[1];
+                               /* Speaker Allocation Data Block */
+                               if (dbl >= 1)
+                                       eld[7] = db[1];
                                break;
                        case VENDOR_BLOCK:
                                /* HDMI Vendor-Specific Data Block */
-                               if (db[1] == 0x03 && db[2] == 0x0c && db[3] == 0)
+                               if (cea_db_is_hdmi_vsdb(db))
                                        parse_hdmi_vsdb(connector, db);
                                break;
                        default:
                                break;
                        }
                }
+       }
        eld[5] |= sad_count << 4;
        eld[2] = (20 + mnl + sad_count * 3 + 3) / 4;
  
@@@ -1723,38 -1815,26 +1815,26 @@@ EXPORT_SYMBOL(drm_select_eld)
  bool drm_detect_hdmi_monitor(struct edid *edid)
  {
        u8 *edid_ext;
-       int i, hdmi_id;
+       int i;
        int start_offset, end_offset;
-       bool is_hdmi = false;
  
        edid_ext = drm_find_cea_extension(edid);
        if (!edid_ext)
-               goto end;
+               return false;
  
-       /* Data block offset in CEA extension block */
-       start_offset = 4;
-       end_offset = edid_ext[2];
+       if (cea_db_offsets(edid_ext, &start_offset, &end_offset))
+               return false;
  
        /*
         * Because HDMI identifier is in Vendor Specific Block,
         * search it from all data blocks of CEA extension.
         */
-       for (i = start_offset; i < end_offset;
-               /* Increased by data block len */
-               i += ((edid_ext[i] & 0x1f) + 1)) {
-               /* Find vendor specific block */
-               if ((edid_ext[i] >> 5) == VENDOR_BLOCK) {
-                       hdmi_id = edid_ext[i + 1] | (edid_ext[i + 2] << 8) |
-                                 edid_ext[i + 3] << 16;
-                       /* Find HDMI identifier */
-                       if (hdmi_id == HDMI_IDENTIFIER)
-                               is_hdmi = true;
-                       break;
-               }
+       for_each_cea_db(edid_ext, i, start_offset, end_offset) {
+               if (cea_db_is_hdmi_vsdb(&edid_ext[i]))
+                       return true;
        }
  
- end:
-       return is_hdmi;
+       return false;
  }
  EXPORT_SYMBOL(drm_detect_hdmi_monitor);
  
@@@ -1786,15 -1866,13 +1866,13 @@@ bool drm_detect_monitor_audio(struct ed
                goto end;
        }
  
-       /* Data block offset in CEA extension block */
-       start_offset = 4;
-       end_offset = edid_ext[2];
+       if (cea_db_offsets(edid_ext, &start_offset, &end_offset))
+               goto end;
  
-       for (i = start_offset; i < end_offset;
-                       i += ((edid_ext[i] & 0x1f) + 1)) {
-               if ((edid_ext[i] >> 5) == AUDIO_BLOCK) {
+       for_each_cea_db(edid_ext, i, start_offset, end_offset) {
+               if (cea_db_tag(&edid_ext[i]) == AUDIO_BLOCK) {
                        has_audio = true;
-                       for (j = 1; j < (edid_ext[i] & 0x1f); j += 3)
+                       for (j = 1; j < cea_db_payload_len(&edid_ext[i]) + 1; j += 3)
                                DRM_DEBUG_KMS("CEA audio format %d\n",
                                              (edid_ext[i + j] >> 3) & 0xf);
                        goto end;
  
  #include <linux/module.h>
  #include <linux/firmware.h>
 -#include "drmP.h"
 -#include "drm_crtc.h"
 -#include "drm_crtc_helper.h"
 -#include "drm_edid.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/drm_edid.h>
  
  static char edid_firmware[PATH_MAX];
  module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
@@@ -114,8 -114,8 +114,8 @@@ static u8 generic_edid[GENERIC_EDIDS][1
        },
  };
  
- static int edid_load(struct drm_connector *connector, char *name,
-                    char *connector_name)
+ static u8 *edid_load(struct drm_connector *connector, char *name,
+                       char *connector_name)
  {
        const struct firmware *fw;
        struct platform_device *pdev;
        int fwsize, expected;
        int builtin = 0, err = 0;
        int i, valid_extensions = 0;
+       bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
  
        pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
        if (IS_ERR(pdev)) {
        }
        memcpy(edid, fwdata, fwsize);
  
-       if (!drm_edid_block_valid(edid, 0)) {
+       if (!drm_edid_block_valid(edid, 0, print_bad_edid)) {
+               connector->bad_edid_counter++;
                DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
                    name);
                kfree(edid);
                if (i != valid_extensions + 1)
                        memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
                            edid + i * EDID_LENGTH, EDID_LENGTH);
-               if (drm_edid_block_valid(edid + i * EDID_LENGTH, i))
+               if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, print_bad_edid))
                        valid_extensions++;
        }
  
                edid = new_edid;
        }
  
-       connector->display_info.raw_edid = edid;
        DRM_INFO("Got %s EDID base block and %d extension%s from "
            "\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
            "external", valid_extensions, valid_extensions == 1 ? "" : "s",
@@@ -215,7 -216,10 +216,10 @@@ relfw_out
        release_firmware(fw);
  
  out:
-       return err;
+       if (err)
+               return ERR_PTR(err);
+       return edid;
  }
  
  int drm_load_edid_firmware(struct drm_connector *connector)
        char *connector_name = drm_get_connector_name(connector);
        char *edidname = edid_firmware, *last, *colon;
        int ret;
+       struct edid *edid;
  
        if (*edidname == '\0')
                return 0;
        if (*last == '\n')
                *last = '\0';
  
-       ret = edid_load(connector, edidname, connector_name);
-       if (ret)
+       edid = (struct edid *) edid_load(connector, edidname, connector_name);
+       if (IS_ERR_OR_NULL(edid))
                return 0;
  
-       drm_mode_connector_update_edid_property(connector,
-           (struct edid *) connector->display_info.raw_edid);
+       drm_mode_connector_update_edid_property(connector, edid);
+       ret = drm_add_edid_modes(connector, edid);
+       kfree(edid);
  
-       return drm_add_edid_modes(connector, (struct edid *)
-           connector->display_info.raw_edid);
+       return ret;
  }
@@@ -24,8 -24,8 +24,8 @@@
   */
  
  #include <linux/kernel.h>
 -#include "drmP.h"
 -#include "drm_edid.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_edid.h>
  
  /*
   * Autogenerated from the DMT spec.
@@@ -89,7 -89,7 +89,7 @@@ static const struct drm_display_mode dr
                   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,
+       { DRM_MODE("1024x768i", 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) },
@@@ -395,7 -395,7 +395,7 @@@ static const struct drm_display_mode ed
        { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
                   1184, 1344, 0,  768, 771, 777, 806, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
+       { DRM_MODE("1024x768i", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
                   1208, 1264, 0, 768, 768, 776, 817, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
        { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
@@@ -506,17 -506,17 +506,17 @@@ static const struct drm_display_mode ed
                   1430, 1650, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
        /* 5 - 1920x1080i@60Hz */
-       { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
+       { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
        /* 6 - 1440x480i@60Hz */
-       { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
+       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
        /* 7 - 1440x480i@60Hz */
-       { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
+       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_DBLCLK) },
        /* 10 - 2880x480i@60Hz */
-       { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
+       { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
                   3204, 3432, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
        /* 11 - 2880x480i@60Hz */
-       { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
+       { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
                   3204, 3432, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
                   1760, 1980, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
        /* 20 - 1920x1080i@50Hz */
-       { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
+       { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
        /* 21 - 1440x576i@50Hz */
-       { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
+       { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
        /* 22 - 1440x576i@50Hz */
-       { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
+       { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_DBLCLK) },
        /* 25 - 2880x576i@50Hz */
-       { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
+       { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
                   3180, 3456, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
        /* 26 - 2880x576i@50Hz */
-       { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
+       { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
                   3180, 3456, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
                   3184, 3456, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 39 - 1920x1080i@50Hz */
-       { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952,
+       { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952,
                   2120, 2304, 0, 1080, 1126, 1136, 1250, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
        /* 40 - 1920x1080i@100Hz */
-       { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
+       { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_DBLCLK) },
        /* 46 - 1920x1080i@120Hz */
-       { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
+       { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 50 - 1440x480i@120Hz */
-       { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
+       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
        /* 51 - 1440x480i@120Hz */
-       { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
+       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 54 - 1440x576i@200Hz */
-       { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
+       { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
        /* 55 - 1440x576i@200Hz */
-       { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
+       { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 58 - 1440x480i@240 */
-       { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
+       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
        /* 59 - 1440x480i@240 */
-       { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
+       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
  #include <linux/slab.h>
  #include <linux/fb.h>
  #include <linux/module.h>
 -#include "drmP.h"
 -#include "drm_crtc.h"
 -#include "drm_fb_helper.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_fb_helper.h>
 +#include <drm/drm_crtc_helper.h>
  
  MODULE_AUTHOR("David Airlie, Jesse Barnes");
  MODULE_DESCRIPTION("DRM KMS helper");
@@@ -236,7 -236,7 +236,7 @@@ bool drm_fb_helper_restore_fbdev_mode(s
  }
  EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode);
  
- bool drm_fb_helper_force_kernel_mode(void)
static bool drm_fb_helper_force_kernel_mode(void)
  {
        bool ret, error = false;
        struct drm_fb_helper *helper;
@@@ -330,7 -330,7 +330,7 @@@ static void drm_fb_helper_dpms(struct f
                /* Walk the connectors & encoders on this fb turning them on/off */
                for (j = 0; j < fb_helper->connector_count; j++) {
                        connector = fb_helper->connector_info[j]->connector;
-                       drm_helper_connector_dpms(connector, dpms_mode);
+                       connector->funcs->dpms(connector, dpms_mode);
                        drm_connector_property_set_value(connector,
                                dev->mode_config.dpms_property, dpms_mode);
                }
@@@ -1230,7 -1230,6 +1230,6 @@@ static void drm_setup_crtcs(struct drm_
        struct drm_device *dev = fb_helper->dev;
        struct drm_fb_helper_crtc **crtcs;
        struct drm_display_mode **modes;
-       struct drm_encoder *encoder;
        struct drm_mode_set *modeset;
        bool *enabled;
        int width, height;
        width = dev->mode_config.max_width;
        height = dev->mode_config.max_height;
  
-       /* clean out all the encoder/crtc combos */
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               encoder->crtc = NULL;
-       }
        crtcs = kcalloc(dev->mode_config.num_connector,
                        sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
        modes = kcalloc(dev->mode_config.num_connector,
@@@ -33,7 -33,7 +33,7 @@@
   * OTHER DEALINGS IN THE SOFTWARE.
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "drm_trace.h"
  
  #include <linux/interrupt.h>  /* For task queue support */
@@@ -1236,7 -1236,7 +1236,7 @@@ done
        return ret;
  }
  
- void drm_handle_vblank_events(struct drm_device *dev, int crtc)
static void drm_handle_vblank_events(struct drm_device *dev, int crtc)
  {
        struct drm_pending_vblank_event *e, *t;
        struct timeval now;
diff --combined drivers/gpu/drm/drm_vm.c
@@@ -33,7 -33,7 +33,7 @@@
   * OTHER DEALINGS IN THE SOFTWARE.
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include <linux/export.h>
  #if defined(__ia64__)
  #include <linux/efi.h>
@@@ -62,7 -62,7 +62,7 @@@ static pgprot_t drm_io_prot(uint32_t ma
                tmp = pgprot_writecombine(tmp);
        else
                tmp = pgprot_noncached(tmp);
- #elif defined(__sparc__) || defined(__arm__)
+ #elif defined(__sparc__) || defined(__arm__) || defined(__mips__)
        tmp = pgprot_noncached(tmp);
  #endif
        return tmp;
@@@ -619,20 -619,11 +619,11 @@@ int drm_mmap_locked(struct file *filp, 
                offset = drm_core_get_reg_ofs(dev);
                vma->vm_flags |= VM_IO; /* not in core dump */
                vma->vm_page_prot = drm_io_prot(map->type, vma);
- #if !defined(__arm__)
                if (io_remap_pfn_range(vma, vma->vm_start,
                                       (map->offset + offset) >> PAGE_SHIFT,
                                       vma->vm_end - vma->vm_start,
                                       vma->vm_page_prot))
                        return -EAGAIN;
- #else
-               if (remap_pfn_range(vma, vma->vm_start,
-                                       (map->offset + offset) >> PAGE_SHIFT,
-                                       vma->vm_end - vma->vm_start,
-                                       vma->vm_page_prot))
-                       return -EAGAIN;
- #endif
                DRM_DEBUG("   Type = %d; start = 0x%lx, end = 0x%lx,"
                          " offset = 0x%llx\n",
                          map->type,
@@@ -25,8 -25,8 +25,8 @@@
   * OTHER DEALINGS IN THE SOFTWARE.
   */
  
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
  
  #include <drm/exynos_drm.h>
  #include "exynos_drm_drv.h"
@@@ -147,9 -147,7 +147,7 @@@ static int exynos_drm_connector_get_mod
  
                drm_mode_connector_update_edid_property(connector, edid);
                count = drm_add_edid_modes(connector, edid);
-               kfree(connector->display_info.raw_edid);
-               connector->display_info.raw_edid = edid;
+               kfree(edid);
        } else {
                struct drm_display_mode *mode = drm_mode_create(connector->dev);
                struct exynos_drm_panel_info *panel;
   * OTHER DEALINGS IN THE SOFTWARE.
   */
  
 -#include "drmP.h"
 -#include "drm_crtc.h"
 -#include "drm_fb_helper.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_fb_helper.h>
 +#include <drm/drm_crtc_helper.h>
  
  #include "exynos_drm_drv.h"
  #include "exynos_drm_fb.h"
@@@ -266,8 -266,8 +266,8 @@@ static void exynos_drm_fbdev_destroy(st
        /* release drm framebuffer and real buffer */
        if (fb_helper->fb && fb_helper->fb->funcs) {
                fb = fb_helper->fb;
-               if (fb && fb->funcs->destroy)
-                       fb->funcs->destroy(fb);
+               if (fb)
+                       drm_framebuffer_remove(fb);
        }
  
        /* release linux framebuffer */
@@@ -10,7 -10,7 +10,7 @@@
   * option) any later version.
   *
   */
 -#include "drmP.h"
 +#include <drm/drmP.h>
  
  #include <linux/kernel.h>
  #include <linux/module.h>
@@@ -18,8 -18,8 +18,8 @@@
  
  #include <drm/exynos_drm.h>
  
 -#include "drm_edid.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drm_edid.h>
 +#include <drm/drm_crtc_helper.h>
  
  #include "exynos_drm_drv.h"
  #include "exynos_drm_crtc.h"
@@@ -102,7 -102,6 +102,6 @@@ static int vidi_get_edid(struct device 
                                u8 *edid, int len)
  {
        struct vidi_context *ctx = get_vidi_context(dev);
-       struct edid *raw_edid;
  
        DRM_DEBUG_KMS("%s\n", __FILE__);
  
                return -EFAULT;
        }
  
-       raw_edid = kzalloc(len, GFP_KERNEL);
-       if (!raw_edid) {
-               DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
-               return -ENOMEM;
-       }
-       memcpy(raw_edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
-                                               * EDID_LENGTH, len));
-       /* attach the edid data to connector. */
-       connector->display_info.raw_edid = (char *)raw_edid;
        memcpy(edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
                                        * EDID_LENGTH, len));
  
@@@ -20,7 -20,7 +20,7 @@@
  #include <linux/backlight.h>
  #include <drm/drmP.h>
  #include <drm/drm.h>
 -#include "gma_drm.h"
 +#include <drm/gma_drm.h>
  #include "psb_drv.h"
  #include "psb_reg.h"
  #include "psb_intel_reg.h"
@@@ -58,10 -58,17 +58,17 @@@ static int cdv_output_init(struct drm_d
        cdv_intel_lvds_init(dev, &dev_priv->mode_dev);
  
        /* These bits indicate HDMI not SDVO on CDV */
-       if (REG_READ(SDVOB) & SDVO_DETECTED)
+       if (REG_READ(SDVOB) & SDVO_DETECTED) {
                cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOB);
-       if (REG_READ(SDVOC) & SDVO_DETECTED)
+               if (REG_READ(DP_B) & DP_DETECTED)
+                       cdv_intel_dp_init(dev, &dev_priv->mode_dev, DP_B);
+       }
+       if (REG_READ(SDVOC) & SDVO_DETECTED) {
                cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOC);
+               if (REG_READ(DP_C) & DP_DETECTED)
+                       cdv_intel_dp_init(dev, &dev_priv->mode_dev, DP_C);
+       }
        return 0;
  }
  
@@@ -163,6 -170,7 +170,7 @@@ static int cdv_backlight_init(struct dr
                        cdv_get_brightness(cdv_backlight_device);
        backlight_update_status(cdv_backlight_device);
        dev_priv->backlight_device = cdv_backlight_device;
+       dev_priv->backlight_enabled = true;
        return 0;
  }
  
@@@ -449,6 -457,7 +457,7 @@@ static void cdv_get_core_freq(struct dr
        case 6:
        case 7:
                dev_priv->core_freq = 266;
+               break;
        default:
                dev_priv->core_freq = 0;
        }
@@@ -488,6 -497,65 +497,65 @@@ static void cdv_hotplug_enable(struct d
        }       
  }
  
+ static const char *force_audio_names[] = {
+       "off",
+       "auto",
+       "on",
+ };
+ void cdv_intel_attach_force_audio_property(struct drm_connector *connector)
+ {
+       struct drm_device *dev = connector->dev;
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct drm_property *prop;
+       int i;
+       prop = dev_priv->force_audio_property;
+       if (prop == NULL) {
+               prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
+                                          "audio",
+                                          ARRAY_SIZE(force_audio_names));
+               if (prop == NULL)
+                       return;
+               for (i = 0; i < ARRAY_SIZE(force_audio_names); i++)
+                       drm_property_add_enum(prop, i, i-1, force_audio_names[i]);
+               dev_priv->force_audio_property = prop;
+       }
+       drm_connector_attach_property(connector, prop, 0);
+ }
+ static const char *broadcast_rgb_names[] = {
+       "Full",
+       "Limited 16:235",
+ };
+ void cdv_intel_attach_broadcast_rgb_property(struct drm_connector *connector)
+ {
+       struct drm_device *dev = connector->dev;
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct drm_property *prop;
+       int i;
+       prop = dev_priv->broadcast_rgb_property;
+       if (prop == NULL) {
+               prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
+                                          "Broadcast RGB",
+                                          ARRAY_SIZE(broadcast_rgb_names));
+               if (prop == NULL)
+                       return;
+               for (i = 0; i < ARRAY_SIZE(broadcast_rgb_names); i++)
+                       drm_property_add_enum(prop, i, i, broadcast_rgb_names[i]);
+               dev_priv->broadcast_rgb_property = prop;
+       }
+       drm_connector_attach_property(connector, prop, 0);
+ }
  /* Cedarview */
  static const struct psb_offset cdv_regmap[2] = {
        {
index 0000000,c9abc06..e3a3978
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1951 +1,1950 @@@
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 -#include "drm_crtc_helper.h"
+ /*
+  * Copyright Â© 2012 Intel Corporation
+  *
+  * 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+  * IN THE SOFTWARE.
+  *
+  * Authors:
+  *    Keith Packard <keithp@keithp.com>
+  *
+  */
+ #include <linux/i2c.h>
+ #include <linux/slab.h>
 -#include "drm_dp_helper.h"
++#include <drm/drmP.h>
++#include <drm/drm_crtc.h>
++#include <drm/drm_crtc_helper.h>
+ #include "psb_drv.h"
+ #include "psb_intel_drv.h"
+ #include "psb_intel_reg.h"
++#include <drm/drm_dp_helper.h>
+ #define _wait_for(COND, MS, W) ({ \
+         unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);       \
+         int ret__ = 0;                                                  \
+         while (! (COND)) {                                              \
+                 if (time_after(jiffies, timeout__)) {                   \
+                         ret__ = -ETIMEDOUT;                             \
+                         break;                                          \
+                 }                                                       \
+                 if (W && !in_dbg_master()) msleep(W);                   \
+         }                                                               \
+         ret__;                                                          \
+ })      
+ #define wait_for(COND, MS) _wait_for(COND, MS, 1)
+ #define DP_LINK_STATUS_SIZE   6
+ #define DP_LINK_CHECK_TIMEOUT (10 * 1000)
+ #define DP_LINK_CONFIGURATION_SIZE    9
+ #define CDV_FAST_LINK_TRAIN   1
+ struct cdv_intel_dp {
+       uint32_t output_reg;
+       uint32_t DP;
+       uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
+       bool has_audio;
+       int force_audio;
+       uint32_t color_range;
+       uint8_t link_bw;
+       uint8_t lane_count;
+       uint8_t dpcd[4];
+       struct psb_intel_encoder *encoder;
+       struct i2c_adapter adapter;
+       struct i2c_algo_dp_aux_data algo;
+       uint8_t train_set[4];
+       uint8_t link_status[DP_LINK_STATUS_SIZE];
+       int panel_power_up_delay;
+       int panel_power_down_delay;
+       int panel_power_cycle_delay;
+       int backlight_on_delay;
+       int backlight_off_delay;
+       struct drm_display_mode *panel_fixed_mode;  /* for eDP */
+       bool panel_on;
+ };
+ struct ddi_regoff {
+       uint32_t        PreEmph1;
+       uint32_t        PreEmph2;
+       uint32_t        VSwing1;
+       uint32_t        VSwing2;
+       uint32_t        VSwing3;
+       uint32_t        VSwing4;
+       uint32_t        VSwing5;
+ };
+ static struct ddi_regoff ddi_DP_train_table[] = {
+       {.PreEmph1 = 0x812c, .PreEmph2 = 0x8124, .VSwing1 = 0x8154,
+       .VSwing2 = 0x8148, .VSwing3 = 0x814C, .VSwing4 = 0x8150,
+       .VSwing5 = 0x8158,},
+       {.PreEmph1 = 0x822c, .PreEmph2 = 0x8224, .VSwing1 = 0x8254,
+       .VSwing2 = 0x8248, .VSwing3 = 0x824C, .VSwing4 = 0x8250,
+       .VSwing5 = 0x8258,},
+ };
+ static uint32_t dp_vswing_premph_table[] = {
+         0x55338954,   0x4000,
+         0x554d8954,   0x2000,
+         0x55668954,   0,
+         0x559ac0d4,   0x6000,
+ };
+ /**
+  * is_edp - is the given port attached to an eDP panel (either CPU or PCH)
+  * @intel_dp: DP struct
+  *
+  * If a CPU or PCH DP output is attached to an eDP panel, this function
+  * will return true, and false otherwise.
+  */
+ static bool is_edp(struct psb_intel_encoder *encoder)
+ {
+       return encoder->type == INTEL_OUTPUT_EDP;
+ }
+ static void cdv_intel_dp_start_link_train(struct psb_intel_encoder *encoder);
+ static void cdv_intel_dp_complete_link_train(struct psb_intel_encoder *encoder);
+ static void cdv_intel_dp_link_down(struct psb_intel_encoder *encoder);
+ static int
+ cdv_intel_dp_max_lane_count(struct psb_intel_encoder *encoder)
+ {
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       int max_lane_count = 4;
+       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) {
+               max_lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & 0x1f;
+               switch (max_lane_count) {
+               case 1: case 2: case 4:
+                       break;
+               default:
+                       max_lane_count = 4;
+               }
+       }
+       return max_lane_count;
+ }
+ static int
+ cdv_intel_dp_max_link_bw(struct psb_intel_encoder *encoder)
+ {
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
+       switch (max_link_bw) {
+       case DP_LINK_BW_1_62:
+       case DP_LINK_BW_2_7:
+               break;
+       default:
+               max_link_bw = DP_LINK_BW_1_62;
+               break;
+       }
+       return max_link_bw;
+ }
+ static int
+ cdv_intel_dp_link_clock(uint8_t link_bw)
+ {
+       if (link_bw == DP_LINK_BW_2_7)
+               return 270000;
+       else
+               return 162000;
+ }
+ static int
+ cdv_intel_dp_link_required(int pixel_clock, int bpp)
+ {
+       return (pixel_clock * bpp + 7) / 8;
+ }
+ static int
+ cdv_intel_dp_max_data_rate(int max_link_clock, int max_lanes)
+ {
+       return (max_link_clock * max_lanes * 19) / 20;
+ }
+ static void cdv_intel_edp_panel_vdd_on(struct psb_intel_encoder *intel_encoder)
+ {
+       struct drm_device *dev = intel_encoder->base.dev;
+       struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
+       u32 pp;
+       if (intel_dp->panel_on) {
+               DRM_DEBUG_KMS("Skip VDD on because of panel on\n");
+               return;
+       }       
+       DRM_DEBUG_KMS("\n");
+       pp = REG_READ(PP_CONTROL);
+       pp |= EDP_FORCE_VDD;
+       REG_WRITE(PP_CONTROL, pp);
+       REG_READ(PP_CONTROL);
+       msleep(intel_dp->panel_power_up_delay);
+ }
+ static void cdv_intel_edp_panel_vdd_off(struct psb_intel_encoder *intel_encoder)
+ {
+       struct drm_device *dev = intel_encoder->base.dev;
+       u32 pp;
+       DRM_DEBUG_KMS("\n");
+       pp = REG_READ(PP_CONTROL);
+       pp &= ~EDP_FORCE_VDD;
+       REG_WRITE(PP_CONTROL, pp);
+       REG_READ(PP_CONTROL);
+ }
+ /* Returns true if the panel was already on when called */
+ static bool cdv_intel_edp_panel_on(struct psb_intel_encoder *intel_encoder)
+ {
+       struct drm_device *dev = intel_encoder->base.dev;
+       struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
+       u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_NONE;
+       if (intel_dp->panel_on)
+               return true;
+       DRM_DEBUG_KMS("\n");
+       pp = REG_READ(PP_CONTROL);
+       pp &= ~PANEL_UNLOCK_MASK;
+       pp |= (PANEL_UNLOCK_REGS | POWER_TARGET_ON);
+       REG_WRITE(PP_CONTROL, pp);
+       REG_READ(PP_CONTROL);
+       if (wait_for(((REG_READ(PP_STATUS) & idle_on_mask) == idle_on_mask), 1000)) {
+               DRM_DEBUG_KMS("Error in Powering up eDP panel, status %x\n", REG_READ(PP_STATUS));
+               intel_dp->panel_on = false;
+       } else
+               intel_dp->panel_on = true;      
+       msleep(intel_dp->panel_power_up_delay);
+       return false;
+ }
+ static void cdv_intel_edp_panel_off (struct psb_intel_encoder *intel_encoder)
+ {
+       struct drm_device *dev = intel_encoder->base.dev;
+       u32 pp, idle_off_mask = PP_ON ;
+       struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
+       DRM_DEBUG_KMS("\n");
+       pp = REG_READ(PP_CONTROL);
+       if ((pp & POWER_TARGET_ON) == 0) 
+               return;
+       intel_dp->panel_on = false;
+       pp &= ~PANEL_UNLOCK_MASK;
+       /* ILK workaround: disable reset around power sequence */
+       pp &= ~POWER_TARGET_ON;
+       pp &= ~EDP_FORCE_VDD;
+       pp &= ~EDP_BLC_ENABLE;
+       REG_WRITE(PP_CONTROL, pp);
+       REG_READ(PP_CONTROL);
+       DRM_DEBUG_KMS("PP_STATUS %x\n", REG_READ(PP_STATUS));
+       if (wait_for((REG_READ(PP_STATUS) & idle_off_mask) == 0, 1000)) {
+               DRM_DEBUG_KMS("Error in turning off Panel\n");  
+       }
+       msleep(intel_dp->panel_power_cycle_delay);
+       DRM_DEBUG_KMS("Over\n");
+ }
+ static void cdv_intel_edp_backlight_on (struct psb_intel_encoder *intel_encoder)
+ {
+       struct drm_device *dev = intel_encoder->base.dev;
+       u32 pp;
+       DRM_DEBUG_KMS("\n");
+       /*
+        * If we enable the backlight right away following a panel power
+        * on, we may see slight flicker as the panel syncs with the eDP
+        * link.  So delay a bit to make sure the image is solid before
+        * allowing it to appear.
+        */
+       msleep(300);
+       pp = REG_READ(PP_CONTROL);
+       pp |= EDP_BLC_ENABLE;
+       REG_WRITE(PP_CONTROL, pp);
+       gma_backlight_enable(dev);
+ }
+ static void cdv_intel_edp_backlight_off (struct psb_intel_encoder *intel_encoder)
+ {
+       struct drm_device *dev = intel_encoder->base.dev;
+       struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
+       u32 pp;
+       DRM_DEBUG_KMS("\n");
+       gma_backlight_disable(dev);
+       msleep(10);
+       pp = REG_READ(PP_CONTROL);
+       pp &= ~EDP_BLC_ENABLE;
+       REG_WRITE(PP_CONTROL, pp);
+       msleep(intel_dp->backlight_off_delay);
+ }
+ static int
+ cdv_intel_dp_mode_valid(struct drm_connector *connector,
+                   struct drm_display_mode *mode)
+ {
+       struct psb_intel_encoder *encoder = psb_intel_attached_encoder(connector);
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       int max_link_clock = cdv_intel_dp_link_clock(cdv_intel_dp_max_link_bw(encoder));
+       int max_lanes = cdv_intel_dp_max_lane_count(encoder);
+       struct drm_psb_private *dev_priv = connector->dev->dev_private;
+       if (is_edp(encoder) && intel_dp->panel_fixed_mode) {
+               if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay)
+                       return MODE_PANEL;
+               if (mode->vdisplay > intel_dp->panel_fixed_mode->vdisplay)
+                       return MODE_PANEL;
+       }
+       /* only refuse the mode on non eDP since we have seen some weird eDP panels
+          which are outside spec tolerances but somehow work by magic */
+       if (!is_edp(encoder) &&
+           (cdv_intel_dp_link_required(mode->clock, dev_priv->edp.bpp)
+            > cdv_intel_dp_max_data_rate(max_link_clock, max_lanes)))
+               return MODE_CLOCK_HIGH;
+       if (is_edp(encoder)) {
+           if (cdv_intel_dp_link_required(mode->clock, 24)
+               > cdv_intel_dp_max_data_rate(max_link_clock, max_lanes))
+               return MODE_CLOCK_HIGH;
+               
+       }
+       if (mode->clock < 10000)
+               return MODE_CLOCK_LOW;
+       return MODE_OK;
+ }
+ static uint32_t
+ pack_aux(uint8_t *src, int src_bytes)
+ {
+       int     i;
+       uint32_t v = 0;
+       if (src_bytes > 4)
+               src_bytes = 4;
+       for (i = 0; i < src_bytes; i++)
+               v |= ((uint32_t) src[i]) << ((3-i) * 8);
+       return v;
+ }
+ static void
+ unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
+ {
+       int i;
+       if (dst_bytes > 4)
+               dst_bytes = 4;
+       for (i = 0; i < dst_bytes; i++)
+               dst[i] = src >> ((3-i) * 8);
+ }
+ static int
+ cdv_intel_dp_aux_ch(struct psb_intel_encoder *encoder,
+               uint8_t *send, int send_bytes,
+               uint8_t *recv, int recv_size)
+ {
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       uint32_t output_reg = intel_dp->output_reg;
+       struct drm_device *dev = encoder->base.dev;
+       uint32_t ch_ctl = output_reg + 0x10;
+       uint32_t ch_data = ch_ctl + 4;
+       int i;
+       int recv_bytes;
+       uint32_t status;
+       uint32_t aux_clock_divider;
+       int try, precharge;
+       /* The clock divider is based off the hrawclk,
+        * and would like to run at 2MHz. So, take the
+        * hrawclk value and divide by 2 and use that
+        * On CDV platform it uses 200MHz as hrawclk.
+        *
+        */
+       aux_clock_divider = 200 / 2;
+       precharge = 4;
+       if (is_edp(encoder))
+               precharge = 10;
+       if (REG_READ(ch_ctl) & DP_AUX_CH_CTL_SEND_BUSY) {
+               DRM_ERROR("dp_aux_ch not started status 0x%08x\n",
+                         REG_READ(ch_ctl));
+               return -EBUSY;
+       }
+       /* Must try at least 3 times according to DP spec */
+       for (try = 0; try < 5; try++) {
+               /* Load the send data into the aux channel data registers */
+               for (i = 0; i < send_bytes; i += 4)
+                       REG_WRITE(ch_data + i,
+                                  pack_aux(send + i, send_bytes - i));
+       
+               /* Send the command and wait for it to complete */
+               REG_WRITE(ch_ctl,
+                          DP_AUX_CH_CTL_SEND_BUSY |
+                          DP_AUX_CH_CTL_TIME_OUT_400us |
+                          (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
+                          (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
+                          (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
+                          DP_AUX_CH_CTL_DONE |
+                          DP_AUX_CH_CTL_TIME_OUT_ERROR |
+                          DP_AUX_CH_CTL_RECEIVE_ERROR);
+               for (;;) {
+                       status = REG_READ(ch_ctl);
+                       if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
+                               break;
+                       udelay(100);
+               }
+       
+               /* Clear done status and any errors */
+               REG_WRITE(ch_ctl,
+                          status |
+                          DP_AUX_CH_CTL_DONE |
+                          DP_AUX_CH_CTL_TIME_OUT_ERROR |
+                          DP_AUX_CH_CTL_RECEIVE_ERROR);
+               if (status & DP_AUX_CH_CTL_DONE)
+                       break;
+       }
+       if ((status & DP_AUX_CH_CTL_DONE) == 0) {
+               DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status);
+               return -EBUSY;
+       }
+       /* Check for timeout or receive error.
+        * Timeouts occur when the sink is not connected
+        */
+       if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
+               DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status);
+               return -EIO;
+       }
+       /* Timeouts occur when the device isn't connected, so they're
+        * "normal" -- don't fill the kernel log with these */
+       if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
+               DRM_DEBUG_KMS("dp_aux_ch timeout status 0x%08x\n", status);
+               return -ETIMEDOUT;
+       }
+       /* Unload any bytes sent back from the other side */
+       recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
+                     DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
+       if (recv_bytes > recv_size)
+               recv_bytes = recv_size;
+       
+       for (i = 0; i < recv_bytes; i += 4)
+               unpack_aux(REG_READ(ch_data + i),
+                          recv + i, recv_bytes - i);
+       return recv_bytes;
+ }
+ /* Write data to the aux channel in native mode */
+ static int
+ cdv_intel_dp_aux_native_write(struct psb_intel_encoder *encoder,
+                         uint16_t address, uint8_t *send, int send_bytes)
+ {
+       int ret;
+       uint8_t msg[20];
+       int msg_bytes;
+       uint8_t ack;
+       if (send_bytes > 16)
+               return -1;
+       msg[0] = AUX_NATIVE_WRITE << 4;
+       msg[1] = address >> 8;
+       msg[2] = address & 0xff;
+       msg[3] = send_bytes - 1;
+       memcpy(&msg[4], send, send_bytes);
+       msg_bytes = send_bytes + 4;
+       for (;;) {
+               ret = cdv_intel_dp_aux_ch(encoder, msg, msg_bytes, &ack, 1);
+               if (ret < 0)
+                       return ret;
+               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+                       break;
+               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+                       udelay(100);
+               else
+                       return -EIO;
+       }
+       return send_bytes;
+ }
+ /* Write a single byte to the aux channel in native mode */
+ static int
+ cdv_intel_dp_aux_native_write_1(struct psb_intel_encoder *encoder,
+                           uint16_t address, uint8_t byte)
+ {
+       return cdv_intel_dp_aux_native_write(encoder, address, &byte, 1);
+ }
+ /* read bytes from a native aux channel */
+ static int
+ cdv_intel_dp_aux_native_read(struct psb_intel_encoder *encoder,
+                        uint16_t address, uint8_t *recv, int recv_bytes)
+ {
+       uint8_t msg[4];
+       int msg_bytes;
+       uint8_t reply[20];
+       int reply_bytes;
+       uint8_t ack;
+       int ret;
+       msg[0] = AUX_NATIVE_READ << 4;
+       msg[1] = address >> 8;
+       msg[2] = address & 0xff;
+       msg[3] = recv_bytes - 1;
+       msg_bytes = 4;
+       reply_bytes = recv_bytes + 1;
+       for (;;) {
+               ret = cdv_intel_dp_aux_ch(encoder, msg, msg_bytes,
+                                     reply, reply_bytes);
+               if (ret == 0)
+                       return -EPROTO;
+               if (ret < 0)
+                       return ret;
+               ack = reply[0];
+               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) {
+                       memcpy(recv, reply + 1, ret - 1);
+                       return ret - 1;
+               }
+               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+                       udelay(100);
+               else
+                       return -EIO;
+       }
+ }
+ static int
+ cdv_intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
+                   uint8_t write_byte, uint8_t *read_byte)
+ {
+       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+       struct cdv_intel_dp *intel_dp = container_of(adapter,
+                                               struct cdv_intel_dp,
+                                               adapter);
+       struct psb_intel_encoder *encoder = intel_dp->encoder;
+       uint16_t address = algo_data->address;
+       uint8_t msg[5];
+       uint8_t reply[2];
+       unsigned retry;
+       int msg_bytes;
+       int reply_bytes;
+       int ret;
+       /* Set up the command byte */
+       if (mode & MODE_I2C_READ)
+               msg[0] = AUX_I2C_READ << 4;
+       else
+               msg[0] = AUX_I2C_WRITE << 4;
+       if (!(mode & MODE_I2C_STOP))
+               msg[0] |= AUX_I2C_MOT << 4;
+       msg[1] = address >> 8;
+       msg[2] = address;
+       switch (mode) {
+       case MODE_I2C_WRITE:
+               msg[3] = 0;
+               msg[4] = write_byte;
+               msg_bytes = 5;
+               reply_bytes = 1;
+               break;
+       case MODE_I2C_READ:
+               msg[3] = 0;
+               msg_bytes = 4;
+               reply_bytes = 2;
+               break;
+       default:
+               msg_bytes = 3;
+               reply_bytes = 1;
+               break;
+       }
+       for (retry = 0; retry < 5; retry++) {
+               ret = cdv_intel_dp_aux_ch(encoder,
+                                     msg, msg_bytes,
+                                     reply, reply_bytes);
+               if (ret < 0) {
+                       DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
+                       return ret;
+               }
+               switch (reply[0] & AUX_NATIVE_REPLY_MASK) {
+               case AUX_NATIVE_REPLY_ACK:
+                       /* I2C-over-AUX Reply field is only valid
+                        * when paired with AUX ACK.
+                        */
+                       break;
+               case AUX_NATIVE_REPLY_NACK:
+                       DRM_DEBUG_KMS("aux_ch native nack\n");
+                       return -EREMOTEIO;
+               case AUX_NATIVE_REPLY_DEFER:
+                       udelay(100);
+                       continue;
+               default:
+                       DRM_ERROR("aux_ch invalid native reply 0x%02x\n",
+                                 reply[0]);
+                       return -EREMOTEIO;
+               }
+               switch (reply[0] & AUX_I2C_REPLY_MASK) {
+               case AUX_I2C_REPLY_ACK:
+                       if (mode == MODE_I2C_READ) {
+                               *read_byte = reply[1];
+                       }
+                       return reply_bytes - 1;
+               case AUX_I2C_REPLY_NACK:
+                       DRM_DEBUG_KMS("aux_i2c nack\n");
+                       return -EREMOTEIO;
+               case AUX_I2C_REPLY_DEFER:
+                       DRM_DEBUG_KMS("aux_i2c defer\n");
+                       udelay(100);
+                       break;
+               default:
+                       DRM_ERROR("aux_i2c invalid reply 0x%02x\n", reply[0]);
+                       return -EREMOTEIO;
+               }
+       }
+       DRM_ERROR("too many retries, giving up\n");
+       return -EREMOTEIO;
+ }
+ static int
+ cdv_intel_dp_i2c_init(struct psb_intel_connector *connector, struct psb_intel_encoder *encoder, const char *name)
+ {
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       int ret;
+       DRM_DEBUG_KMS("i2c_init %s\n", name);
+       intel_dp->algo.running = false;
+       intel_dp->algo.address = 0;
+       intel_dp->algo.aux_ch = cdv_intel_dp_i2c_aux_ch;
+       memset(&intel_dp->adapter, '\0', sizeof (intel_dp->adapter));
+       intel_dp->adapter.owner = THIS_MODULE;
+       intel_dp->adapter.class = I2C_CLASS_DDC;
+       strncpy (intel_dp->adapter.name, name, sizeof(intel_dp->adapter.name) - 1);
+       intel_dp->adapter.name[sizeof(intel_dp->adapter.name) - 1] = '\0';
+       intel_dp->adapter.algo_data = &intel_dp->algo;
+       intel_dp->adapter.dev.parent = &connector->base.kdev;
+       if (is_edp(encoder))
+               cdv_intel_edp_panel_vdd_on(encoder);
+       ret = i2c_dp_aux_add_bus(&intel_dp->adapter);
+       if (is_edp(encoder))
+               cdv_intel_edp_panel_vdd_off(encoder);
+       
+       return ret;
+ }
+ void cdv_intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
+       struct drm_display_mode *adjusted_mode)
+ {
+       adjusted_mode->hdisplay = fixed_mode->hdisplay;
+       adjusted_mode->hsync_start = fixed_mode->hsync_start;
+       adjusted_mode->hsync_end = fixed_mode->hsync_end;
+       adjusted_mode->htotal = fixed_mode->htotal;
+       adjusted_mode->vdisplay = fixed_mode->vdisplay;
+       adjusted_mode->vsync_start = fixed_mode->vsync_start;
+       adjusted_mode->vsync_end = fixed_mode->vsync_end;
+       adjusted_mode->vtotal = fixed_mode->vtotal;
+       adjusted_mode->clock = fixed_mode->clock;
+       drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+ }
+ static bool
+ cdv_intel_dp_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode,
+                   struct drm_display_mode *adjusted_mode)
+ {
+       struct drm_psb_private *dev_priv = encoder->dev->dev_private;
+       struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
+       struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
+       int lane_count, clock;
+       int max_lane_count = cdv_intel_dp_max_lane_count(intel_encoder);
+       int max_clock = cdv_intel_dp_max_link_bw(intel_encoder) == DP_LINK_BW_2_7 ? 1 : 0;
+       static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
+       int refclock = mode->clock;
+       int bpp = 24;
+       if (is_edp(intel_encoder) && intel_dp->panel_fixed_mode) {
+               cdv_intel_fixed_panel_mode(intel_dp->panel_fixed_mode, adjusted_mode);
+               refclock = intel_dp->panel_fixed_mode->clock;
+               bpp = dev_priv->edp.bpp;
+       }
+       for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
+               for (clock = max_clock; clock >= 0; clock--) {
+                       int link_avail = cdv_intel_dp_max_data_rate(cdv_intel_dp_link_clock(bws[clock]), lane_count);
+                       if (cdv_intel_dp_link_required(refclock, bpp) <= link_avail) {
+                               intel_dp->link_bw = bws[clock];
+                               intel_dp->lane_count = lane_count;
+                               adjusted_mode->clock = cdv_intel_dp_link_clock(intel_dp->link_bw);
+                               DRM_DEBUG_KMS("Display port link bw %02x lane "
+                                               "count %d clock %d\n",
+                                      intel_dp->link_bw, intel_dp->lane_count,
+                                      adjusted_mode->clock);
+                               return true;
+                       }
+               }
+       }
+       if (is_edp(intel_encoder)) {
+               /* okay we failed just pick the highest */
+               intel_dp->lane_count = max_lane_count;
+               intel_dp->link_bw = bws[max_clock];
+               adjusted_mode->clock = cdv_intel_dp_link_clock(intel_dp->link_bw);
+               DRM_DEBUG_KMS("Force picking display port link bw %02x lane "
+                             "count %d clock %d\n",
+                             intel_dp->link_bw, intel_dp->lane_count,
+                             adjusted_mode->clock);
+               return true;
+       }
+       return false;
+ }
+ struct cdv_intel_dp_m_n {
+       uint32_t        tu;
+       uint32_t        gmch_m;
+       uint32_t        gmch_n;
+       uint32_t        link_m;
+       uint32_t        link_n;
+ };
+ static void
+ cdv_intel_reduce_ratio(uint32_t *num, uint32_t *den)
+ {
+       /*
+       while (*num > 0xffffff || *den > 0xffffff) {
+               *num >>= 1;
+               *den >>= 1;
+       }*/
+       uint64_t value, m;
+       m = *num;
+       value = m * (0x800000);
+       m = do_div(value, *den);
+       *num = value;
+       *den = 0x800000;
+ }
+ static void
+ cdv_intel_dp_compute_m_n(int bpp,
+                    int nlanes,
+                    int pixel_clock,
+                    int link_clock,
+                    struct cdv_intel_dp_m_n *m_n)
+ {
+       m_n->tu = 64;
+       m_n->gmch_m = (pixel_clock * bpp + 7) >> 3;
+       m_n->gmch_n = link_clock * nlanes;
+       cdv_intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
+       m_n->link_m = pixel_clock;
+       m_n->link_n = link_clock;
+       cdv_intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
+ }
+ void
+ cdv_intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                struct drm_display_mode *adjusted_mode)
+ {
+       struct drm_device *dev = crtc->dev;
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_encoder *encoder;
+       struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);
+       int lane_count = 4, bpp = 24;
+       struct cdv_intel_dp_m_n m_n;
+       int pipe = intel_crtc->pipe;
+       /*
+        * Find the lane count in the intel_encoder private
+        */
+       list_for_each_entry(encoder, &mode_config->encoder_list, head) {
+               struct psb_intel_encoder *intel_encoder;
+               struct cdv_intel_dp *intel_dp;
+               if (encoder->crtc != crtc)
+                       continue;
+               intel_encoder = to_psb_intel_encoder(encoder);
+               intel_dp = intel_encoder->dev_priv;
+               if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
+                       lane_count = intel_dp->lane_count;
+                       break;
+               } else if (is_edp(intel_encoder)) {
+                       lane_count = intel_dp->lane_count;
+                       bpp = dev_priv->edp.bpp;
+                       break;
+               }
+       }
+       /*
+        * Compute the GMCH and Link ratios. The '3' here is
+        * the number of bytes_per_pixel post-LUT, which we always
+        * set up for 8-bits of R/G/B, or 3 bytes total.
+        */
+       cdv_intel_dp_compute_m_n(bpp, lane_count,
+                            mode->clock, adjusted_mode->clock, &m_n);
+       {
+               REG_WRITE(PIPE_GMCH_DATA_M(pipe),
+                          ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
+                          m_n.gmch_m);
+               REG_WRITE(PIPE_GMCH_DATA_N(pipe), m_n.gmch_n);
+               REG_WRITE(PIPE_DP_LINK_M(pipe), m_n.link_m);
+               REG_WRITE(PIPE_DP_LINK_N(pipe), m_n.link_n);
+       }
+ }
+ static void
+ cdv_intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
+                 struct drm_display_mode *adjusted_mode)
+ {
+       struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
+       struct drm_crtc *crtc = encoder->crtc;
+       struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);
+       struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
+       struct drm_device *dev = encoder->dev;
+       intel_dp->DP = DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
+       intel_dp->DP |= intel_dp->color_range;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+               intel_dp->DP |= DP_SYNC_HS_HIGH;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+               intel_dp->DP |= DP_SYNC_VS_HIGH;
+       intel_dp->DP |= DP_LINK_TRAIN_OFF;
+       switch (intel_dp->lane_count) {
+       case 1:
+               intel_dp->DP |= DP_PORT_WIDTH_1;
+               break;
+       case 2:
+               intel_dp->DP |= DP_PORT_WIDTH_2;
+               break;
+       case 4:
+               intel_dp->DP |= DP_PORT_WIDTH_4;
+               break;
+       }
+       if (intel_dp->has_audio)
+               intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
+       memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
+       intel_dp->link_configuration[0] = intel_dp->link_bw;
+       intel_dp->link_configuration[1] = intel_dp->lane_count;
+       /*
+        * Check for DPCD version > 1.1 and enhanced framing support
+        */
+       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
+           (intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)) {
+               intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+               intel_dp->DP |= DP_ENHANCED_FRAMING;
+       }
+       /* CPT DP's pipe select is decided in TRANS_DP_CTL */
+       if (intel_crtc->pipe == 1)
+               intel_dp->DP |= DP_PIPEB_SELECT;
+       REG_WRITE(intel_dp->output_reg, (intel_dp->DP | DP_PORT_EN));
+       DRM_DEBUG_KMS("DP expected reg is %x\n", intel_dp->DP);
+       if (is_edp(intel_encoder)) {
+               uint32_t pfit_control;
+               cdv_intel_edp_panel_on(intel_encoder);
+               if (mode->hdisplay != adjusted_mode->hdisplay ||
+                           mode->vdisplay != adjusted_mode->vdisplay)
+                       pfit_control = PFIT_ENABLE;
+               else
+                       pfit_control = 0;
+               pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT;
+               REG_WRITE(PFIT_CONTROL, pfit_control);
+       }
+ }
+ /* If the sink supports it, try to set the power state appropriately */
+ static void cdv_intel_dp_sink_dpms(struct psb_intel_encoder *encoder, int mode)
+ {
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       int ret, i;
+       /* Should have a valid DPCD by this point */
+       if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
+               return;
+       if (mode != DRM_MODE_DPMS_ON) {
+               ret = cdv_intel_dp_aux_native_write_1(encoder, DP_SET_POWER,
+                                                 DP_SET_POWER_D3);
+               if (ret != 1)
+                       DRM_DEBUG_DRIVER("failed to write sink power state\n");
+       } else {
+               /*
+                * When turning on, we need to retry for 1ms to give the sink
+                * time to wake up.
+                */
+               for (i = 0; i < 3; i++) {
+                       ret = cdv_intel_dp_aux_native_write_1(encoder,
+                                                         DP_SET_POWER,
+                                                         DP_SET_POWER_D0);
+                       if (ret == 1)
+                               break;
+                       udelay(1000);
+               }
+       }
+ }
+ static void cdv_intel_dp_prepare(struct drm_encoder *encoder)
+ {
+       struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
+       int edp = is_edp(intel_encoder);
+       if (edp) {
+               cdv_intel_edp_backlight_off(intel_encoder);
+               cdv_intel_edp_panel_off(intel_encoder);
+               cdv_intel_edp_panel_vdd_on(intel_encoder);
+         }
+       /* Wake up the sink first */
+       cdv_intel_dp_sink_dpms(intel_encoder, DRM_MODE_DPMS_ON);
+       cdv_intel_dp_link_down(intel_encoder);
+       if (edp)
+               cdv_intel_edp_panel_vdd_off(intel_encoder);
+ }
+ static void cdv_intel_dp_commit(struct drm_encoder *encoder)
+ {
+       struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
+       int edp = is_edp(intel_encoder);
+       if (edp)
+               cdv_intel_edp_panel_on(intel_encoder);
+       cdv_intel_dp_start_link_train(intel_encoder);
+       cdv_intel_dp_complete_link_train(intel_encoder);
+       if (edp)
+               cdv_intel_edp_backlight_on(intel_encoder);
+ }
+ static void
+ cdv_intel_dp_dpms(struct drm_encoder *encoder, int mode)
+ {
+       struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
+       struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
+       struct drm_device *dev = encoder->dev;
+       uint32_t dp_reg = REG_READ(intel_dp->output_reg);
+       int edp = is_edp(intel_encoder);
+       if (mode != DRM_MODE_DPMS_ON) {
+               if (edp) {
+                       cdv_intel_edp_backlight_off(intel_encoder);
+                       cdv_intel_edp_panel_vdd_on(intel_encoder);
+               }
+               cdv_intel_dp_sink_dpms(intel_encoder, mode);
+               cdv_intel_dp_link_down(intel_encoder);
+               if (edp) {
+                       cdv_intel_edp_panel_vdd_off(intel_encoder);
+                       cdv_intel_edp_panel_off(intel_encoder);
+               }
+       } else {
+               if (edp)
+                       cdv_intel_edp_panel_on(intel_encoder);
+               cdv_intel_dp_sink_dpms(intel_encoder, mode);
+               if (!(dp_reg & DP_PORT_EN)) {
+                       cdv_intel_dp_start_link_train(intel_encoder);
+                       cdv_intel_dp_complete_link_train(intel_encoder);
+               }
+               if (edp)
+                       cdv_intel_edp_backlight_on(intel_encoder);
+       }
+ }
+ /*
+  * Native read with retry for link status and receiver capability reads for
+  * cases where the sink may still be asleep.
+  */
+ static bool
+ cdv_intel_dp_aux_native_read_retry(struct psb_intel_encoder *encoder, uint16_t address,
+                              uint8_t *recv, int recv_bytes)
+ {
+       int ret, i;
+       /*
+        * Sinks are *supposed* to come up within 1ms from an off state,
+        * but we're also supposed to retry 3 times per the spec.
+        */
+       for (i = 0; i < 3; i++) {
+               ret = cdv_intel_dp_aux_native_read(encoder, address, recv,
+                                              recv_bytes);
+               if (ret == recv_bytes)
+                       return true;
+               udelay(1000);
+       }
+       return false;
+ }
+ /*
+  * Fetch AUX CH registers 0x202 - 0x207 which contain
+  * link status information
+  */
+ static bool
+ cdv_intel_dp_get_link_status(struct psb_intel_encoder *encoder)
+ {
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       return cdv_intel_dp_aux_native_read_retry(encoder,
+                                             DP_LANE0_1_STATUS,
+                                             intel_dp->link_status,
+                                             DP_LINK_STATUS_SIZE);
+ }
+ static uint8_t
+ cdv_intel_dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
+                    int r)
+ {
+       return link_status[r - DP_LANE0_1_STATUS];
+ }
+ static uint8_t
+ cdv_intel_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
+                                int lane)
+ {
+       int         i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
+       int         s = ((lane & 1) ?
+                        DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
+                        DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
+       uint8_t l = cdv_intel_dp_link_status(link_status, i);
+       return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
+ }
+ static uint8_t
+ cdv_intel_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
+                                     int lane)
+ {
+       int         i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
+       int         s = ((lane & 1) ?
+                        DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
+                        DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
+       uint8_t l = cdv_intel_dp_link_status(link_status, i);
+       return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
+ }
+ #if 0
+ static char   *voltage_names[] = {
+       "0.4V", "0.6V", "0.8V", "1.2V"
+ };
+ static char   *pre_emph_names[] = {
+       "0dB", "3.5dB", "6dB", "9.5dB"
+ };
+ static char   *link_train_names[] = {
+       "pattern 1", "pattern 2", "idle", "off"
+ };
+ #endif
+ #define CDV_DP_VOLTAGE_MAX        DP_TRAIN_VOLTAGE_SWING_1200
+ /*
+ static uint8_t
+ cdv_intel_dp_pre_emphasis_max(uint8_t voltage_swing)
+ {
+       switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+       case DP_TRAIN_VOLTAGE_SWING_400:
+               return DP_TRAIN_PRE_EMPHASIS_6;
+       case DP_TRAIN_VOLTAGE_SWING_600:
+               return DP_TRAIN_PRE_EMPHASIS_6;
+       case DP_TRAIN_VOLTAGE_SWING_800:
+               return DP_TRAIN_PRE_EMPHASIS_3_5;
+       case DP_TRAIN_VOLTAGE_SWING_1200:
+       default:
+               return DP_TRAIN_PRE_EMPHASIS_0;
+       }
+ }
+ */
+ static void
+ cdv_intel_get_adjust_train(struct psb_intel_encoder *encoder)
+ {
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       uint8_t v = 0;
+       uint8_t p = 0;
+       int lane;
+       for (lane = 0; lane < intel_dp->lane_count; lane++) {
+               uint8_t this_v = cdv_intel_get_adjust_request_voltage(intel_dp->link_status, lane);
+               uint8_t this_p = cdv_intel_get_adjust_request_pre_emphasis(intel_dp->link_status, lane);
+               if (this_v > v)
+                       v = this_v;
+               if (this_p > p)
+                       p = this_p;
+       }
+       
+       if (v >= CDV_DP_VOLTAGE_MAX)
+               v = CDV_DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
+       if (p == DP_TRAIN_PRE_EMPHASIS_MASK)
+               p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+               
+       for (lane = 0; lane < 4; lane++)
+               intel_dp->train_set[lane] = v | p;
+ }
+ static uint8_t
+ cdv_intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
+                     int lane)
+ {
+       int i = DP_LANE0_1_STATUS + (lane >> 1);
+       int s = (lane & 1) * 4;
+       uint8_t l = cdv_intel_dp_link_status(link_status, i);
+       return (l >> s) & 0xf;
+ }
+ /* Check for clock recovery is done on all channels */
+ static bool
+ cdv_intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+ {
+       int lane;
+       uint8_t lane_status;
+       for (lane = 0; lane < lane_count; lane++) {
+               lane_status = cdv_intel_get_lane_status(link_status, lane);
+               if ((lane_status & DP_LANE_CR_DONE) == 0)
+                       return false;
+       }
+       return true;
+ }
+ /* Check to see if channel eq is done on all channels */
+ #define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\
+                        DP_LANE_CHANNEL_EQ_DONE|\
+                        DP_LANE_SYMBOL_LOCKED)
+ static bool
+ cdv_intel_channel_eq_ok(struct psb_intel_encoder *encoder)
+ {
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       uint8_t lane_align;
+       uint8_t lane_status;
+       int lane;
+       lane_align = cdv_intel_dp_link_status(intel_dp->link_status,
+                                         DP_LANE_ALIGN_STATUS_UPDATED);
+       if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
+               return false;
+       for (lane = 0; lane < intel_dp->lane_count; lane++) {
+               lane_status = cdv_intel_get_lane_status(intel_dp->link_status, lane);
+               if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
+                       return false;
+       }
+       return true;
+ }
+ static bool
+ cdv_intel_dp_set_link_train(struct psb_intel_encoder *encoder,
+                       uint32_t dp_reg_value,
+                       uint8_t dp_train_pat)
+ {
+       
+       struct drm_device *dev = encoder->base.dev;
+       int ret;
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       REG_WRITE(intel_dp->output_reg, dp_reg_value);
+       REG_READ(intel_dp->output_reg);
+       ret = cdv_intel_dp_aux_native_write_1(encoder,
+                                   DP_TRAINING_PATTERN_SET,
+                                   dp_train_pat);
+       if (ret != 1) {
+               DRM_DEBUG_KMS("Failure in setting link pattern %x\n",
+                               dp_train_pat);
+               return false;
+       }
+       return true;
+ }
+ static bool
+ cdv_intel_dplink_set_level(struct psb_intel_encoder *encoder,
+                       uint8_t dp_train_pat)
+ {
+       
+       int ret;
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       ret = cdv_intel_dp_aux_native_write(encoder,
+                                       DP_TRAINING_LANE0_SET,
+                                       intel_dp->train_set,
+                                       intel_dp->lane_count);
+       if (ret != intel_dp->lane_count) {
+               DRM_DEBUG_KMS("Failure in setting level %d, lane_cnt= %d\n",
+                               intel_dp->train_set[0], intel_dp->lane_count);
+               return false;
+       }
+       return true;
+ }
+ static void
+ cdv_intel_dp_set_vswing_premph(struct psb_intel_encoder *encoder, uint8_t signal_level)
+ {
+       struct drm_device *dev = encoder->base.dev;
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       struct ddi_regoff *ddi_reg;
+       int vswing, premph, index;
+       if (intel_dp->output_reg == DP_B)
+               ddi_reg = &ddi_DP_train_table[0];
+       else
+               ddi_reg = &ddi_DP_train_table[1];
+       vswing = (signal_level & DP_TRAIN_VOLTAGE_SWING_MASK);
+       premph = ((signal_level & DP_TRAIN_PRE_EMPHASIS_MASK)) >>
+                               DP_TRAIN_PRE_EMPHASIS_SHIFT;
+       if (vswing + premph > 3)
+               return;
+ #ifdef CDV_FAST_LINK_TRAIN
+       return;
+ #endif
+       DRM_DEBUG_KMS("Test2\n");
+       //return ;
+       cdv_sb_reset(dev);
+       /* ;Swing voltage programming
+         ;gfx_dpio_set_reg(0xc058, 0x0505313A) */
+       cdv_sb_write(dev, ddi_reg->VSwing5, 0x0505313A);
+       /* ;gfx_dpio_set_reg(0x8154, 0x43406055) */
+       cdv_sb_write(dev, ddi_reg->VSwing1, 0x43406055);
+       /* ;gfx_dpio_set_reg(0x8148, 0x55338954)
+        * The VSwing_PreEmph table is also considered based on the vswing/premp
+        */
+       index = (vswing + premph) * 2;
+       if (premph == 1 && vswing == 1) {
+               cdv_sb_write(dev, ddi_reg->VSwing2, 0x055738954);
+       } else
+               cdv_sb_write(dev, ddi_reg->VSwing2, dp_vswing_premph_table[index]);
+       /* ;gfx_dpio_set_reg(0x814c, 0x40802040) */
+       if ((vswing + premph) == DP_TRAIN_VOLTAGE_SWING_1200)
+               cdv_sb_write(dev, ddi_reg->VSwing3, 0x70802040);
+       else
+               cdv_sb_write(dev, ddi_reg->VSwing3, 0x40802040);
+       /* ;gfx_dpio_set_reg(0x8150, 0x2b405555) */
+       /* cdv_sb_write(dev, ddi_reg->VSwing4, 0x2b405555); */
+       /* ;gfx_dpio_set_reg(0x8154, 0xc3406055) */
+       cdv_sb_write(dev, ddi_reg->VSwing1, 0xc3406055);
+       /* ;Pre emphasis programming
+        * ;gfx_dpio_set_reg(0xc02c, 0x1f030040)
+        */
+       cdv_sb_write(dev, ddi_reg->PreEmph1, 0x1f030040);
+       /* ;gfx_dpio_set_reg(0x8124, 0x00004000) */
+       index = 2 * premph + 1;
+       cdv_sb_write(dev, ddi_reg->PreEmph2, dp_vswing_premph_table[index]);
+       return; 
+ }
+ /* Enable corresponding port and start training pattern 1 */
+ static void
+ cdv_intel_dp_start_link_train(struct psb_intel_encoder *encoder)
+ {
+       struct drm_device *dev = encoder->base.dev;
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       int i;
+       uint8_t voltage;
+       bool clock_recovery = false;
+       int tries;
+       u32 reg;
+       uint32_t DP = intel_dp->DP;
+       DP |= DP_PORT_EN;
+       DP &= ~DP_LINK_TRAIN_MASK;
+               
+       reg = DP;       
+       reg |= DP_LINK_TRAIN_PAT_1;
+       /* Enable output, wait for it to become active */
+       REG_WRITE(intel_dp->output_reg, reg);
+       REG_READ(intel_dp->output_reg);
+       psb_intel_wait_for_vblank(dev);
+       DRM_DEBUG_KMS("Link config\n");
+       /* Write the link configuration data */
+       cdv_intel_dp_aux_native_write(encoder, DP_LINK_BW_SET,
+                                 intel_dp->link_configuration,
+                                 2);
+       memset(intel_dp->train_set, 0, 4);
+       voltage = 0;
+       tries = 0;
+       clock_recovery = false;
+       DRM_DEBUG_KMS("Start train\n");
+               reg = DP | DP_LINK_TRAIN_PAT_1;
+       for (;;) {
+               /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
+               DRM_DEBUG_KMS("DP Link Train Set %x, Link_config %x, %x\n",
+                               intel_dp->train_set[0],
+                               intel_dp->link_configuration[0],
+                               intel_dp->link_configuration[1]);
+               if (!cdv_intel_dp_set_link_train(encoder, reg, DP_TRAINING_PATTERN_1)) {
+                       DRM_DEBUG_KMS("Failure in aux-transfer setting pattern 1\n");
+               }
+               cdv_intel_dp_set_vswing_premph(encoder, intel_dp->train_set[0]);
+               /* Set training pattern 1 */
+               cdv_intel_dplink_set_level(encoder, DP_TRAINING_PATTERN_1);
+               udelay(200);
+               if (!cdv_intel_dp_get_link_status(encoder))
+                       break;
+               DRM_DEBUG_KMS("DP Link status %x, %x, %x, %x, %x, %x\n",
+                               intel_dp->link_status[0], intel_dp->link_status[1], intel_dp->link_status[2],
+                               intel_dp->link_status[3], intel_dp->link_status[4], intel_dp->link_status[5]);
+               if (cdv_intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
+                       DRM_DEBUG_KMS("PT1 train is done\n");
+                       clock_recovery = true;
+                       break;
+               }
+               /* Check to see if we've tried the max voltage */
+               for (i = 0; i < intel_dp->lane_count; i++)
+                       if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+                               break;
+               if (i == intel_dp->lane_count)
+                       break;
+               /* Check to see if we've tried the same voltage 5 times */
+               if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+                       ++tries;
+                       if (tries == 5)
+                               break;
+               } else
+                       tries = 0;
+               voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+               /* Compute new intel_dp->train_set as requested by target */
+               cdv_intel_get_adjust_train(encoder);
+       }
+       if (!clock_recovery) {
+               DRM_DEBUG_KMS("failure in DP patter 1 training, train set %x\n", intel_dp->train_set[0]);
+       }
+       
+       intel_dp->DP = DP;
+ }
+ static void
+ cdv_intel_dp_complete_link_train(struct psb_intel_encoder *encoder)
+ {
+       struct drm_device *dev = encoder->base.dev;
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       bool channel_eq = false;
+       int tries, cr_tries;
+       u32 reg;
+       uint32_t DP = intel_dp->DP;
+       /* channel equalization */
+       tries = 0;
+       cr_tries = 0;
+       channel_eq = false;
+       DRM_DEBUG_KMS("\n");
+               reg = DP | DP_LINK_TRAIN_PAT_2;
+       for (;;) {
+               DRM_DEBUG_KMS("DP Link Train Set %x, Link_config %x, %x\n",
+                               intel_dp->train_set[0],
+                               intel_dp->link_configuration[0],
+                               intel_dp->link_configuration[1]);
+               /* channel eq pattern */
+               if (!cdv_intel_dp_set_link_train(encoder, reg,
+                                            DP_TRAINING_PATTERN_2)) {
+                       DRM_DEBUG_KMS("Failure in aux-transfer setting pattern 2\n");
+               }
+               /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
+               if (cr_tries > 5) {
+                       DRM_ERROR("failed to train DP, aborting\n");
+                       cdv_intel_dp_link_down(encoder);
+                       break;
+               }
+               cdv_intel_dp_set_vswing_premph(encoder, intel_dp->train_set[0]);
+               cdv_intel_dplink_set_level(encoder, DP_TRAINING_PATTERN_2);
+               udelay(1000);
+               if (!cdv_intel_dp_get_link_status(encoder))
+                       break;
+               DRM_DEBUG_KMS("DP Link status %x, %x, %x, %x, %x, %x\n",
+                               intel_dp->link_status[0], intel_dp->link_status[1], intel_dp->link_status[2],
+                               intel_dp->link_status[3], intel_dp->link_status[4], intel_dp->link_status[5]);
+               /* Make sure clock is still ok */
+               if (!cdv_intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
+                       cdv_intel_dp_start_link_train(encoder);
+                       cr_tries++;
+                       continue;
+               }
+               if (cdv_intel_channel_eq_ok(encoder)) {
+                       DRM_DEBUG_KMS("PT2 train is done\n");
+                       channel_eq = true;
+                       break;
+               }
+               /* Try 5 times, then try clock recovery if that fails */
+               if (tries > 5) {
+                       cdv_intel_dp_link_down(encoder);
+                       cdv_intel_dp_start_link_train(encoder);
+                       tries = 0;
+                       cr_tries++;
+                       continue;
+               }
+               /* Compute new intel_dp->train_set as requested by target */
+               cdv_intel_get_adjust_train(encoder);
+               ++tries;
+       }
+       reg = DP | DP_LINK_TRAIN_OFF;
+       REG_WRITE(intel_dp->output_reg, reg);
+       REG_READ(intel_dp->output_reg);
+       cdv_intel_dp_aux_native_write_1(encoder,
+                                   DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE);
+ }
+ static void
+ cdv_intel_dp_link_down(struct psb_intel_encoder *encoder)
+ {
+       struct drm_device *dev = encoder->base.dev;
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       uint32_t DP = intel_dp->DP;
+       if ((REG_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)
+               return;
+       DRM_DEBUG_KMS("\n");
+       {
+               DP &= ~DP_LINK_TRAIN_MASK;
+               REG_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
+       }
+       REG_READ(intel_dp->output_reg);
+       msleep(17);
+       REG_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
+       REG_READ(intel_dp->output_reg);
+ }
+ static enum drm_connector_status
+ cdv_dp_detect(struct psb_intel_encoder *encoder)
+ {
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       enum drm_connector_status status;
+       status = connector_status_disconnected;
+       if (cdv_intel_dp_aux_native_read(encoder, 0x000, intel_dp->dpcd,
+                                    sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
+       {
+               if (intel_dp->dpcd[DP_DPCD_REV] != 0)
+                       status = connector_status_connected;
+       }
+       if (status == connector_status_connected)
+               DRM_DEBUG_KMS("DPCD: Rev=%x LN_Rate=%x LN_CNT=%x LN_DOWNSP=%x\n",
+                       intel_dp->dpcd[0], intel_dp->dpcd[1],
+                       intel_dp->dpcd[2], intel_dp->dpcd[3]);
+       return status;
+ }
+ /**
+  * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
+  *
+  * \return true if DP port is connected.
+  * \return false if DP port is disconnected.
+  */
+ static enum drm_connector_status
+ cdv_intel_dp_detect(struct drm_connector *connector, bool force)
+ {
+       struct psb_intel_encoder *encoder = psb_intel_attached_encoder(connector);
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       enum drm_connector_status status;
+       struct edid *edid = NULL;
+       int edp = is_edp(encoder);
+       intel_dp->has_audio = false;
+       if (edp)
+               cdv_intel_edp_panel_vdd_on(encoder);
+       status = cdv_dp_detect(encoder);
+       if (status != connector_status_connected) {
+               if (edp)
+                       cdv_intel_edp_panel_vdd_off(encoder);
+               return status;
+         }
+       if (intel_dp->force_audio) {
+               intel_dp->has_audio = intel_dp->force_audio > 0;
+       } else {
+               edid = drm_get_edid(connector, &intel_dp->adapter);
+               if (edid) {
+                       intel_dp->has_audio = drm_detect_monitor_audio(edid);
+                       kfree(edid);
+               }
+       }
+       if (edp)
+               cdv_intel_edp_panel_vdd_off(encoder);
+       return connector_status_connected;
+ }
+ static int cdv_intel_dp_get_modes(struct drm_connector *connector)
+ {
+       struct psb_intel_encoder *intel_encoder = psb_intel_attached_encoder(connector);
+       struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
+       struct edid *edid = NULL;
+       int ret = 0;
+       int edp = is_edp(intel_encoder);
+       edid = drm_get_edid(connector, &intel_dp->adapter);
+       if (edid) {
+               drm_mode_connector_update_edid_property(connector, edid);
+               ret = drm_add_edid_modes(connector, edid);
+               kfree(edid);
+       }
+       if (is_edp(intel_encoder)) {
+               struct drm_device *dev = connector->dev;
+               struct drm_psb_private *dev_priv = dev->dev_private;
+               
+               cdv_intel_edp_panel_vdd_off(intel_encoder);
+               if (ret) {
+                       if (edp && !intel_dp->panel_fixed_mode) {
+                               struct drm_display_mode *newmode;
+                               list_for_each_entry(newmode, &connector->probed_modes,
+                                           head) {
+                                       if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
+                                               intel_dp->panel_fixed_mode =
+                                                       drm_mode_duplicate(dev, newmode);
+                                               break;
+                                       }
+                               }
+                       }
+                       return ret;
+               }
+               if (!intel_dp->panel_fixed_mode && dev_priv->lfp_lvds_vbt_mode) {
+                       intel_dp->panel_fixed_mode =
+                               drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
+                       if (intel_dp->panel_fixed_mode) {
+                               intel_dp->panel_fixed_mode->type |=
+                                       DRM_MODE_TYPE_PREFERRED;
+                       }
+               }
+               if (intel_dp->panel_fixed_mode != NULL) {
+                       struct drm_display_mode *mode;
+                       mode = drm_mode_duplicate(dev, intel_dp->panel_fixed_mode);
+                       drm_mode_probed_add(connector, mode);
+                       return 1;
+               }
+       }
+       return ret;
+ }
+ static bool
+ cdv_intel_dp_detect_audio(struct drm_connector *connector)
+ {
+       struct psb_intel_encoder *encoder = psb_intel_attached_encoder(connector);
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       struct edid *edid;
+       bool has_audio = false;
+       int edp = is_edp(encoder);
+       if (edp)
+               cdv_intel_edp_panel_vdd_on(encoder);
+       edid = drm_get_edid(connector, &intel_dp->adapter);
+       if (edid) {
+               has_audio = drm_detect_monitor_audio(edid);
+               kfree(edid);
+       }
+       if (edp)
+               cdv_intel_edp_panel_vdd_off(encoder);
+       return has_audio;
+ }
+ static int
+ cdv_intel_dp_set_property(struct drm_connector *connector,
+                     struct drm_property *property,
+                     uint64_t val)
+ {
+       struct drm_psb_private *dev_priv = connector->dev->dev_private;
+       struct psb_intel_encoder *encoder = psb_intel_attached_encoder(connector);
+       struct cdv_intel_dp *intel_dp = encoder->dev_priv;
+       int ret;
+       ret = drm_connector_property_set_value(connector, property, val);
+       if (ret)
+               return ret;
+       if (property == dev_priv->force_audio_property) {
+               int i = val;
+               bool has_audio;
+               if (i == intel_dp->force_audio)
+                       return 0;
+               intel_dp->force_audio = i;
+               if (i == 0)
+                       has_audio = cdv_intel_dp_detect_audio(connector);
+               else
+                       has_audio = i > 0;
+               if (has_audio == intel_dp->has_audio)
+                       return 0;
+               intel_dp->has_audio = has_audio;
+               goto done;
+       }
+       if (property == dev_priv->broadcast_rgb_property) {
+               if (val == !!intel_dp->color_range)
+                       return 0;
+               intel_dp->color_range = val ? DP_COLOR_RANGE_16_235 : 0;
+               goto done;
+       }
+       return -EINVAL;
+ done:
+       if (encoder->base.crtc) {
+               struct drm_crtc *crtc = encoder->base.crtc;
+               drm_crtc_helper_set_mode(crtc, &crtc->mode,
+                                        crtc->x, crtc->y,
+                                        crtc->fb);
+       }
+       return 0;
+ }
+ static void
+ cdv_intel_dp_destroy(struct drm_connector *connector)
+ {
+       struct psb_intel_encoder *psb_intel_encoder =
+                                       psb_intel_attached_encoder(connector);
+       struct cdv_intel_dp *intel_dp = psb_intel_encoder->dev_priv;
+       if (is_edp(psb_intel_encoder)) {
+       /*      cdv_intel_panel_destroy_backlight(connector->dev); */
+               if (intel_dp->panel_fixed_mode) {
+                       kfree(intel_dp->panel_fixed_mode);
+                       intel_dp->panel_fixed_mode = NULL;
+               }
+       }
+       i2c_del_adapter(&intel_dp->adapter);
+       drm_sysfs_connector_remove(connector);
+       drm_connector_cleanup(connector);
+       kfree(connector);
+ }
+ static void cdv_intel_dp_encoder_destroy(struct drm_encoder *encoder)
+ {
+       drm_encoder_cleanup(encoder);
+ }
+ static const struct drm_encoder_helper_funcs cdv_intel_dp_helper_funcs = {
+       .dpms = cdv_intel_dp_dpms,
+       .mode_fixup = cdv_intel_dp_mode_fixup,
+       .prepare = cdv_intel_dp_prepare,
+       .mode_set = cdv_intel_dp_mode_set,
+       .commit = cdv_intel_dp_commit,
+ };
+ static const struct drm_connector_funcs cdv_intel_dp_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = cdv_intel_dp_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .set_property = cdv_intel_dp_set_property,
+       .destroy = cdv_intel_dp_destroy,
+ };
+ static const struct drm_connector_helper_funcs cdv_intel_dp_connector_helper_funcs = {
+       .get_modes = cdv_intel_dp_get_modes,
+       .mode_valid = cdv_intel_dp_mode_valid,
+       .best_encoder = psb_intel_best_encoder,
+ };
+ static const struct drm_encoder_funcs cdv_intel_dp_enc_funcs = {
+       .destroy = cdv_intel_dp_encoder_destroy,
+ };
+ static void cdv_intel_dp_add_properties(struct drm_connector *connector)
+ {
+       cdv_intel_attach_force_audio_property(connector);
+       cdv_intel_attach_broadcast_rgb_property(connector);
+ }
+ /* check the VBT to see whether the eDP is on DP-D port */
+ static bool cdv_intel_dpc_is_edp(struct drm_device *dev)
+ {
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct child_device_config *p_child;
+       int i;
+       if (!dev_priv->child_dev_num)
+               return false;
+       for (i = 0; i < dev_priv->child_dev_num; i++) {
+               p_child = dev_priv->child_dev + i;
+               if (p_child->dvo_port == PORT_IDPC &&
+                   p_child->device_type == DEVICE_TYPE_eDP)
+                       return true;
+       }
+       return false;
+ }
+ /* Cedarview display clock gating
+    We need this disable dot get correct behaviour while enabling
+    DP/eDP. TODO - investigate if we can turn it back to normality
+    after enabling */
+ static void cdv_disable_intel_clock_gating(struct drm_device *dev)
+ {
+       u32 reg_value;
+       reg_value = REG_READ(DSPCLK_GATE_D);
+       reg_value |= (DPUNIT_PIPEB_GATE_DISABLE |
+                       DPUNIT_PIPEA_GATE_DISABLE |
+                       DPCUNIT_CLOCK_GATE_DISABLE |
+                       DPLSUNIT_CLOCK_GATE_DISABLE |
+                       DPOUNIT_CLOCK_GATE_DISABLE |
+                       DPIOUNIT_CLOCK_GATE_DISABLE);   
+       REG_WRITE(DSPCLK_GATE_D, reg_value);
+       udelay(500);            
+ }
+ void
+ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev, int output_reg)
+ {
+       struct psb_intel_encoder *psb_intel_encoder;
+       struct psb_intel_connector *psb_intel_connector;
+       struct drm_connector *connector;
+       struct drm_encoder *encoder;
+       struct cdv_intel_dp *intel_dp;
+       const char *name = NULL;
+       int type = DRM_MODE_CONNECTOR_DisplayPort;
+       psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL);
+       if (!psb_intel_encoder)
+               return;
+         psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL);
+         if (!psb_intel_connector)
+                 goto err_connector;
+       intel_dp = kzalloc(sizeof(struct cdv_intel_dp), GFP_KERNEL);
+       if (!intel_dp)
+               goto err_priv;
+       if ((output_reg == DP_C) && cdv_intel_dpc_is_edp(dev))
+               type = DRM_MODE_CONNECTOR_eDP;
+       connector = &psb_intel_connector->base;
+       encoder = &psb_intel_encoder->base;
+       drm_connector_init(dev, connector, &cdv_intel_dp_connector_funcs, type);
+       drm_encoder_init(dev, encoder, &cdv_intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS);
+       psb_intel_connector_attach_encoder(psb_intel_connector, psb_intel_encoder);
+       if (type == DRM_MODE_CONNECTOR_DisplayPort)
+               psb_intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
+         else
+               psb_intel_encoder->type = INTEL_OUTPUT_EDP;
+       psb_intel_encoder->dev_priv=intel_dp;
+       intel_dp->encoder = psb_intel_encoder;
+       intel_dp->output_reg = output_reg;
+       
+       drm_encoder_helper_add(encoder, &cdv_intel_dp_helper_funcs);
+       drm_connector_helper_add(connector, &cdv_intel_dp_connector_helper_funcs);
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+       connector->interlace_allowed = false;
+       connector->doublescan_allowed = false;
+       drm_sysfs_connector_add(connector);
+       /* Set up the DDC bus. */
+       switch (output_reg) {
+               case DP_B:
+                       name = "DPDDC-B";
+                       psb_intel_encoder->ddi_select = (DP_MASK | DDI0_SELECT);
+                       break;
+               case DP_C:
+                       name = "DPDDC-C";
+                       psb_intel_encoder->ddi_select = (DP_MASK | DDI1_SELECT);
+                       break;
+       }
+       cdv_disable_intel_clock_gating(dev);
+       cdv_intel_dp_i2c_init(psb_intel_connector, psb_intel_encoder, name);
+         /* FIXME:fail check */
+       cdv_intel_dp_add_properties(connector);
+       if (is_edp(psb_intel_encoder)) {
+               int ret;
+               struct edp_power_seq cur;
+                 u32 pp_on, pp_off, pp_div;
+               u32 pwm_ctrl;
+               pp_on = REG_READ(PP_CONTROL);
+               pp_on &= ~PANEL_UNLOCK_MASK;
+               pp_on |= PANEL_UNLOCK_REGS;
+               
+               REG_WRITE(PP_CONTROL, pp_on);
+               pwm_ctrl = REG_READ(BLC_PWM_CTL2);
+               pwm_ctrl |= PWM_PIPE_B;
+               REG_WRITE(BLC_PWM_CTL2, pwm_ctrl);
+                 pp_on = REG_READ(PP_ON_DELAYS);
+                 pp_off = REG_READ(PP_OFF_DELAYS);
+                 pp_div = REG_READ(PP_DIVISOR);
+       
+               /* Pull timing values out of registers */
+                 cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >>
+                         PANEL_POWER_UP_DELAY_SHIFT;
+                 cur.t8 = (pp_on & PANEL_LIGHT_ON_DELAY_MASK) >>
+                         PANEL_LIGHT_ON_DELAY_SHIFT;
+                 cur.t9 = (pp_off & PANEL_LIGHT_OFF_DELAY_MASK) >>
+                         PANEL_LIGHT_OFF_DELAY_SHIFT;
+                 cur.t10 = (pp_off & PANEL_POWER_DOWN_DELAY_MASK) >>
+                         PANEL_POWER_DOWN_DELAY_SHIFT;
+                 cur.t11_t12 = ((pp_div & PANEL_POWER_CYCLE_DELAY_MASK) >>
+                                PANEL_POWER_CYCLE_DELAY_SHIFT);
+                 DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
+                               cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12);
+               intel_dp->panel_power_up_delay = cur.t1_t3 / 10;
+                 intel_dp->backlight_on_delay = cur.t8 / 10;
+                 intel_dp->backlight_off_delay = cur.t9 / 10;
+                 intel_dp->panel_power_down_delay = cur.t10 / 10;
+                 intel_dp->panel_power_cycle_delay = (cur.t11_t12 - 1) * 100;
+                 DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n",
+                               intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay,
+                               intel_dp->panel_power_cycle_delay);
+                 DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n",
+                               intel_dp->backlight_on_delay, intel_dp->backlight_off_delay);
+               cdv_intel_edp_panel_vdd_on(psb_intel_encoder);
+               ret = cdv_intel_dp_aux_native_read(psb_intel_encoder, DP_DPCD_REV,
+                                              intel_dp->dpcd,
+                                              sizeof(intel_dp->dpcd));
+               cdv_intel_edp_panel_vdd_off(psb_intel_encoder);
+               if (ret == 0) {
+                       /* if this fails, presume the device is a ghost */
+                       DRM_INFO("failed to retrieve link info, disabling eDP\n");
+                       cdv_intel_dp_encoder_destroy(encoder);
+                       cdv_intel_dp_destroy(connector);
+                       goto err_priv;
+               } else {
+                       DRM_DEBUG_KMS("DPCD: Rev=%x LN_Rate=%x LN_CNT=%x LN_DOWNSP=%x\n",
+                               intel_dp->dpcd[0], intel_dp->dpcd[1], 
+                               intel_dp->dpcd[2], intel_dp->dpcd[3]);
+                       
+               }
+               /* The CDV reference driver moves pnale backlight setup into the displays that
+                  have a backlight: this is a good idea and one we should probably adopt, however
+                  we need to migrate all the drivers before we can do that */
+                 /*cdv_intel_panel_setup_backlight(dev); */
+       }
+       return;
+ err_priv:
+       kfree(psb_intel_connector);
+ err_connector:
+       kfree(psb_intel_encoder);
+ }
@@@ -25,7 -25,7 +25,7 @@@
  
  #include <drm/drmP.h>
  #include <drm/drm.h>
 -#include "gma_drm.h"
 +#include <drm/gma_drm.h>
  #include "psb_drv.h"
  
  int psb_gem_init_object(struct drm_gem_object *obj)
  void psb_gem_free_object(struct drm_gem_object *obj)
  {
        struct gtt_range *gtt = container_of(obj, struct gtt_range, gem);
-       drm_gem_object_release_wrap(obj);
+       /* Remove the list map if one is present */
+       if (obj->map_list.map)
+               drm_gem_free_mmap_offset(obj);
+       drm_gem_object_release(obj);
        /* This must occur last as it frees up the memory of the GEM object */
        psb_gtt_free_range(obj->dev, gtt);
  }
@@@ -77,7 -82,7 +82,7 @@@ int psb_gem_dumb_map_gtt(struct drm_fil
  
        /* Make it mmapable */
        if (!obj->map_list.map) {
-               ret = gem_create_mmap_offset(obj);
+               ret = drm_gem_create_mmap_offset(obj);
                if (ret)
                        goto out;
        }
@@@ -20,7 -20,7 +20,7 @@@
   */
  #include <drm/drmP.h>
  #include <drm/drm.h>
 -#include "gma_drm.h"
 +#include <drm/gma_drm.h>
  #include "psb_drv.h"
  #include "psb_intel_drv.h"
  #include "psb_intel_reg.h"
@@@ -54,6 -54,98 +54,98 @@@ static void *find_section(struct bdb_he
        return NULL;
  }
  
+ static void
+ parse_edp(struct drm_psb_private *dev_priv, struct bdb_header *bdb)
+ {
+       struct bdb_edp *edp;
+       struct edp_power_seq *edp_pps;
+       struct edp_link_params *edp_link_params;
+       uint8_t panel_type;
+       edp = find_section(bdb, BDB_EDP);
+       
+       dev_priv->edp.bpp = 18;
+       if (!edp) {
+               if (dev_priv->edp.support) {
+                       DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported, assume %dbpp panel color depth.\n",
+                                     dev_priv->edp.bpp);
+               }
+               return;
+       }
+       panel_type = dev_priv->panel_type;
+       switch ((edp->color_depth >> (panel_type * 2)) & 3) {
+       case EDP_18BPP:
+               dev_priv->edp.bpp = 18;
+               break;
+       case EDP_24BPP:
+               dev_priv->edp.bpp = 24;
+               break;
+       case EDP_30BPP:
+               dev_priv->edp.bpp = 30;
+               break;
+       }
+       /* Get the eDP sequencing and link info */
+       edp_pps = &edp->power_seqs[panel_type];
+       edp_link_params = &edp->link_params[panel_type];
+       dev_priv->edp.pps = *edp_pps;
+       DRM_DEBUG_KMS("EDP timing in vbt t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
+                               dev_priv->edp.pps.t1_t3, dev_priv->edp.pps.t8, 
+                               dev_priv->edp.pps.t9, dev_priv->edp.pps.t10,
+                               dev_priv->edp.pps.t11_t12);
+       dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
+               DP_LINK_BW_1_62;
+       switch (edp_link_params->lanes) {
+       case 0:
+               dev_priv->edp.lanes = 1;
+               break;
+       case 1:
+               dev_priv->edp.lanes = 2;
+               break;
+       case 3:
+       default:
+               dev_priv->edp.lanes = 4;
+               break;
+       }
+       DRM_DEBUG_KMS("VBT reports EDP: Lane_count %d, Lane_rate %d, Bpp %d\n",
+                       dev_priv->edp.lanes, dev_priv->edp.rate, dev_priv->edp.bpp);
+       switch (edp_link_params->preemphasis) {
+       case 0:
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
+               break;
+       case 1:
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
+               break;
+       case 2:
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
+               break;
+       case 3:
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
+               break;
+       }
+       switch (edp_link_params->vswing) {
+       case 0:
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400;
+               break;
+       case 1:
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600;
+               break;
+       case 2:
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800;
+               break;
+       case 3:
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200;
+               break;
+       }
+       DRM_DEBUG_KMS("VBT reports EDP: VSwing  %d, Preemph %d\n",
+                       dev_priv->edp.vswing, dev_priv->edp.preemphasis);
+ }
  static u16
  get_blocksize(void *p)
  {
@@@ -154,6 -246,8 +246,8 @@@ static void parse_lfp_panel_data(struc
                return;
  
        dev_priv->lvds_dither = lvds_options->pixel_dither;
+       dev_priv->panel_type = lvds_options->panel_type;
        if (lvds_options->panel_type == 0xff)
                return;
  
@@@ -340,6 -434,9 +434,9 @@@ parse_driver_features(struct drm_psb_pr
        if (!driver)
                return;
  
+       if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
+               dev_priv->edp.support = 1;
        /* This bit means to use 96Mhz for DPLL_A or not */
        if (driver->primary_lfp_id)
                dev_priv->dplla_96mhz = true;
@@@ -437,6 -534,9 +534,9 @@@ int psb_intel_init_bios(struct drm_devi
        size_t size;
        int i;
  
+       dev_priv->panel_type = 0xff;
        /* XXX Should this validation be moved to intel_opregion.c? */
        if (dev_priv->opregion.vbt) {
                struct vbt_header *vbt = dev_priv->opregion.vbt;
        parse_sdvo_device_mapping(dev_priv, bdb);
        parse_device_mapping(dev_priv, bdb);
        parse_backlight_data(dev_priv, bdb);
+       parse_edp(dev_priv, bdb);
  
        if (bios)
                pci_unmap_rom(pdev, bios);
@@@ -25,7 -25,7 +25,7 @@@
  
  #include <drm/drmP.h>
  #include <drm/drm.h>
 -#include "gma_drm.h"
 +#include <drm/gma_drm.h>
  #include "psb_drv.h"
  #include "mid_bios.h"
  
@@@ -118,20 -118,20 +118,20 @@@ static void mid_get_pci_revID(struct dr
                                        dev_priv->platform_rev_id);
  }
  
- struct vbt_header {
+ struct mid_vbt_header {
        u32 signature;
        u8 revision;
  } __packed;
  
  /* The same for r0 and r1 */
  struct vbt_r0 {
-       struct vbt_header vbt_header;
+       struct mid_vbt_header vbt_header;
        u8 size;
        u8 checksum;
  } __packed;
  
  struct vbt_r10 {
-       struct vbt_header vbt_header;
+       struct mid_vbt_header vbt_header;
        u8 checksum;
        u16 size;
        u8 panel_count;
@@@ -281,7 -281,7 +281,7 @@@ static void mid_get_vbt_data(struct drm
        struct drm_device *dev = dev_priv->dev;
        u32 addr;
        u8 __iomem *vbt_virtual;
-       struct vbt_header vbt_header;
+       struct mid_vbt_header vbt_header;
        struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0));
        int ret = -1;
  
@@@ -20,7 -20,7 +20,7 @@@
  #include <linux/backlight.h>
  #include <drm/drmP.h>
  #include <drm/drm.h>
 -#include "gma_drm.h"
 +#include <drm/gma_drm.h>
  #include "psb_drv.h"
  #include "psb_reg.h"
  #include "psb_intel_reg.h"
@@@ -290,6 -290,7 +290,7 @@@ static void psb_get_core_freq(struct dr
        case 6:
        case 7:
                dev_priv->core_freq = 266;
+               break;
        default:
                dev_priv->core_freq = 0;
        }
  #include <linux/kref.h>
  
  #include <drm/drmP.h>
 -#include "drm_global.h"
 -#include "gma_drm.h"
 +#include <drm/drm_global.h>
- #include "gem_glue.h"
 +#include <drm/gma_drm.h>
  #include "psb_reg.h"
  #include "psb_intel_drv.h"
+ #include "intel_bios.h"
  #include "gtt.h"
  #include "power.h"
  #include "opregion.h"
@@@ -613,6 -613,8 +613,8 @@@ struct drm_psb_private 
         */
        struct backlight_device *backlight_device;
        struct drm_property *backlight_property;
+       bool backlight_enabled;
+       int backlight_level;
        uint32_t blc_adj1;
        uint32_t blc_adj2;
  
        int mdfld_panel_id;
  
        bool dplla_96mhz;       /* DPLL data from the VBT */
+       struct {
+               int rate;
+               int lanes;
+               int preemphasis;
+               int vswing;
+               bool initialized;
+               bool support;
+               int bpp;
+               struct edp_power_seq pps;
+       } edp;
+       uint8_t panel_type;
  };
  
  
@@@ -796,6 -811,9 +811,9 @@@ extern int psb_fbdev_init(struct drm_de
  /* backlight.c */
  int gma_backlight_init(struct drm_device *dev);
  void gma_backlight_exit(struct drm_device *dev);
+ void gma_backlight_disable(struct drm_device *dev);
+ void gma_backlight_enable(struct drm_device *dev);
+ void gma_backlight_set(struct drm_device *dev, int v);
  
  /* oaktrail_crtc.c */
  extern const struct drm_crtc_helper_funcs oaktrail_helper_funcs;
  #include <linux/i2c.h>
  #include <linux/slab.h>
  #include <linux/delay.h>
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 -#include "drm_edid.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_edid.h>
  #include "psb_intel_drv.h"
 -#include "gma_drm.h"
 +#include <drm/gma_drm.h>
  #include "psb_drv.h"
  #include "psb_intel_sdvo_regs.h"
  #include "psb_intel_reg.h"
@@@ -1291,7 -1292,6 +1291,6 @@@ psb_intel_sdvo_get_analog_edid(struct d
  
        return drm_get_edid(connector,
                            &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
-       return NULL;
  }
  
  static enum drm_connector_status
@@@ -1342,7 -1342,6 +1341,6 @@@ psb_intel_sdvo_hdmi_sink_detect(struct 
                        }
                } else
                        status = connector_status_disconnected;
-               connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
  
@@@ -1403,7 -1402,6 +1401,6 @@@ psb_intel_sdvo_detect(struct drm_connec
                                ret = connector_status_disconnected;
                        else
                                ret = connector_status_connected;
-                       connector->display_info.raw_edid = NULL;
                        kfree(edid);
                } else
                        ret = connector_status_connected;
@@@ -1452,7 -1450,6 +1449,6 @@@ static void psb_intel_sdvo_get_ddc_mode
                        drm_add_edid_modes(connector, edid);
                }
  
-               connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
  }
@@@ -24,8 -24,9 +24,8 @@@
  #define _INTEL_DVO_H
  
  #include <linux/i2c.h>
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
  #include "intel_drv.h"
  
  struct intel_dvo_device {
@@@ -57,13 -58,12 +57,12 @@@ struct intel_dvo_dev_ops 
        void (*create_resources)(struct intel_dvo_device *dvo);
  
        /*
-        * Turn on/off output or set intermediate power levels if available.
+        * Turn on/off output.
         *
-        * Unsupported intermediate modes drop to the lower power setting.
-        * If the  mode is DPMSModeOff, the output must be disabled,
-        * as the DPLL may be disabled afterwards.
+        * Because none of our dvo drivers support an intermediate power levels,
+        * we don't expose this in the interfac.
         */
-       void (*dpms)(struct intel_dvo_device *dvo, int mode);
+       void (*dpms)(struct intel_dvo_device *dvo, bool enable);
  
        /*
         * Callback for testing a video mode for a given output.
         */
        enum drm_connector_status (*detect)(struct intel_dvo_device *dvo);
  
+       /*
+        * Probe the current hw status, returning true if the connected output
+        * is active.
+        */
+       bool (*get_hw_state)(struct intel_dvo_device *dev);
        /**
         * Query the device for the modes it provides.
         *
@@@ -139,5 -145,6 +144,6 @@@ extern struct intel_dvo_dev_ops ch7xxx_
  extern struct intel_dvo_dev_ops ivch_ops;
  extern struct intel_dvo_dev_ops tfp410_ops;
  extern struct intel_dvo_dev_ops ch7017_ops;
+ extern struct intel_dvo_dev_ops ns2501_ops;
  
  #endif /* _INTEL_DVO_H */
  #include <linux/debugfs.h>
  #include <linux/slab.h>
  #include <linux/export.h>
 -#include "drmP.h"
 -#include "drm.h"
 +#include <drm/drmP.h>
  #include "intel_drv.h"
  #include "intel_ringbuffer.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  
  #define DRM_I915_RING_DEBUG 1
@@@ -43,7 -44,6 +43,6 @@@
  
  enum {
        ACTIVE_LIST,
-       FLUSHING_LIST,
        INACTIVE_LIST,
        PINNED_LIST,
  };
@@@ -61,28 -61,11 +60,11 @@@ static int i915_capabilities(struct seq
  
        seq_printf(m, "gen: %d\n", info->gen);
        seq_printf(m, "pch: %d\n", INTEL_PCH_TYPE(dev));
- #define B(x) seq_printf(m, #x ": %s\n", yesno(info->x))
-       B(is_mobile);
-       B(is_i85x);
-       B(is_i915g);
-       B(is_i945gm);
-       B(is_g33);
-       B(need_gfx_hws);
-       B(is_g4x);
-       B(is_pineview);
-       B(is_broadwater);
-       B(is_crestline);
-       B(has_fbc);
-       B(has_pipe_cxsr);
-       B(has_hotplug);
-       B(cursor_needs_physical);
-       B(has_overlay);
-       B(overlay_needs_physical);
-       B(supports_tv);
-       B(has_bsd_ring);
-       B(has_blt_ring);
-       B(has_llc);
- #undef B
+ #define DEV_INFO_FLAG(x) seq_printf(m, #x ": %s\n", yesno(info->x))
+ #define DEV_INFO_SEP ;
+       DEV_INFO_FLAGS;
+ #undef DEV_INFO_FLAG
+ #undef DEV_INFO_SEP
  
        return 0;
  }
@@@ -120,20 -103,23 +102,23 @@@ static const char *cache_level_str(int 
  static void
  describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
  {
-       seq_printf(m, "%p: %s%s %8zdKiB %04x %04x %d %d%s%s%s",
+       seq_printf(m, "%p: %s%s %8zdKiB %04x %04x %d %d %d%s%s%s",
                   &obj->base,
                   get_pin_flag(obj),
                   get_tiling_flag(obj),
                   obj->base.size / 1024,
                   obj->base.read_domains,
                   obj->base.write_domain,
-                  obj->last_rendering_seqno,
+                  obj->last_read_seqno,
+                  obj->last_write_seqno,
                   obj->last_fenced_seqno,
                   cache_level_str(obj->cache_level),
                   obj->dirty ? " dirty" : "",
                   obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
        if (obj->base.name)
                seq_printf(m, " (name: %d)", obj->base.name);
+       if (obj->pin_count)
+               seq_printf(m, " (pinned x %d)", obj->pin_count);
        if (obj->fence_reg != I915_FENCE_REG_NONE)
                seq_printf(m, " (fence: %d)", obj->fence_reg);
        if (obj->gtt_space != NULL)
@@@ -176,10 -162,6 +161,6 @@@ static int i915_gem_object_list_info(st
                seq_printf(m, "Inactive:\n");
                head = &dev_priv->mm.inactive_list;
                break;
-       case FLUSHING_LIST:
-               seq_printf(m, "Flushing:\n");
-               head = &dev_priv->mm.flushing_list;
-               break;
        default:
                mutex_unlock(&dev->struct_mutex);
                return -EINVAL;
@@@ -217,8 -199,8 +198,8 @@@ static int i915_gem_object_info(struct 
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 count, mappable_count;
-       size_t size, mappable_size;
+       u32 count, mappable_count, purgeable_count;
+       size_t size, mappable_size, purgeable_size;
        struct drm_i915_gem_object *obj;
        int ret;
  
                   dev_priv->mm.object_memory);
  
        size = count = mappable_size = mappable_count = 0;
-       count_objects(&dev_priv->mm.gtt_list, gtt_list);
+       count_objects(&dev_priv->mm.bound_list, gtt_list);
        seq_printf(m, "%u [%u] objects, %zu [%zu] bytes in gtt\n",
                   count, mappable_count, size, mappable_size);
  
        size = count = mappable_size = mappable_count = 0;
        count_objects(&dev_priv->mm.active_list, mm_list);
-       count_objects(&dev_priv->mm.flushing_list, mm_list);
        seq_printf(m, "  %u [%u] active objects, %zu [%zu] bytes\n",
                   count, mappable_count, size, mappable_size);
  
        seq_printf(m, "  %u [%u] inactive objects, %zu [%zu] bytes\n",
                   count, mappable_count, size, mappable_size);
  
+       size = count = purgeable_size = purgeable_count = 0;
+       list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list) {
+               size += obj->base.size, ++count;
+               if (obj->madv == I915_MADV_DONTNEED)
+                       purgeable_size += obj->base.size, ++purgeable_count;
+       }
+       seq_printf(m, "%u unbound objects, %zu bytes\n", count, size);
        size = count = mappable_size = mappable_count = 0;
-       list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
                if (obj->fault_mappable) {
                        size += obj->gtt_space->size;
                        ++count;
                        mappable_size += obj->gtt_space->size;
                        ++mappable_count;
                }
+               if (obj->madv == I915_MADV_DONTNEED) {
+                       purgeable_size += obj->base.size;
+                       ++purgeable_count;
+               }
        }
+       seq_printf(m, "%u purgeable objects, %zu bytes\n",
+                  purgeable_count, purgeable_size);
        seq_printf(m, "%u pinned mappable objects, %zu bytes\n",
                   mappable_count, mappable_size);
        seq_printf(m, "%u fault mappable objects, %zu bytes\n",
@@@ -285,7 -280,7 +279,7 @@@ static int i915_gem_gtt_info(struct seq
                return ret;
  
        total_obj_size = total_gtt_size = count = 0;
-       list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
                if (list == PINNED_LIST && obj->pin_count == 0)
                        continue;
  
@@@ -358,40 -353,22 +352,22 @@@ static int i915_gem_request_info(struc
        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;
+       struct intel_ring_buffer *ring;
        struct drm_i915_gem_request *gem_request;
-       int ret, count;
+       int ret, count, i;
  
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
  
        count = 0;
-       if (!list_empty(&dev_priv->ring[RCS].request_list)) {
-               seq_printf(m, "Render requests:\n");
-               list_for_each_entry(gem_request,
-                                   &dev_priv->ring[RCS].request_list,
-                                   list) {
-                       seq_printf(m, "    %d @ %d\n",
-                                  gem_request->seqno,
-                                  (int) (jiffies - gem_request->emitted_jiffies));
-               }
-               count++;
-       }
-       if (!list_empty(&dev_priv->ring[VCS].request_list)) {
-               seq_printf(m, "BSD requests:\n");
-               list_for_each_entry(gem_request,
-                                   &dev_priv->ring[VCS].request_list,
-                                   list) {
-                       seq_printf(m, "    %d @ %d\n",
-                                  gem_request->seqno,
-                                  (int) (jiffies - gem_request->emitted_jiffies));
-               }
-               count++;
-       }
-       if (!list_empty(&dev_priv->ring[BCS].request_list)) {
-               seq_printf(m, "BLT requests:\n");
+       for_each_ring(ring, dev_priv, i) {
+               if (list_empty(&ring->request_list))
+                       continue;
+               seq_printf(m, "%s requests:\n", ring->name);
                list_for_each_entry(gem_request,
-                                   &dev_priv->ring[BCS].request_list,
+                                   &ring->request_list,
                                    list) {
                        seq_printf(m, "    %d @ %d\n",
                                   gem_request->seqno,
@@@ -412,7 -389,7 +388,7 @@@ static void i915_ring_seqno_info(struc
  {
        if (ring->get_seqno) {
                seq_printf(m, "Current sequence (%s): %d\n",
-                          ring->name, ring->get_seqno(ring));
+                          ring->name, ring->get_seqno(ring, false));
        }
  }
  
@@@ -421,14 -398,15 +397,15 @@@ static int i915_gem_seqno_info(struct s
        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;
+       struct intel_ring_buffer *ring;
        int ret, i;
  
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
  
-       for (i = 0; i < I915_NUM_RINGS; i++)
-               i915_ring_seqno_info(m, &dev_priv->ring[i]);
+       for_each_ring(ring, dev_priv, i)
+               i915_ring_seqno_info(m, ring);
  
        mutex_unlock(&dev->struct_mutex);
  
@@@ -441,6 -419,7 +418,7 @@@ static int i915_interrupt_info(struct s
        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;
+       struct intel_ring_buffer *ring;
        int ret, i, pipe;
  
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        }
        seq_printf(m, "Interrupts received: %d\n",
                   atomic_read(&dev_priv->irq_received));
-       for (i = 0; i < I915_NUM_RINGS; i++) {
+       for_each_ring(ring, dev_priv, i) {
                if (IS_GEN6(dev) || IS_GEN7(dev)) {
-                       seq_printf(m, "Graphics Interrupt mask (%s):    %08x\n",
-                                  dev_priv->ring[i].name,
-                                  I915_READ_IMR(&dev_priv->ring[i]));
+                       seq_printf(m,
+                                  "Graphics Interrupt mask (%s):       %08x\n",
+                                  ring->name, I915_READ_IMR(ring));
                }
-               i915_ring_seqno_info(m, &dev_priv->ring[i]);
+               i915_ring_seqno_info(m, ring);
        }
        mutex_unlock(&dev->struct_mutex);
  
@@@ -547,7 -526,8 +525,8 @@@ static int i915_gem_fence_regs_info(str
        for (i = 0; i < dev_priv->num_fence_regs; i++) {
                struct drm_i915_gem_object *obj = dev_priv->fence_regs[i].obj;
  
-               seq_printf(m, "Fenced object[%2d] = ", i);
+               seq_printf(m, "Fence %d, pin count = %d, object = ",
+                          i, dev_priv->fence_regs[i].pin_count);
                if (obj == NULL)
                        seq_printf(m, "unused");
                else
@@@ -629,12 -609,12 +608,12 @@@ static void print_error_buffers(struct 
        seq_printf(m, "%s [%d]:\n", name, count);
  
        while (count--) {
-               seq_printf(m, "  %08x %8u %04x %04x %08x%s%s%s%s%s%s%s",
+               seq_printf(m, "  %08x %8u %04x %04x %x %x%s%s%s%s%s%s%s",
                           err->gtt_offset,
                           err->size,
                           err->read_domains,
                           err->write_domain,
-                          err->seqno,
+                          err->rseqno, err->wseqno,
                           pin_flag(err->pinned),
                           tiling_flag(err->tiling),
                           dirty_flag(err->dirty),
@@@ -666,10 -646,9 +645,9 @@@ static void i915_ring_error_state(struc
        seq_printf(m, "  IPEIR: 0x%08x\n", error->ipeir[ring]);
        seq_printf(m, "  IPEHR: 0x%08x\n", error->ipehr[ring]);
        seq_printf(m, "  INSTDONE: 0x%08x\n", error->instdone[ring]);
-       if (ring == RCS && INTEL_INFO(dev)->gen >= 4) {
-               seq_printf(m, "  INSTDONE1: 0x%08x\n", error->instdone1);
+       if (ring == RCS && INTEL_INFO(dev)->gen >= 4)
                seq_printf(m, "  BBADDR: 0x%08llx\n", error->bbaddr);
-       }
        if (INTEL_INFO(dev)->gen >= 4)
                seq_printf(m, "  INSTPS: 0x%08x\n", error->instps[ring]);
        seq_printf(m, "  INSTPM: 0x%08x\n", error->instpm[ring]);
@@@ -718,11 -697,17 +696,17 @@@ static int i915_error_state(struct seq_
        for (i = 0; i < dev_priv->num_fence_regs; i++)
                seq_printf(m, "  fence[%d] = %08llx\n", i, error->fence[i]);
  
+       for (i = 0; i < ARRAY_SIZE(error->extra_instdone); i++)
+               seq_printf(m, "  INSTDONE_%d: 0x%08x\n", i, error->extra_instdone[i]);
        if (INTEL_INFO(dev)->gen >= 6) {
                seq_printf(m, "ERROR: 0x%08x\n", error->error);
                seq_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
        }
  
+       if (INTEL_INFO(dev)->gen == 7)
+               seq_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
        for_each_ring(ring, dev_priv, i)
                i915_ring_error_state(m, dev, error, i);
  
@@@ -798,10 -783,14 +782,14 @@@ i915_error_state_write(struct file *fil
        struct seq_file *m = filp->private_data;
        struct i915_error_state_file_priv *error_priv = m->private;
        struct drm_device *dev = error_priv->dev;
+       int ret;
  
        DRM_DEBUG_DRIVER("Resetting error state\n");
  
-       mutex_lock(&dev->struct_mutex);
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
        i915_destroy_error_state(dev);
        mutex_unlock(&dev->struct_mutex);
  
@@@ -925,7 -914,7 +913,7 @@@ static int i915_cur_delayinfo(struct se
                seq_printf(m, "Render p-state limit: %d\n",
                           rp_state_limits & 0xff);
                seq_printf(m, "CAGF: %dMHz\n", ((rpstat & GEN6_CAGF_MASK) >>
-                                               GEN6_CAGF_SHIFT) * 50);
+                                               GEN6_CAGF_SHIFT) * GT_FREQUENCY_MULTIPLIER);
                seq_printf(m, "RP CUR UP EI: %dus\n", rpupei &
                           GEN6_CURICONT_MASK);
                seq_printf(m, "RP CUR UP: %dus\n", rpcurup &
  
                max_freq = (rp_state_cap & 0xff0000) >> 16;
                seq_printf(m, "Lowest (RPN) frequency: %dMHz\n",
-                          max_freq * 50);
+                          max_freq * GT_FREQUENCY_MULTIPLIER);
  
                max_freq = (rp_state_cap & 0xff00) >> 8;
                seq_printf(m, "Nominal (RP1) frequency: %dMHz\n",
-                          max_freq * 50);
+                          max_freq * GT_FREQUENCY_MULTIPLIER);
  
                max_freq = rp_state_cap & 0xff;
                seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
-                          max_freq * 50);
+                          max_freq * GT_FREQUENCY_MULTIPLIER);
        } else {
                seq_printf(m, "no P-state info available\n");
        }
@@@ -1291,7 -1280,8 +1279,8 @@@ static int i915_ring_freq_table(struct 
  
        seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\n");
  
-       for (gpu_freq = dev_priv->min_delay; gpu_freq <= dev_priv->max_delay;
+       for (gpu_freq = dev_priv->rps.min_delay;
+            gpu_freq <= dev_priv->rps.max_delay;
             gpu_freq++) {
                I915_WRITE(GEN6_PCODE_DATA, gpu_freq);
                I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
                        continue;
                }
                ia_freq = I915_READ(GEN6_PCODE_DATA);
-               seq_printf(m, "%d\t\t%d\n", gpu_freq * 50, ia_freq * 100);
+               seq_printf(m, "%d\t\t%d\n", gpu_freq * GT_FREQUENCY_MULTIPLIER, ia_freq * 100);
        }
  
        mutex_unlock(&dev->struct_mutex);
@@@ -1471,8 -1461,12 +1460,12 @@@ static int i915_swizzle_info(struct seq
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
  
-       mutex_lock(&dev->struct_mutex);
        seq_printf(m, "bit6 swizzle for X-tiling = %s\n",
                   swizzle_string(dev_priv->mm.bit_6_swizzle_x));
        seq_printf(m, "bit6 swizzle for Y-tiling = %s\n",
@@@ -1519,9 -1513,7 +1512,7 @@@ static int i915_ppgtt_info(struct seq_f
        if (INTEL_INFO(dev)->gen == 6)
                seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(GFX_MODE));
  
-       for (i = 0; i < I915_NUM_RINGS; i++) {
-               ring = &dev_priv->ring[i];
+       for_each_ring(ring, dev_priv, i) {
                seq_printf(m, "%s\n", ring->name);
                if (INTEL_INFO(dev)->gen == 7)
                        seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(RING_MODE_GEN7(ring)));
@@@ -1673,7 -1665,7 +1664,7 @@@ i915_ring_stop_write(struct file *filp
        struct drm_device *dev = filp->private_data;
        struct drm_i915_private *dev_priv = dev->dev_private;
        char buf[20];
-       int val = 0;
+       int val = 0, ret;
  
        if (cnt > 0) {
                if (cnt > sizeof(buf) - 1)
  
        DRM_DEBUG_DRIVER("Stopping rings 0x%08x\n", val);
  
-       mutex_lock(&dev->struct_mutex);
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
        dev_priv->stop_rings = val;
        mutex_unlock(&dev->struct_mutex);
  
@@@ -1712,10 -1707,18 +1706,18 @@@ i915_max_freq_read(struct file *filp
        struct drm_device *dev = filp->private_data;
        drm_i915_private_t *dev_priv = dev->dev_private;
        char buf[80];
-       int len;
+       int len, ret;
+       if (!(IS_GEN6(dev) || IS_GEN7(dev)))
+               return -ENODEV;
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
  
        len = snprintf(buf, sizeof(buf),
-                      "max freq: %d\n", dev_priv->max_delay * 50);
+                      "max freq: %d\n", dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER);
+       mutex_unlock(&dev->struct_mutex);
  
        if (len > sizeof(buf))
                len = sizeof(buf);
@@@ -1732,7 -1735,10 +1734,10 @@@ i915_max_freq_write(struct file *filp
        struct drm_device *dev = filp->private_data;
        struct drm_i915_private *dev_priv = dev->dev_private;
        char buf[20];
-       int val = 1;
+       int val = 1, ret;
+       if (!(IS_GEN6(dev) || IS_GEN7(dev)))
+               return -ENODEV;
  
        if (cnt > 0) {
                if (cnt > sizeof(buf) - 1)
  
        DRM_DEBUG_DRIVER("Manually setting max freq to %d\n", val);
  
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
        /*
         * Turbo will still be enabled, but won't go above the set value.
         */
-       dev_priv->max_delay = val / 50;
+       dev_priv->rps.max_delay = val / GT_FREQUENCY_MULTIPLIER;
  
-       gen6_set_rps(dev, val / 50);
+       gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER);
+       mutex_unlock(&dev->struct_mutex);
  
        return cnt;
  }
@@@ -1772,10 -1783,18 +1782,18 @@@ i915_min_freq_read(struct file *filp, c
        struct drm_device *dev = filp->private_data;
        drm_i915_private_t *dev_priv = dev->dev_private;
        char buf[80];
-       int len;
+       int len, ret;
+       if (!(IS_GEN6(dev) || IS_GEN7(dev)))
+               return -ENODEV;
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
  
        len = snprintf(buf, sizeof(buf),
-                      "min freq: %d\n", dev_priv->min_delay * 50);
+                      "min freq: %d\n", dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER);
+       mutex_unlock(&dev->struct_mutex);
  
        if (len > sizeof(buf))
                len = sizeof(buf);
@@@ -1790,7 -1809,10 +1808,10 @@@ i915_min_freq_write(struct file *filp, 
        struct drm_device *dev = filp->private_data;
        struct drm_i915_private *dev_priv = dev->dev_private;
        char buf[20];
-       int val = 1;
+       int val = 1, ret;
+       if (!(IS_GEN6(dev) || IS_GEN7(dev)))
+               return -ENODEV;
  
        if (cnt > 0) {
                if (cnt > sizeof(buf) - 1)
  
        DRM_DEBUG_DRIVER("Manually setting min freq to %d\n", val);
  
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
        /*
         * Turbo will still be enabled, but won't go below the set value.
         */
-       dev_priv->min_delay = val / 50;
+       dev_priv->rps.min_delay = val / GT_FREQUENCY_MULTIPLIER;
  
-       gen6_set_rps(dev, val / 50);
+       gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER);
+       mutex_unlock(&dev->struct_mutex);
  
        return cnt;
  }
@@@ -1833,9 -1860,15 +1859,15 @@@ i915_cache_sharing_read(struct file *fi
        drm_i915_private_t *dev_priv = dev->dev_private;
        char buf[80];
        u32 snpcr;
-       int len;
+       int len, ret;
+       if (!(IS_GEN6(dev) || IS_GEN7(dev)))
+               return -ENODEV;
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
  
-       mutex_lock(&dev_priv->dev->struct_mutex);
        snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
        mutex_unlock(&dev_priv->dev->struct_mutex);
  
@@@ -1861,6 -1894,9 +1893,9 @@@ i915_cache_sharing_write(struct file *f
        u32 snpcr;
        int val = 1;
  
+       if (!(IS_GEN6(dev) || IS_GEN7(dev)))
+               return -ENODEV;
        if (cnt > 0) {
                if (cnt > sizeof(buf) - 1)
                        return -EINVAL;
@@@ -1924,16 -1960,11 +1959,11 @@@ static int i915_forcewake_open(struct i
  {
        struct drm_device *dev = inode->i_private;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret;
  
        if (INTEL_INFO(dev)->gen < 6)
                return 0;
  
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
-       if (ret)
-               return ret;
        gen6_gt_force_wake_get(dev_priv);
-       mutex_unlock(&dev->struct_mutex);
  
        return 0;
  }
@@@ -1946,16 -1977,7 +1976,7 @@@ static int i915_forcewake_release(struc
        if (INTEL_INFO(dev)->gen < 6)
                return 0;
  
-       /*
-        * It's bad that we can potentially hang userspace if struct_mutex gets
-        * forever stuck.  However, if we cannot acquire this lock it means that
-        * almost certainly the driver has hung, is not unload-able. Therefore
-        * hanging here is probably a minor inconvenience not to be seen my
-        * almost every user.
-        */
-       mutex_lock(&dev->struct_mutex);
        gen6_gt_force_wake_put(dev_priv);
-       mutex_unlock(&dev->struct_mutex);
  
        return 0;
  }
@@@ -2005,7 -2027,6 +2026,6 @@@ static struct drm_info_list i915_debugf
        {"i915_gem_gtt", i915_gem_gtt_info, 0},
        {"i915_gem_pinned", i915_gem_gtt_info, 0, (void *) PINNED_LIST},
        {"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},
        {"i915_gem_pageflip", i915_gem_pageflip_info, 0},
        {"i915_gem_request", i915_gem_request_info, 0},
@@@ -2066,6 -2087,7 +2086,7 @@@ int i915_debugfs_init(struct drm_minor 
                                  &i915_cache_sharing_fops);
        if (ret)
                return ret;
        ret = i915_debugfs_create(minor->debugfs_root, minor,
                                  "i915_ring_stop",
                                  &i915_ring_stop_fops);
  
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc_helper.h"
 -#include "drm_fb_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/drm_fb_helper.h>
  #include "intel_drv.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "i915_trace.h"
  #include <linux/pci.h>
@@@ -234,10 -235,10 +234,10 @@@ static int i915_initialize(struct drm_d
                }
        }
  
-       dev_priv->cpp = init->cpp;
-       dev_priv->back_offset = init->back_offset;
-       dev_priv->front_offset = init->front_offset;
-       dev_priv->current_page = 0;
+       dev_priv->dri1.cpp = init->cpp;
+       dev_priv->dri1.back_offset = init->back_offset;
+       dev_priv->dri1.front_offset = init->front_offset;
+       dev_priv->dri1.current_page = 0;
        if (master_priv->sarea_priv)
                master_priv->sarea_priv->pf_current_page = 0;
  
@@@ -574,7 -575,7 +574,7 @@@ static int i915_dispatch_flip(struct dr
  
        DRM_DEBUG_DRIVER("%s: page=%d pfCurrentPage=%d\n",
                          __func__,
-                        dev_priv->current_page,
+                        dev_priv->dri1.current_page,
                         master_priv->sarea_priv->pf_current_page);
  
        i915_kernel_lost_context(dev);
  
        OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP);
        OUT_RING(0);
-       if (dev_priv->current_page == 0) {
-               OUT_RING(dev_priv->back_offset);
-               dev_priv->current_page = 1;
+       if (dev_priv->dri1.current_page == 0) {
+               OUT_RING(dev_priv->dri1.back_offset);
+               dev_priv->dri1.current_page = 1;
        } else {
-               OUT_RING(dev_priv->front_offset);
-               dev_priv->current_page = 0;
+               OUT_RING(dev_priv->dri1.front_offset);
+               dev_priv->dri1.current_page = 0;
        }
        OUT_RING(0);
  
                ADVANCE_LP_RING();
        }
  
-       master_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+       master_priv->sarea_priv->pf_current_page = dev_priv->dri1.current_page;
        return 0;
  }
  
@@@ -1008,6 -1009,12 +1008,12 @@@ static int i915_getparam(struct drm_dev
        case I915_PARAM_HAS_WAIT_TIMEOUT:
                value = 1;
                break;
+       case I915_PARAM_HAS_SEMAPHORES:
+               value = i915_semaphore_is_enabled(dev);
+               break;
+       case I915_PARAM_HAS_PRIME_VMAP_FLUSH:
+               value = 1;
+               break;
        default:
                DRM_DEBUG_DRIVER("Unknown parameter %d\n",
                                 param->param);
@@@ -1424,6 -1431,21 +1430,21 @@@ static void i915_kick_out_firmware_fb(s
        kfree(ap);
  }
  
+ static void i915_dump_device_info(struct drm_i915_private *dev_priv)
+ {
+       const struct intel_device_info *info = dev_priv->info;
+ #define DEV_INFO_FLAG(name) info->name ? #name "," : ""
+ #define DEV_INFO_SEP ,
+       DRM_DEBUG_DRIVER("i915 device info: gen=%i, pciid=0x%04x flags="
+                        "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+                        info->gen,
+                        dev_priv->dev->pdev->device,
+                        DEV_INFO_FLAGS);
+ #undef DEV_INFO_FLAG
+ #undef DEV_INFO_SEP
+ }
  /**
   * i915_driver_load - setup chip and create an initial config
   * @dev: DRM device
@@@ -1439,7 -1461,7 +1460,7 @@@ int i915_driver_load(struct drm_device 
  {
        struct drm_i915_private *dev_priv;
        struct intel_device_info *info;
-       int ret = 0, mmio_bar;
+       int ret = 0, mmio_bar, mmio_size;
        uint32_t aperture_size;
  
        info = (struct intel_device_info *) flags;
        if (info->gen >= 6 && !drm_core_check_feature(dev, DRIVER_MODESET))
                return -ENODEV;
  
        /* i915 has 4 more counters */
        dev->counters += 4;
        dev->types[6] = _DRM_STAT_IRQ;
        dev_priv->dev = dev;
        dev_priv->info = info;
  
+       i915_dump_device_info(dev_priv);
        if (i915_get_bridge_dev(dev)) {
                ret = -EIO;
                goto free_priv;
                dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32));
  
        mmio_bar = IS_GEN2(dev) ? 1 : 0;
-       dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, 0);
+       /* Before gen4, the registers and the GTT are behind different BARs.
+        * However, from gen4 onwards, the registers and the GTT are shared
+        * in the same BAR, so we want to restrict this ioremap from
+        * clobbering the GTT which we want ioremap_wc instead. Fortunately,
+        * the register BAR remains the same size for all the earlier
+        * generations up to Ironlake.
+        */
+       if (info->gen < 5)
+               mmio_size = 512*1024;
+       else
+               mmio_size = 2*1024*1024;
+       dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size);
        if (!dev_priv->regs) {
                DRM_ERROR("failed to map registers\n");
                ret = -EIO;
         *
         * All tasks on the workqueue are expected to acquire the dev mutex
         * so there is no point in running more than one instance of the
-        * workqueue at any time: max_active = 1 and NON_REENTRANT.
+        * workqueue at any time.  Use an ordered one.
         */
-       dev_priv->wq = alloc_workqueue("i915",
-                                      WQ_UNBOUND | WQ_NON_REENTRANT,
-                                      1);
+       dev_priv->wq = alloc_ordered_workqueue("i915", 0);
        if (dev_priv->wq == NULL) {
                DRM_ERROR("Failed to create our workqueue.\n");
                ret = -ENOMEM;
  
        spin_lock_init(&dev_priv->irq_lock);
        spin_lock_init(&dev_priv->error_lock);
-       spin_lock_init(&dev_priv->rps_lock);
+       spin_lock_init(&dev_priv->rps.lock);
        spin_lock_init(&dev_priv->dpio_lock);
  
        if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
@@@ -1835,6 -1868,8 +1867,8 @@@ struct drm_ioctl_desc i915_ioctls[] = 
        DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED),
+       DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_UNLOCKED),
+       DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED),
+       DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED),
  };
  
  int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
   */
  
  #include <linux/device.h>
 -#include "drmP.h"
 -#include "drm.h"
 -#include "i915_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "i915_trace.h"
  #include "intel_drv.h"
  
  #include <linux/console.h>
  #include <linux/module.h>
 -#include "drm_crtc_helper.h"
 +#include <drm/drm_crtc_helper.h>
  
  static int i915_modeset __read_mostly = -1;
  module_param_named(modeset, i915_modeset, int, 0400);
@@@ -469,6 -470,9 +469,9 @@@ static int i915_drm_freeze(struct drm_d
                                "GEM idle failed, resume might fail\n");
                        return error;
                }
+               intel_modeset_disable(dev);
                drm_irq_uninstall(dev);
        }
  
@@@ -542,13 -546,9 +545,9 @@@ static int i915_drm_thaw(struct drm_dev
                mutex_unlock(&dev->struct_mutex);
  
                intel_modeset_init_hw(dev);
+               intel_modeset_setup_hw_state(dev);
                drm_mode_config_reset(dev);
                drm_irq_install(dev);
-               /* Resume the modeset for every activated CRTC */
-               mutex_lock(&dev->mode_config.mutex);
-               drm_helper_resume_force_mode(dev);
-               mutex_unlock(&dev->mode_config.mutex);
        }
  
        intel_opregion_init(dev);
@@@ -1059,7 -1059,7 +1058,7 @@@ static bool IS_DISPLAYREG(u32 reg
         * This should make it easier to transition modules over to the
         * new register block scheme, since we can do it incrementally.
         */
-       if (reg >= 0x180000)
+       if (reg >= VLV_DISPLAY_BASE)
                return false;
  
        if (reg >= RENDER_RING_BASE &&
@@@ -1173,9 -1173,59 +1172,59 @@@ void i915_write##x(struct drm_i915_priv
        if (unlikely(__fifo_ret)) { \
                gen6_gt_check_fifodbg(dev_priv); \
        } \
+       if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \
+               DRM_ERROR("Unclaimed write to %x\n", reg); \
+               writel(ERR_INT_MMIO_UNCLAIMED, dev_priv->regs + GEN7_ERR_INT);  \
+       } \
  }
  __i915_write(8, b)
  __i915_write(16, w)
  __i915_write(32, l)
  __i915_write(64, q)
  #undef __i915_write
+ static const struct register_whitelist {
+       uint64_t offset;
+       uint32_t size;
+       uint32_t gen_bitmask; /* support gens, 0x10 for 4, 0x30 for 4 and 5, etc. */
+ } whitelist[] = {
+       { RING_TIMESTAMP(RENDER_RING_BASE), 8, 0xF0 },
+ };
+ int i915_reg_read_ioctl(struct drm_device *dev,
+                       void *data, struct drm_file *file)
+ {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_reg_read *reg = data;
+       struct register_whitelist const *entry = whitelist;
+       int i;
+       for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) {
+               if (entry->offset == reg->offset &&
+                   (1 << INTEL_INFO(dev)->gen & entry->gen_bitmask))
+                       break;
+       }
+       if (i == ARRAY_SIZE(whitelist))
+               return -EINVAL;
+       switch (entry->size) {
+       case 8:
+               reg->val = I915_READ64(reg->offset);
+               break;
+       case 4:
+               reg->val = I915_READ(reg->offset);
+               break;
+       case 2:
+               reg->val = I915_READ16(reg->offset);
+               break;
+       case 1:
+               reg->val = I915_READ8(reg->offset);
+               break;
+       default:
+               WARN_ON(1);
+               return -EINVAL;
+       }
+       return 0;
+ }
@@@ -25,8 -25,9 +25,8 @@@
   *
   */
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "i915_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "i915_trace.h"
  #include "intel_drv.h"
  #include <linux/pci.h>
  #include <linux/dma-buf.h>
  
- static __must_check int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj);
  static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj);
  static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj);
  static __must_check int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
                                                    unsigned alignment,
-                                                   bool map_and_fenceable);
+                                                   bool map_and_fenceable,
+                                                   bool nonblocking);
  static int i915_gem_phys_pwrite(struct drm_device *dev,
                                struct drm_i915_gem_object *obj,
                                struct drm_i915_gem_pwrite *args,
@@@ -55,6 -56,8 +55,8 @@@ static void i915_gem_object_update_fenc
  
  static int i915_gem_inactive_shrink(struct shrinker *shrinker,
                                    struct shrink_control *sc);
+ static long i915_gem_purge(struct drm_i915_private *dev_priv, long target);
+ static void i915_gem_shrink_all(struct drm_i915_private *dev_priv);
  static void i915_gem_object_truncate(struct drm_i915_gem_object *obj);
  
  static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj)
@@@ -140,7 -143,7 +142,7 @@@ int i915_mutex_lock_interruptible(struc
  static inline bool
  i915_gem_object_is_inactive(struct drm_i915_gem_object *obj)
  {
-       return !obj->active;
+       return obj->gtt_space && !obj->active;
  }
  
  int
@@@ -179,7 -182,7 +181,7 @@@ i915_gem_get_aperture_ioctl(struct drm_
  
        pinned = 0;
        mutex_lock(&dev->struct_mutex);
-       list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list)
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list)
                if (obj->pin_count)
                        pinned += obj->gtt_space->size;
        mutex_unlock(&dev->struct_mutex);
@@@ -340,7 -343,7 +342,7 @@@ shmem_pread_fast(struct page *page, in
                                      page_length);
        kunmap_atomic(vaddr);
  
-       return ret;
+       return ret ? -EFAULT : 0;
  }
  
  static void
@@@ -391,7 -394,7 +393,7 @@@ shmem_pread_slow(struct page *page, in
                                     page_length);
        kunmap(page);
  
-       return ret;
+       return ret ? - EFAULT : 0;
  }
  
  static int
@@@ -400,7 -403,6 +402,6 @@@ i915_gem_shmem_pread(struct drm_device 
                     struct drm_i915_gem_pread *args,
                     struct drm_file *file)
  {
-       struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
        char __user *user_data;
        ssize_t remain;
        loff_t offset;
        int hit_slowpath = 0;
        int prefaulted = 0;
        int needs_clflush = 0;
-       int release_page;
+       struct scatterlist *sg;
+       int i;
  
        user_data = (char __user *) (uintptr_t) args->data_ptr;
        remain = args->size;
                 * anyway again before the next pread happens. */
                if (obj->cache_level == I915_CACHE_NONE)
                        needs_clflush = 1;
-               ret = i915_gem_object_set_to_gtt_domain(obj, false);
-               if (ret)
-                       return ret;
+               if (obj->gtt_space) {
+                       ret = i915_gem_object_set_to_gtt_domain(obj, false);
+                       if (ret)
+                               return ret;
+               }
        }
  
+       ret = i915_gem_object_get_pages(obj);
+       if (ret)
+               return ret;
+       i915_gem_object_pin_pages(obj);
        offset = args->offset;
  
-       while (remain > 0) {
+       for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
                struct page *page;
  
+               if (i < offset >> PAGE_SHIFT)
+                       continue;
+               if (remain <= 0)
+                       break;
                /* Operation in this page
                 *
                 * shmem_page_offset = offset within page in shmem file
                if ((shmem_page_offset + page_length) > PAGE_SIZE)
                        page_length = PAGE_SIZE - shmem_page_offset;
  
-               if (obj->pages) {
-                       page = obj->pages[offset >> PAGE_SHIFT];
-                       release_page = 0;
-               } else {
-                       page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
-                       if (IS_ERR(page)) {
-                               ret = PTR_ERR(page);
-                               goto out;
-                       }
-                       release_page = 1;
-               }
+               page = sg_page(sg);
                page_do_bit17_swizzling = obj_do_bit17_swizzling &&
                        (page_to_phys(page) & (1 << 17)) != 0;
  
                        goto next_page;
  
                hit_slowpath = 1;
-               page_cache_get(page);
                mutex_unlock(&dev->struct_mutex);
  
                if (!prefaulted) {
                                       needs_clflush);
  
                mutex_lock(&dev->struct_mutex);
-               page_cache_release(page);
  next_page:
                mark_page_accessed(page);
-               if (release_page)
-                       page_cache_release(page);
  
-               if (ret) {
-                       ret = -EFAULT;
+               if (ret)
                        goto out;
-               }
  
                remain -= page_length;
                user_data += page_length;
        }
  
  out:
+       i915_gem_object_unpin_pages(obj);
        if (hit_slowpath) {
                /* Fixup: Kill any reinstated backing storage pages */
                if (obj->madv == __I915_MADV_PURGED)
@@@ -605,7 -608,7 +607,7 @@@ i915_gem_gtt_pwrite_fast(struct drm_dev
        char __user *user_data;
        int page_offset, page_length, ret;
  
-       ret = i915_gem_object_pin(obj, 0, true);
+       ret = i915_gem_object_pin(obj, 0, true, true);
        if (ret)
                goto out;
  
@@@ -685,7 -688,7 +687,7 @@@ shmem_pwrite_fast(struct page *page, in
                                       page_length);
        kunmap_atomic(vaddr);
  
-       return ret;
+       return ret ? -EFAULT : 0;
  }
  
  /* Only difference to the fast-path function is that this can handle bit17
@@@ -719,7 -722,7 +721,7 @@@ shmem_pwrite_slow(struct page *page, in
                                             page_do_bit17_swizzling);
        kunmap(page);
  
-       return ret;
+       return ret ? -EFAULT : 0;
  }
  
  static int
@@@ -728,7 -731,6 +730,6 @@@ i915_gem_shmem_pwrite(struct drm_devic
                      struct drm_i915_gem_pwrite *args,
                      struct drm_file *file)
  {
-       struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
        ssize_t remain;
        loff_t offset;
        char __user *user_data;
        int hit_slowpath = 0;
        int needs_clflush_after = 0;
        int needs_clflush_before = 0;
-       int release_page;
+       int i;
+       struct scatterlist *sg;
  
        user_data = (char __user *) (uintptr_t) args->data_ptr;
        remain = args->size;
                 * right away and we therefore have to clflush anyway. */
                if (obj->cache_level == I915_CACHE_NONE)
                        needs_clflush_after = 1;
-               ret = i915_gem_object_set_to_gtt_domain(obj, true);
-               if (ret)
-                       return ret;
+               if (obj->gtt_space) {
+                       ret = i915_gem_object_set_to_gtt_domain(obj, true);
+                       if (ret)
+                               return ret;
+               }
        }
        /* Same trick applies for invalidate partially written cachelines before
         * writing.  */
            && obj->cache_level == I915_CACHE_NONE)
                needs_clflush_before = 1;
  
+       ret = i915_gem_object_get_pages(obj);
+       if (ret)
+               return ret;
+       i915_gem_object_pin_pages(obj);
        offset = args->offset;
        obj->dirty = 1;
  
-       while (remain > 0) {
+       for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
                struct page *page;
                int partial_cacheline_write;
  
+               if (i < offset >> PAGE_SHIFT)
+                       continue;
+               if (remain <= 0)
+                       break;
                /* Operation in this page
                 *
                 * shmem_page_offset = offset within page in shmem file
                        ((shmem_page_offset | page_length)
                                & (boot_cpu_data.x86_clflush_size - 1));
  
-               if (obj->pages) {
-                       page = obj->pages[offset >> PAGE_SHIFT];
-                       release_page = 0;
-               } else {
-                       page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
-                       if (IS_ERR(page)) {
-                               ret = PTR_ERR(page);
-                               goto out;
-                       }
-                       release_page = 1;
-               }
+               page = sg_page(sg);
                page_do_bit17_swizzling = obj_do_bit17_swizzling &&
                        (page_to_phys(page) & (1 << 17)) != 0;
  
                        goto next_page;
  
                hit_slowpath = 1;
-               page_cache_get(page);
                mutex_unlock(&dev->struct_mutex);
                ret = shmem_pwrite_slow(page, shmem_page_offset, page_length,
                                        user_data, page_do_bit17_swizzling,
                                        partial_cacheline_write,
                                        needs_clflush_after);
  
                mutex_lock(&dev->struct_mutex);
-               page_cache_release(page);
  next_page:
                set_page_dirty(page);
                mark_page_accessed(page);
-               if (release_page)
-                       page_cache_release(page);
  
-               if (ret) {
-                       ret = -EFAULT;
+               if (ret)
                        goto out;
-               }
  
                remain -= page_length;
                user_data += page_length;
        }
  
  out:
+       i915_gem_object_unpin_pages(obj);
        if (hit_slowpath) {
                /* Fixup: Kill any reinstated backing storage pages */
                if (obj->madv == __I915_MADV_PURGED)
@@@ -919,10 -921,8 +920,8 @@@ i915_gem_pwrite_ioctl(struct drm_devic
                goto out;
        }
  
-       if (obj->gtt_space &&
-           obj->cache_level == I915_CACHE_NONE &&
+       if (obj->cache_level == I915_CACHE_NONE &&
            obj->tiling_mode == I915_TILING_NONE &&
-           obj->map_and_fenceable &&
            obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
                ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file);
                /* Note that the gtt paths might fail with non-page-backed user
                 * textures). Fallback to the shmem path in that case. */
        }
  
-       if (ret == -EFAULT)
+       if (ret == -EFAULT || ret == -ENOSPC)
                ret = i915_gem_shmem_pwrite(dev, obj, args, file);
  
  out:
@@@ -940,6 -940,240 +939,240 @@@ unlock
        return ret;
  }
  
+ int
+ i915_gem_check_wedge(struct drm_i915_private *dev_priv,
+                    bool interruptible)
+ {
+       if (atomic_read(&dev_priv->mm.wedged)) {
+               struct completion *x = &dev_priv->error_completion;
+               bool recovery_complete;
+               unsigned long flags;
+               /* Give the error handler a chance to run. */
+               spin_lock_irqsave(&x->wait.lock, flags);
+               recovery_complete = x->done > 0;
+               spin_unlock_irqrestore(&x->wait.lock, flags);
+               /* Non-interruptible callers can't handle -EAGAIN, hence return
+                * -EIO unconditionally for these. */
+               if (!interruptible)
+                       return -EIO;
+               /* Recovery complete, but still wedged means reset failure. */
+               if (recovery_complete)
+                       return -EIO;
+               return -EAGAIN;
+       }
+       return 0;
+ }
+ /*
+  * Compare seqno against outstanding lazy request. Emit a request if they are
+  * equal.
+  */
+ static int
+ i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno)
+ {
+       int ret;
+       BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex));
+       ret = 0;
+       if (seqno == ring->outstanding_lazy_request)
+               ret = i915_add_request(ring, NULL, NULL);
+       return ret;
+ }
+ /**
+  * __wait_seqno - wait until execution of seqno has finished
+  * @ring: the ring expected to report seqno
+  * @seqno: duh!
+  * @interruptible: do an interruptible wait (normally yes)
+  * @timeout: in - how long to wait (NULL forever); out - how much time remaining
+  *
+  * Returns 0 if the seqno was found within the alloted time. Else returns the
+  * errno with remaining time filled in timeout argument.
+  */
+ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
+                       bool interruptible, struct timespec *timeout)
+ {
+       drm_i915_private_t *dev_priv = ring->dev->dev_private;
+       struct timespec before, now, wait_time={1,0};
+       unsigned long timeout_jiffies;
+       long end;
+       bool wait_forever = true;
+       int ret;
+       if (i915_seqno_passed(ring->get_seqno(ring, true), seqno))
+               return 0;
+       trace_i915_gem_request_wait_begin(ring, seqno);
+       if (timeout != NULL) {
+               wait_time = *timeout;
+               wait_forever = false;
+       }
+       timeout_jiffies = timespec_to_jiffies(&wait_time);
+       if (WARN_ON(!ring->irq_get(ring)))
+               return -ENODEV;
+       /* Record current time in case interrupted by signal, or wedged * */
+       getrawmonotonic(&before);
+ #define EXIT_COND \
+       (i915_seqno_passed(ring->get_seqno(ring, false), seqno) || \
+       atomic_read(&dev_priv->mm.wedged))
+       do {
+               if (interruptible)
+                       end = wait_event_interruptible_timeout(ring->irq_queue,
+                                                              EXIT_COND,
+                                                              timeout_jiffies);
+               else
+                       end = wait_event_timeout(ring->irq_queue, EXIT_COND,
+                                                timeout_jiffies);
+               ret = i915_gem_check_wedge(dev_priv, interruptible);
+               if (ret)
+                       end = ret;
+       } while (end == 0 && wait_forever);
+       getrawmonotonic(&now);
+       ring->irq_put(ring);
+       trace_i915_gem_request_wait_end(ring, seqno);
+ #undef EXIT_COND
+       if (timeout) {
+               struct timespec sleep_time = timespec_sub(now, before);
+               *timeout = timespec_sub(*timeout, sleep_time);
+       }
+       switch (end) {
+       case -EIO:
+       case -EAGAIN: /* Wedged */
+       case -ERESTARTSYS: /* Signal */
+               return (int)end;
+       case 0: /* Timeout */
+               if (timeout)
+                       set_normalized_timespec(timeout, 0, 0);
+               return -ETIME;
+       default: /* Completed */
+               WARN_ON(end < 0); /* We're not aware of other errors */
+               return 0;
+       }
+ }
+ /**
+  * Waits for a sequence number to be signaled, and cleans up the
+  * request and object lists appropriately for that event.
+  */
+ int
+ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno)
+ {
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       bool interruptible = dev_priv->mm.interruptible;
+       int ret;
+       BUG_ON(!mutex_is_locked(&dev->struct_mutex));
+       BUG_ON(seqno == 0);
+       ret = i915_gem_check_wedge(dev_priv, interruptible);
+       if (ret)
+               return ret;
+       ret = i915_gem_check_olr(ring, seqno);
+       if (ret)
+               return ret;
+       return __wait_seqno(ring, seqno, interruptible, NULL);
+ }
+ /**
+  * Ensures that all rendering to the object has completed and the object is
+  * safe to unbind from the GTT or access from the CPU.
+  */
+ static __must_check int
+ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
+                              bool readonly)
+ {
+       struct intel_ring_buffer *ring = obj->ring;
+       u32 seqno;
+       int ret;
+       seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno;
+       if (seqno == 0)
+               return 0;
+       ret = i915_wait_seqno(ring, seqno);
+       if (ret)
+               return ret;
+       i915_gem_retire_requests_ring(ring);
+       /* Manually manage the write flush as we may have not yet
+        * retired the buffer.
+        */
+       if (obj->last_write_seqno &&
+           i915_seqno_passed(seqno, obj->last_write_seqno)) {
+               obj->last_write_seqno = 0;
+               obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
+       }
+       return 0;
+ }
+ /* A nonblocking variant of the above wait. This is a highly dangerous routine
+  * as the object state may change during this call.
+  */
+ static __must_check int
+ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj,
+                                           bool readonly)
+ {
+       struct drm_device *dev = obj->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring = obj->ring;
+       u32 seqno;
+       int ret;
+       BUG_ON(!mutex_is_locked(&dev->struct_mutex));
+       BUG_ON(!dev_priv->mm.interruptible);
+       seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno;
+       if (seqno == 0)
+               return 0;
+       ret = i915_gem_check_wedge(dev_priv, true);
+       if (ret)
+               return ret;
+       ret = i915_gem_check_olr(ring, seqno);
+       if (ret)
+               return ret;
+       mutex_unlock(&dev->struct_mutex);
+       ret = __wait_seqno(ring, seqno, true, NULL);
+       mutex_lock(&dev->struct_mutex);
+       i915_gem_retire_requests_ring(ring);
+       /* Manually manage the write flush as we may have not yet
+        * retired the buffer.
+        */
+       if (obj->last_write_seqno &&
+           i915_seqno_passed(seqno, obj->last_write_seqno)) {
+               obj->last_write_seqno = 0;
+               obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
+       }
+       return ret;
+ }
  /**
   * Called when user space prepares to use an object with the CPU, either
   * through the mmap ioctl's mapping or a GTT mapping.
@@@ -977,6 -1211,14 +1210,14 @@@ i915_gem_set_domain_ioctl(struct drm_de
                goto unlock;
        }
  
+       /* Try to flush the object off the GPU without holding the lock.
+        * We will repeat the flush holding the lock in the normal manner
+        * to catch cases where we are gazumped.
+        */
+       ret = i915_gem_object_wait_rendering__nonblocking(obj, !write_domain);
+       if (ret)
+               goto unref;
        if (read_domains & I915_GEM_DOMAIN_GTT) {
                ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
  
                ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0);
        }
  
+ unref:
        drm_gem_object_unreference(&obj->base);
  unlock:
        mutex_unlock(&dev->struct_mutex);
@@@ -1109,7 -1352,7 +1351,7 @@@ int i915_gem_fault(struct vm_area_struc
                        goto unlock;
        }
        if (!obj->gtt_space) {
-               ret = i915_gem_object_bind_to_gtt(obj, 0, true);
+               ret = i915_gem_object_bind_to_gtt(obj, 0, true, false);
                if (ret)
                        goto unlock;
  
@@@ -1270,8 -1513,44 +1512,44 @@@ i915_gem_get_unfenced_gtt_alignment(str
        return i915_gem_get_gtt_size(dev, size, tiling_mode);
  }
  
- int
- i915_gem_mmap_gtt(struct drm_file *file,
+ static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj)
+ {
+       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+       int ret;
+       if (obj->base.map_list.map)
+               return 0;
+       ret = drm_gem_create_mmap_offset(&obj->base);
+       if (ret != -ENOSPC)
+               return ret;
+       /* Badly fragmented mmap space? The only way we can recover
+        * space is by destroying unwanted objects. We can't randomly release
+        * mmap_offsets as userspace expects them to be persistent for the
+        * lifetime of the objects. The closest we can is to release the
+        * offsets on purgeable objects by truncating it and marking it purged,
+        * which prevents userspace from ever using that object again.
+        */
+       i915_gem_purge(dev_priv, obj->base.size >> PAGE_SHIFT);
+       ret = drm_gem_create_mmap_offset(&obj->base);
+       if (ret != -ENOSPC)
+               return ret;
+       i915_gem_shrink_all(dev_priv);
+       return drm_gem_create_mmap_offset(&obj->base);
+ }
+ static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj)
+ {
+       if (!obj->base.map_list.map)
+               return;
+       drm_gem_free_mmap_offset(&obj->base);
+ }
+ int
+ i915_gem_mmap_gtt(struct drm_file *file,
                  struct drm_device *dev,
                  uint32_t handle,
                  uint64_t *offset)
                goto out;
        }
  
-       if (!obj->base.map_list.map) {
-               ret = drm_gem_create_mmap_offset(&obj->base);
-               if (ret)
-                       goto out;
-       }
+       ret = i915_gem_object_create_mmap_offset(obj);
+       if (ret)
+               goto out;
  
        *offset = (u64)obj->base.map_list.hash.key << PAGE_SHIFT;
  
@@@ -1340,83 -1617,245 +1616,245 @@@ i915_gem_mmap_gtt_ioctl(struct drm_devi
        return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
  }
  
- int
- i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
                            gfp_t gfpmask)
+ /* Immediately discard the backing storage */
+ static void
i915_gem_object_truncate(struct drm_i915_gem_object *obj)
  {
-       int page_count, i;
-       struct address_space *mapping;
        struct inode *inode;
-       struct page *page;
  
-       if (obj->pages || obj->sg_table)
-               return 0;
+       i915_gem_object_free_mmap_offset(obj);
  
-       /* Get the list of pages out of our struct file.  They'll be pinned
-        * at this point until we release them.
-        */
-       page_count = obj->base.size / PAGE_SIZE;
-       BUG_ON(obj->pages != NULL);
-       obj->pages = drm_malloc_ab(page_count, sizeof(struct page *));
-       if (obj->pages == NULL)
-               return -ENOMEM;
+       if (obj->base.filp == NULL)
+               return;
  
+       /* Our goal here is to return as much of the memory as
+        * is possible back to the system as we are called from OOM.
+        * To do this we must instruct the shmfs to drop all of its
+        * backing pages, *now*.
+        */
        inode = obj->base.filp->f_path.dentry->d_inode;
-       mapping = inode->i_mapping;
-       gfpmask |= mapping_gfp_mask(mapping);
-       for (i = 0; i < page_count; i++) {
-               page = shmem_read_mapping_page_gfp(mapping, i, gfpmask);
-               if (IS_ERR(page))
-                       goto err_pages;
-               obj->pages[i] = page;
-       }
-       if (i915_gem_object_needs_bit17_swizzle(obj))
-               i915_gem_object_do_bit_17_swizzle(obj);
-       return 0;
+       shmem_truncate_range(inode, 0, (loff_t)-1);
  
- err_pages:
-       while (i--)
-               page_cache_release(obj->pages[i]);
+       obj->madv = __I915_MADV_PURGED;
+ }
  
-       drm_free_large(obj->pages);
-       obj->pages = NULL;
-       return PTR_ERR(page);
+ static inline int
+ i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
+ {
+       return obj->madv == I915_MADV_DONTNEED;
  }
  
  static void
  i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
  {
        int page_count = obj->base.size / PAGE_SIZE;
-       int i;
-       if (!obj->pages)
-               return;
+       struct scatterlist *sg;
+       int ret, i;
  
        BUG_ON(obj->madv == __I915_MADV_PURGED);
  
+       ret = i915_gem_object_set_to_cpu_domain(obj, true);
+       if (ret) {
+               /* In the event of a disaster, abandon all caches and
+                * hope for the best.
+                */
+               WARN_ON(ret != -EIO);
+               i915_gem_clflush_object(obj);
+               obj->base.read_domains = obj->base.write_domain = I915_GEM_DOMAIN_CPU;
+       }
        if (i915_gem_object_needs_bit17_swizzle(obj))
                i915_gem_object_save_bit_17_swizzle(obj);
  
        if (obj->madv == I915_MADV_DONTNEED)
                obj->dirty = 0;
  
-       for (i = 0; i < page_count; i++) {
+       for_each_sg(obj->pages->sgl, sg, page_count, i) {
+               struct page *page = sg_page(sg);
                if (obj->dirty)
-                       set_page_dirty(obj->pages[i]);
+                       set_page_dirty(page);
  
                if (obj->madv == I915_MADV_WILLNEED)
-                       mark_page_accessed(obj->pages[i]);
+                       mark_page_accessed(page);
  
-               page_cache_release(obj->pages[i]);
+               page_cache_release(page);
        }
        obj->dirty = 0;
  
-       drm_free_large(obj->pages);
+       sg_free_table(obj->pages);
+       kfree(obj->pages);
+ }
+ static int
+ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
+ {
+       const struct drm_i915_gem_object_ops *ops = obj->ops;
+       if (obj->pages == NULL)
+               return 0;
+       BUG_ON(obj->gtt_space);
+       if (obj->pages_pin_count)
+               return -EBUSY;
+       ops->put_pages(obj);
        obj->pages = NULL;
+       list_del(&obj->gtt_list);
+       if (i915_gem_object_is_purgeable(obj))
+               i915_gem_object_truncate(obj);
+       return 0;
+ }
+ static long
+ i915_gem_purge(struct drm_i915_private *dev_priv, long target)
+ {
+       struct drm_i915_gem_object *obj, *next;
+       long count = 0;
+       list_for_each_entry_safe(obj, next,
+                                &dev_priv->mm.unbound_list,
+                                gtt_list) {
+               if (i915_gem_object_is_purgeable(obj) &&
+                   i915_gem_object_put_pages(obj) == 0) {
+                       count += obj->base.size >> PAGE_SHIFT;
+                       if (count >= target)
+                               return count;
+               }
+       }
+       list_for_each_entry_safe(obj, next,
+                                &dev_priv->mm.inactive_list,
+                                mm_list) {
+               if (i915_gem_object_is_purgeable(obj) &&
+                   i915_gem_object_unbind(obj) == 0 &&
+                   i915_gem_object_put_pages(obj) == 0) {
+                       count += obj->base.size >> PAGE_SHIFT;
+                       if (count >= target)
+                               return count;
+               }
+       }
+       return count;
+ }
+ static void
+ i915_gem_shrink_all(struct drm_i915_private *dev_priv)
+ {
+       struct drm_i915_gem_object *obj, *next;
+       i915_gem_evict_everything(dev_priv->dev);
+       list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, gtt_list)
+               i915_gem_object_put_pages(obj);
+ }
+ static int
+ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
+ {
+       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+       int page_count, i;
+       struct address_space *mapping;
+       struct sg_table *st;
+       struct scatterlist *sg;
+       struct page *page;
+       gfp_t gfp;
+       /* Assert that the object is not currently in any GPU domain. As it
+        * wasn't in the GTT, there shouldn't be any way it could have been in
+        * a GPU cache
+        */
+       BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS);
+       BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS);
+       st = kmalloc(sizeof(*st), GFP_KERNEL);
+       if (st == NULL)
+               return -ENOMEM;
+       page_count = obj->base.size / PAGE_SIZE;
+       if (sg_alloc_table(st, page_count, GFP_KERNEL)) {
+               sg_free_table(st);
+               kfree(st);
+               return -ENOMEM;
+       }
+       /* Get the list of pages out of our struct file.  They'll be pinned
+        * at this point until we release them.
+        *
+        * Fail silently without starting the shrinker
+        */
+       mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
+       gfp = mapping_gfp_mask(mapping);
+       gfp |= __GFP_NORETRY | __GFP_NOWARN;
+       gfp &= ~(__GFP_IO | __GFP_WAIT);
+       for_each_sg(st->sgl, sg, page_count, i) {
+               page = shmem_read_mapping_page_gfp(mapping, i, gfp);
+               if (IS_ERR(page)) {
+                       i915_gem_purge(dev_priv, page_count);
+                       page = shmem_read_mapping_page_gfp(mapping, i, gfp);
+               }
+               if (IS_ERR(page)) {
+                       /* We've tried hard to allocate the memory by reaping
+                        * our own buffer, now let the real VM do its job and
+                        * go down in flames if truly OOM.
+                        */
+                       gfp &= ~(__GFP_NORETRY | __GFP_NOWARN);
+                       gfp |= __GFP_IO | __GFP_WAIT;
+                       i915_gem_shrink_all(dev_priv);
+                       page = shmem_read_mapping_page_gfp(mapping, i, gfp);
+                       if (IS_ERR(page))
+                               goto err_pages;
+                       gfp |= __GFP_NORETRY | __GFP_NOWARN;
+                       gfp &= ~(__GFP_IO | __GFP_WAIT);
+               }
+               sg_set_page(sg, page, PAGE_SIZE, 0);
+       }
+       if (i915_gem_object_needs_bit17_swizzle(obj))
+               i915_gem_object_do_bit_17_swizzle(obj);
+       obj->pages = st;
+       return 0;
+ err_pages:
+       for_each_sg(st->sgl, sg, i, page_count)
+               page_cache_release(sg_page(sg));
+       sg_free_table(st);
+       kfree(st);
+       return PTR_ERR(page);
+ }
+ /* Ensure that the associated pages are gathered from the backing storage
+  * and pinned into our object. i915_gem_object_get_pages() may be called
+  * multiple times before they are released by a single call to
+  * i915_gem_object_put_pages() - once the pages are no longer referenced
+  * either as a result of memory pressure (reaping pages under the shrinker)
+  * or as the object is itself released.
+  */
+ int
+ i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
+ {
+       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+       const struct drm_i915_gem_object_ops *ops = obj->ops;
+       int ret;
+       if (obj->pages)
+               return 0;
+       BUG_ON(obj->pages_pin_count);
+       ret = ops->get_pages(obj);
+       if (ret)
+               return ret;
+       list_add_tail(&obj->gtt_list, &dev_priv->mm.unbound_list);
+       return 0;
  }
  
  void
@@@ -1440,7 -1879,7 +1878,7 @@@ i915_gem_object_move_to_active(struct d
        list_move_tail(&obj->mm_list, &dev_priv->mm.active_list);
        list_move_tail(&obj->ring_list, &ring->active_list);
  
-       obj->last_rendering_seqno = seqno;
+       obj->last_read_seqno = seqno;
  
        if (obj->fenced_gpu_access) {
                obj->last_fenced_seqno = seqno;
  }
  
  static void
- i915_gem_object_move_off_active(struct drm_i915_gem_object *obj)
- {
-       list_del_init(&obj->ring_list);
-       obj->last_rendering_seqno = 0;
-       obj->last_fenced_seqno = 0;
- }
- static void
- i915_gem_object_move_to_flushing(struct drm_i915_gem_object *obj)
+ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
  {
        struct drm_device *dev = obj->base.dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
  
+       BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS);
        BUG_ON(!obj->active);
-       list_move_tail(&obj->mm_list, &dev_priv->mm.flushing_list);
  
-       i915_gem_object_move_off_active(obj);
- }
- static void
- i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
- {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       if (obj->pin_count) /* are we a framebuffer? */
+               intel_mark_fb_idle(obj);
  
        list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
  
-       BUG_ON(!list_empty(&obj->gpu_write_list));
-       BUG_ON(!obj->active);
+       list_del_init(&obj->ring_list);
        obj->ring = NULL;
  
-       i915_gem_object_move_off_active(obj);
+       obj->last_read_seqno = 0;
+       obj->last_write_seqno = 0;
+       obj->base.write_domain = 0;
+       obj->last_fenced_seqno = 0;
        obj->fenced_gpu_access = false;
  
        obj->active = 0;
-       obj->pending_gpu_write = false;
        drm_gem_object_unreference(&obj->base);
  
        WARN_ON(i915_verify_lists(dev));
  }
  
- /* Immediately discard the backing storage */
- static void
- i915_gem_object_truncate(struct drm_i915_gem_object *obj)
- {
-       struct inode *inode;
-       /* Our goal here is to return as much of the memory as
-        * is possible back to the system as we are called from OOM.
-        * To do this we must instruct the shmfs to drop all of its
-        * backing pages, *now*.
-        */
-       inode = obj->base.filp->f_path.dentry->d_inode;
-       shmem_truncate_range(inode, 0, (loff_t)-1);
-       if (obj->base.map_list.map)
-               drm_gem_free_mmap_offset(&obj->base);
-       obj->madv = __I915_MADV_PURGED;
- }
- static inline int
- i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
- {
-       return obj->madv == I915_MADV_DONTNEED;
- }
- static void
- i915_gem_process_flushing_list(struct intel_ring_buffer *ring,
-                              uint32_t flush_domains)
- {
-       struct drm_i915_gem_object *obj, *next;
-       list_for_each_entry_safe(obj, next,
-                                &ring->gpu_write_list,
-                                gpu_write_list) {
-               if (obj->base.write_domain & flush_domains) {
-                       uint32_t old_write_domain = obj->base.write_domain;
-                       obj->base.write_domain = 0;
-                       list_del_init(&obj->gpu_write_list);
-                       i915_gem_object_move_to_active(obj, ring,
-                                                      i915_gem_next_request_seqno(ring));
-                       trace_i915_gem_object_change_domain(obj,
-                                                           obj->base.read_domains,
-                                                           old_write_domain);
-               }
-       }
- }
  static u32
  i915_gem_get_seqno(struct drm_device *dev)
  {
@@@ -1588,15 -1965,16 +1964,16 @@@ i915_add_request(struct intel_ring_buff
         * is that the flush _must_ happen before the next request, no matter
         * what.
         */
-       if (ring->gpu_caches_dirty) {
-               ret = i915_gem_flush_ring(ring, 0, I915_GEM_GPU_DOMAINS);
-               if (ret)
-                       return ret;
+       ret = intel_ring_flush_all_caches(ring);
+       if (ret)
+               return ret;
  
-               ring->gpu_caches_dirty = false;
+       if (request == NULL) {
+               request = kmalloc(sizeof(*request), GFP_KERNEL);
+               if (request == NULL)
+                       return -ENOMEM;
        }
  
-       BUG_ON(request == NULL);
        seqno = i915_gem_next_request_seqno(ring);
  
        /* Record the position of the start of the request so that
        request_ring_position = intel_ring_get_tail(ring);
  
        ret = ring->add_request(ring, &seqno);
-       if (ret)
-           return ret;
+       if (ret) {
+               kfree(request);
+               return ret;
+       }
  
        trace_i915_gem_request_add(ring, seqno);
  
        request->emitted_jiffies = jiffies;
        was_empty = list_empty(&ring->request_list);
        list_add_tail(&request->list, &ring->request_list);
+       request->file_priv = NULL;
  
        if (file) {
                struct drm_i915_file_private *file_priv = file->driver_priv;
                                  jiffies +
                                  msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
                }
-               if (was_empty)
+               if (was_empty) {
                        queue_delayed_work(dev_priv->wq,
                                           &dev_priv->mm.retire_work, HZ);
+                       intel_mark_busy(dev_priv->dev);
+               }
        }
  
-       WARN_ON(!list_empty(&ring->gpu_write_list));
        return 0;
  }
  
@@@ -1685,8 -2066,6 +2065,6 @@@ static void i915_gem_reset_ring_lists(s
                                       struct drm_i915_gem_object,
                                       ring_list);
  
-               obj->base.write_domain = 0;
-               list_del_init(&obj->gpu_write_list);
                i915_gem_object_move_to_inactive(obj);
        }
  }
@@@ -1722,20 -2101,6 +2100,6 @@@ void i915_gem_reset(struct drm_device *
        for_each_ring(ring, dev_priv, i)
                i915_gem_reset_ring_lists(dev_priv, ring);
  
-       /* Remove anything from the flushing lists. The GPU cache is likely
-        * to be lost on reset along with the data, so simply move the
-        * lost bo to the inactive list.
-        */
-       while (!list_empty(&dev_priv->mm.flushing_list)) {
-               obj = list_first_entry(&dev_priv->mm.flushing_list,
-                                     struct drm_i915_gem_object,
-                                     mm_list);
-               obj->base.write_domain = 0;
-               list_del_init(&obj->gpu_write_list);
-               i915_gem_object_move_to_inactive(obj);
-       }
        /* Move everything out of the GPU domains to ensure we do any
         * necessary invalidation upon reuse.
         */
@@@ -1764,7 -2129,7 +2128,7 @@@ i915_gem_retire_requests_ring(struct in
  
        WARN_ON(i915_verify_lists(ring->dev));
  
-       seqno = ring->get_seqno(ring);
+       seqno = ring->get_seqno(ring, true);
  
        for (i = 0; i < ARRAY_SIZE(ring->sync_seqno); i++)
                if (seqno >= ring->sync_seqno[i])
                                      struct drm_i915_gem_object,
                                      ring_list);
  
-               if (!i915_seqno_passed(seqno, obj->last_rendering_seqno))
+               if (!i915_seqno_passed(seqno, obj->last_read_seqno))
                        break;
  
-               if (obj->base.write_domain != 0)
-                       i915_gem_object_move_to_flushing(obj);
-               else
-                       i915_gem_object_move_to_inactive(obj);
+               i915_gem_object_move_to_inactive(obj);
        }
  
        if (unlikely(ring->trace_irq_seqno &&
@@@ -1846,226 -2208,30 +2207,30 @@@ i915_gem_retire_work_handler(struct wor
        dev = dev_priv->dev;
  
        /* Come back later if the device is busy... */
-       if (!mutex_trylock(&dev->struct_mutex)) {
-               queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
-               return;
-       }
-       i915_gem_retire_requests(dev);
-       /* Send a periodic flush down the ring so we don't hold onto GEM
-        * objects indefinitely.
-        */
-       idle = true;
-       for_each_ring(ring, dev_priv, i) {
-               if (ring->gpu_caches_dirty) {
-                       struct drm_i915_gem_request *request;
-                       request = kzalloc(sizeof(*request), GFP_KERNEL);
-                       if (request == NULL ||
-                           i915_add_request(ring, NULL, request))
-                           kfree(request);
-               }
-               idle &= list_empty(&ring->request_list);
-       }
-       if (!dev_priv->mm.suspended && !idle)
-               queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
-       mutex_unlock(&dev->struct_mutex);
- }
- int
- i915_gem_check_wedge(struct drm_i915_private *dev_priv,
-                    bool interruptible)
- {
-       if (atomic_read(&dev_priv->mm.wedged)) {
-               struct completion *x = &dev_priv->error_completion;
-               bool recovery_complete;
-               unsigned long flags;
-               /* Give the error handler a chance to run. */
-               spin_lock_irqsave(&x->wait.lock, flags);
-               recovery_complete = x->done > 0;
-               spin_unlock_irqrestore(&x->wait.lock, flags);
-               /* Non-interruptible callers can't handle -EAGAIN, hence return
-                * -EIO unconditionally for these. */
-               if (!interruptible)
-                       return -EIO;
-               /* Recovery complete, but still wedged means reset failure. */
-               if (recovery_complete)
-                       return -EIO;
-               return -EAGAIN;
-       }
-       return 0;
- }
- /*
-  * Compare seqno against outstanding lazy request. Emit a request if they are
-  * equal.
-  */
- static int
- i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno)
- {
-       int ret = 0;
-       BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex));
-       if (seqno == ring->outstanding_lazy_request) {
-               struct drm_i915_gem_request *request;
-               request = kzalloc(sizeof(*request), GFP_KERNEL);
-               if (request == NULL)
-                       return -ENOMEM;
-               ret = i915_add_request(ring, NULL, request);
-               if (ret) {
-                       kfree(request);
-                       return ret;
-               }
-               BUG_ON(seqno != request->seqno);
-       }
-       return ret;
- }
- /**
-  * __wait_seqno - wait until execution of seqno has finished
-  * @ring: the ring expected to report seqno
-  * @seqno: duh!
-  * @interruptible: do an interruptible wait (normally yes)
-  * @timeout: in - how long to wait (NULL forever); out - how much time remaining
-  *
-  * Returns 0 if the seqno was found within the alloted time. Else returns the
-  * errno with remaining time filled in timeout argument.
-  */
- static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
-                       bool interruptible, struct timespec *timeout)
- {
-       drm_i915_private_t *dev_priv = ring->dev->dev_private;
-       struct timespec before, now, wait_time={1,0};
-       unsigned long timeout_jiffies;
-       long end;
-       bool wait_forever = true;
-       int ret;
-       if (i915_seqno_passed(ring->get_seqno(ring), seqno))
-               return 0;
-       trace_i915_gem_request_wait_begin(ring, seqno);
-       if (timeout != NULL) {
-               wait_time = *timeout;
-               wait_forever = false;
-       }
-       timeout_jiffies = timespec_to_jiffies(&wait_time);
-       if (WARN_ON(!ring->irq_get(ring)))
-               return -ENODEV;
-       /* Record current time in case interrupted by signal, or wedged * */
-       getrawmonotonic(&before);
- #define EXIT_COND \
-       (i915_seqno_passed(ring->get_seqno(ring), seqno) || \
-       atomic_read(&dev_priv->mm.wedged))
-       do {
-               if (interruptible)
-                       end = wait_event_interruptible_timeout(ring->irq_queue,
-                                                              EXIT_COND,
-                                                              timeout_jiffies);
-               else
-                       end = wait_event_timeout(ring->irq_queue, EXIT_COND,
-                                                timeout_jiffies);
-               ret = i915_gem_check_wedge(dev_priv, interruptible);
-               if (ret)
-                       end = ret;
-       } while (end == 0 && wait_forever);
-       getrawmonotonic(&now);
-       ring->irq_put(ring);
-       trace_i915_gem_request_wait_end(ring, seqno);
- #undef EXIT_COND
-       if (timeout) {
-               struct timespec sleep_time = timespec_sub(now, before);
-               *timeout = timespec_sub(*timeout, sleep_time);
-       }
-       switch (end) {
-       case -EIO:
-       case -EAGAIN: /* Wedged */
-       case -ERESTARTSYS: /* Signal */
-               return (int)end;
-       case 0: /* Timeout */
-               if (timeout)
-                       set_normalized_timespec(timeout, 0, 0);
-               return -ETIME;
-       default: /* Completed */
-               WARN_ON(end < 0); /* We're not aware of other errors */
-               return 0;
-       }
- }
- /**
-  * Waits for a sequence number to be signaled, and cleans up the
-  * request and object lists appropriately for that event.
-  */
- int
- i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno)
- {
-       drm_i915_private_t *dev_priv = ring->dev->dev_private;
-       int ret = 0;
-       BUG_ON(seqno == 0);
-       ret = i915_gem_check_wedge(dev_priv, dev_priv->mm.interruptible);
-       if (ret)
-               return ret;
-       ret = i915_gem_check_olr(ring, seqno);
-       if (ret)
-               return ret;
-       ret = __wait_seqno(ring, seqno, dev_priv->mm.interruptible, NULL);
-       return ret;
- }
- /**
-  * Ensures that all rendering to the object has completed and the object is
-  * safe to unbind from the GTT or access from the CPU.
-  */
- int
- i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj)
- {
-       int ret;
+       if (!mutex_trylock(&dev->struct_mutex)) {
+               queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+               return;
+       }
  
-       /* This function only exists to support waiting for existing rendering,
-        * not for emitting required flushes.
-        */
-       BUG_ON((obj->base.write_domain & I915_GEM_GPU_DOMAINS) != 0);
+       i915_gem_retire_requests(dev);
  
-       /* If there is rendering queued on the buffer being evicted, wait for
-        * it.
+       /* Send a periodic flush down the ring so we don't hold onto GEM
+        * objects indefinitely.
         */
-       if (obj->active) {
-               ret = i915_wait_seqno(obj->ring, obj->last_rendering_seqno);
-               if (ret)
-                       return ret;
-               i915_gem_retire_requests_ring(obj->ring);
+       idle = true;
+       for_each_ring(ring, dev_priv, i) {
+               if (ring->gpu_caches_dirty)
+                       i915_add_request(ring, NULL, NULL);
+               idle &= list_empty(&ring->request_list);
        }
  
-       return 0;
+       if (!dev_priv->mm.suspended && !idle)
+               queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+       if (idle)
+               intel_mark_idle(dev);
+       mutex_unlock(&dev->struct_mutex);
  }
  
  /**
@@@ -2079,14 -2245,10 +2244,10 @@@ i915_gem_object_flush_active(struct drm
        int ret;
  
        if (obj->active) {
-               ret = i915_gem_object_flush_gpu_write_domain(obj);
+               ret = i915_gem_check_olr(obj->ring, obj->last_read_seqno);
                if (ret)
                        return ret;
  
-               ret = i915_gem_check_olr(obj->ring,
-                                        obj->last_rendering_seqno);
-               if (ret)
-                       return ret;
                i915_gem_retire_requests_ring(obj->ring);
        }
  
@@@ -2146,7 -2308,7 +2307,7 @@@ i915_gem_wait_ioctl(struct drm_device *
                goto out;
  
        if (obj->active) {
-               seqno = obj->last_rendering_seqno;
+               seqno = obj->last_read_seqno;
                ring = obj->ring;
        }
  
@@@ -2201,11 -2363,11 +2362,11 @@@ i915_gem_object_sync(struct drm_i915_ge
                return 0;
  
        if (to == NULL || !i915_semaphore_is_enabled(obj->base.dev))
-               return i915_gem_object_wait_rendering(obj);
+               return i915_gem_object_wait_rendering(obj, false);
  
        idx = intel_ring_sync_index(from, to);
  
-       seqno = obj->last_rendering_seqno;
+       seqno = obj->last_read_seqno;
        if (seqno <= from->sync_seqno[idx])
                return 0;
  
@@@ -2259,6 -2421,8 +2420,8 @@@ i915_gem_object_unbind(struct drm_i915_
        if (obj->pin_count)
                return -EBUSY;
  
+       BUG_ON(obj->pages == NULL);
        ret = i915_gem_object_finish_gpu(obj);
        if (ret)
                return ret;
  
        i915_gem_object_finish_gtt(obj);
  
-       /* Move the object to the CPU domain to ensure that
-        * any possible CPU writes while it's not in the GTT
-        * are flushed when we go to remap it.
-        */
-       if (ret == 0)
-               ret = i915_gem_object_set_to_cpu_domain(obj, 1);
-       if (ret == -ERESTARTSYS)
-               return ret;
-       if (ret) {
-               /* In the event of a disaster, abandon all caches and
-                * hope for the best.
-                */
-               i915_gem_clflush_object(obj);
-               obj->base.read_domains = obj->base.write_domain = I915_GEM_DOMAIN_CPU;
-       }
        /* release the fence reg _after_ flushing */
        ret = i915_gem_object_put_fence(obj);
        if (ret)
        }
        i915_gem_gtt_finish_object(obj);
  
-       i915_gem_object_put_pages_gtt(obj);
-       list_del_init(&obj->gtt_list);
-       list_del_init(&obj->mm_list);
+       list_del(&obj->mm_list);
+       list_move_tail(&obj->gtt_list, &dev_priv->mm.unbound_list);
        /* Avoid an unnecessary call to unbind on rebind. */
        obj->map_and_fenceable = true;
  
        obj->gtt_space = NULL;
        obj->gtt_offset = 0;
  
-       if (i915_gem_object_is_purgeable(obj))
-               i915_gem_object_truncate(obj);
-       return ret;
- }
- int
- i915_gem_flush_ring(struct intel_ring_buffer *ring,
-                   uint32_t invalidate_domains,
-                   uint32_t flush_domains)
- {
-       int ret;
-       if (((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) == 0)
-               return 0;
-       trace_i915_gem_ring_flush(ring, invalidate_domains, flush_domains);
-       ret = ring->flush(ring, invalidate_domains, flush_domains);
-       if (ret)
-               return ret;
-       if (flush_domains & I915_GEM_GPU_DOMAINS)
-               i915_gem_process_flushing_list(ring, flush_domains);
        return 0;
  }
  
  static int i915_ring_idle(struct intel_ring_buffer *ring)
  {
-       int ret;
-       if (list_empty(&ring->gpu_write_list) && list_empty(&ring->active_list))
+       if (list_empty(&ring->active_list))
                return 0;
  
-       if (!list_empty(&ring->gpu_write_list)) {
-               ret = i915_gem_flush_ring(ring,
-                                   I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
-               if (ret)
-                       return ret;
-       }
        return i915_wait_seqno(ring, i915_gem_next_request_seqno(ring));
  }
  
@@@ -2371,10 -2483,6 +2482,6 @@@ int i915_gpu_idle(struct drm_device *de
                ret = i915_ring_idle(ring);
                if (ret)
                        return ret;
-               /* Is the device fubar? */
-               if (WARN_ON(!list_empty(&ring->gpu_write_list)))
-                       return -EBUSY;
        }
  
        return 0;
@@@ -2547,21 -2655,8 +2654,8 @@@ static void i915_gem_object_update_fenc
  static int
  i915_gem_object_flush_fence(struct drm_i915_gem_object *obj)
  {
-       int ret;
-       if (obj->fenced_gpu_access) {
-               if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
-                       ret = i915_gem_flush_ring(obj->ring,
-                                                 0, obj->base.write_domain);
-                       if (ret)
-                               return ret;
-               }
-               obj->fenced_gpu_access = false;
-       }
        if (obj->last_fenced_seqno) {
-               ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno);
+               int ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno);
                if (ret)
                        return ret;
  
        if (obj->base.read_domains & I915_GEM_DOMAIN_GTT)
                mb();
  
+       obj->fenced_gpu_access = false;
        return 0;
  }
  
@@@ -2693,18 -2789,88 +2788,88 @@@ i915_gem_object_get_fence(struct drm_i9
        return 0;
  }
  
+ static bool i915_gem_valid_gtt_space(struct drm_device *dev,
+                                    struct drm_mm_node *gtt_space,
+                                    unsigned long cache_level)
+ {
+       struct drm_mm_node *other;
+       /* On non-LLC machines we have to be careful when putting differing
+        * types of snoopable memory together to avoid the prefetcher
+        * crossing memory domains and dieing.
+        */
+       if (HAS_LLC(dev))
+               return true;
+       if (gtt_space == NULL)
+               return true;
+       if (list_empty(&gtt_space->node_list))
+               return true;
+       other = list_entry(gtt_space->node_list.prev, struct drm_mm_node, node_list);
+       if (other->allocated && !other->hole_follows && other->color != cache_level)
+               return false;
+       other = list_entry(gtt_space->node_list.next, struct drm_mm_node, node_list);
+       if (other->allocated && !gtt_space->hole_follows && other->color != cache_level)
+               return false;
+       return true;
+ }
+ static void i915_gem_verify_gtt(struct drm_device *dev)
+ {
+ #if WATCH_GTT
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj;
+       int err = 0;
+       list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
+               if (obj->gtt_space == NULL) {
+                       printk(KERN_ERR "object found on GTT list with no space reserved\n");
+                       err++;
+                       continue;
+               }
+               if (obj->cache_level != obj->gtt_space->color) {
+                       printk(KERN_ERR "object reserved space [%08lx, %08lx] with wrong color, cache_level=%x, color=%lx\n",
+                              obj->gtt_space->start,
+                              obj->gtt_space->start + obj->gtt_space->size,
+                              obj->cache_level,
+                              obj->gtt_space->color);
+                       err++;
+                       continue;
+               }
+               if (!i915_gem_valid_gtt_space(dev,
+                                             obj->gtt_space,
+                                             obj->cache_level)) {
+                       printk(KERN_ERR "invalid GTT space found at [%08lx, %08lx] - color=%x\n",
+                              obj->gtt_space->start,
+                              obj->gtt_space->start + obj->gtt_space->size,
+                              obj->cache_level);
+                       err++;
+                       continue;
+               }
+       }
+       WARN_ON(err);
+ #endif
+ }
  /**
   * Finds free space in the GTT aperture and binds the object there.
   */
  static int
  i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
                            unsigned alignment,
-                           bool map_and_fenceable)
+                           bool map_and_fenceable,
+                           bool nonblocking)
  {
        struct drm_device *dev = obj->base.dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_mm_node *free_space;
-       gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN;
        u32 size, fence_size, fence_alignment, unfenced_alignment;
        bool mappable, fenceable;
        int ret;
                return -E2BIG;
        }
  
+       ret = i915_gem_object_get_pages(obj);
+       if (ret)
+               return ret;
   search_free:
        if (map_and_fenceable)
                free_space =
-                       drm_mm_search_free_in_range(&dev_priv->mm.gtt_space,
-                                                   size, alignment,
-                                                   0, dev_priv->mm.gtt_mappable_end,
-                                                   0);
+                       drm_mm_search_free_in_range_color(&dev_priv->mm.gtt_space,
+                                                         size, alignment, obj->cache_level,
+                                                         0, dev_priv->mm.gtt_mappable_end,
+                                                         false);
        else
-               free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
-                                               size, alignment, 0);
+               free_space = drm_mm_search_free_color(&dev_priv->mm.gtt_space,
+                                                     size, alignment, obj->cache_level,
+                                                     false);
  
        if (free_space != NULL) {
                if (map_and_fenceable)
                        obj->gtt_space =
                                drm_mm_get_block_range_generic(free_space,
-                                                              size, alignment, 0,
+                                                              size, alignment, obj->cache_level,
                                                               0, dev_priv->mm.gtt_mappable_end,
-                                                              0);
+                                                              false);
                else
                        obj->gtt_space =
-                               drm_mm_get_block(free_space, size, alignment);
+                               drm_mm_get_block_generic(free_space,
+                                                        size, alignment, obj->cache_level,
+                                                        false);
        }
        if (obj->gtt_space == NULL) {
-               /* If the gtt is empty and we're still having trouble
-                * fitting our object in, we're out of memory.
-                */
                ret = i915_gem_evict_something(dev, size, alignment,
-                                              map_and_fenceable);
+                                              obj->cache_level,
+                                              map_and_fenceable,
+                                              nonblocking);
                if (ret)
                        return ret;
  
                goto search_free;
        }
-       ret = i915_gem_object_get_pages_gtt(obj, gfpmask);
-       if (ret) {
+       if (WARN_ON(!i915_gem_valid_gtt_space(dev,
+                                             obj->gtt_space,
+                                             obj->cache_level))) {
                drm_mm_put_block(obj->gtt_space);
                obj->gtt_space = NULL;
-               if (ret == -ENOMEM) {
-                       /* first try to reclaim some memory by clearing the GTT */
-                       ret = i915_gem_evict_everything(dev, false);
-                       if (ret) {
-                               /* now try to shrink everyone else */
-                               if (gfpmask) {
-                                       gfpmask = 0;
-                                       goto search_free;
-                               }
-                               return -ENOMEM;
-                       }
-                       goto search_free;
-               }
-               return ret;
+               return -EINVAL;
        }
  
        ret = i915_gem_gtt_prepare_object(obj);
        if (ret) {
-               i915_gem_object_put_pages_gtt(obj);
                drm_mm_put_block(obj->gtt_space);
                obj->gtt_space = NULL;
-               if (i915_gem_evict_everything(dev, false))
-                       return ret;
-               goto search_free;
+               return ret;
        }
  
        if (!dev_priv->mm.aliasing_ppgtt)
                i915_gem_gtt_bind_object(obj, obj->cache_level);
  
-       list_add_tail(&obj->gtt_list, &dev_priv->mm.gtt_list);
+       list_move_tail(&obj->gtt_list, &dev_priv->mm.bound_list);
        list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
  
-       /* Assert that the object is not currently in any GPU domain. As it
-        * wasn't in the GTT, there shouldn't be any way it could have been in
-        * a GPU cache
-        */
-       BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS);
-       BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS);
        obj->gtt_offset = obj->gtt_space->start;
  
        fenceable =
        obj->map_and_fenceable = mappable && fenceable;
  
        trace_i915_gem_object_bind(obj, map_and_fenceable);
+       i915_gem_verify_gtt(dev);
        return 0;
  }
  
@@@ -2865,18 -3010,7 +3009,7 @@@ i915_gem_clflush_object(struct drm_i915
  
        trace_i915_gem_object_clflush(obj);
  
-       drm_clflush_pages(obj->pages, obj->base.size / PAGE_SIZE);
- }
- /** Flushes any GPU write domain for the object if it's dirty. */
- static int
- i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj)
- {
-       if ((obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0)
-               return 0;
-       /* Queue the GPU write cache flushing we need. */
-       return i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain);
+       drm_clflush_sg(obj->pages);
  }
  
  /** Flushes the GTT write domain for the object if it's dirty. */
@@@ -2945,16 -3079,10 +3078,10 @@@ i915_gem_object_set_to_gtt_domain(struc
        if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
                return 0;
  
-       ret = i915_gem_object_flush_gpu_write_domain(obj);
+       ret = i915_gem_object_wait_rendering(obj, !write);
        if (ret)
                return ret;
  
-       if (obj->pending_gpu_write || write) {
-               ret = i915_gem_object_wait_rendering(obj);
-               if (ret)
-                       return ret;
-       }
        i915_gem_object_flush_cpu_write_domain(obj);
  
        old_write_domain = obj->base.write_domain;
@@@ -2997,6 -3125,12 +3124,12 @@@ int i915_gem_object_set_cache_level(str
                return -EBUSY;
        }
  
+       if (!i915_gem_valid_gtt_space(dev, obj->gtt_space, cache_level)) {
+               ret = i915_gem_object_unbind(obj);
+               if (ret)
+                       return ret;
+       }
        if (obj->gtt_space) {
                ret = i915_gem_object_finish_gpu(obj);
                if (ret)
                 * registers with snooped memory, so relinquish any fences
                 * currently pointing to our region in the aperture.
                 */
-               if (INTEL_INFO(obj->base.dev)->gen < 6) {
+               if (INTEL_INFO(dev)->gen < 6) {
                        ret = i915_gem_object_put_fence(obj);
                        if (ret)
                                return ret;
                if (obj->has_aliasing_ppgtt_mapping)
                        i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
                                               obj, cache_level);
+               obj->gtt_space->color = cache_level;
        }
  
        if (cache_level == I915_CACHE_NONE) {
        }
  
        obj->cache_level = cache_level;
+       i915_gem_verify_gtt(dev);
        return 0;
  }
  
+ int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data,
+                              struct drm_file *file)
+ {
+       struct drm_i915_gem_caching *args = data;
+       struct drm_i915_gem_object *obj;
+       int ret;
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
+       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
+       if (&obj->base == NULL) {
+               ret = -ENOENT;
+               goto unlock;
+       }
+       args->caching = obj->cache_level != I915_CACHE_NONE;
+       drm_gem_object_unreference(&obj->base);
+ unlock:
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+ }
+ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
+                              struct drm_file *file)
+ {
+       struct drm_i915_gem_caching *args = data;
+       struct drm_i915_gem_object *obj;
+       enum i915_cache_level level;
+       int ret;
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
+       switch (args->caching) {
+       case I915_CACHING_NONE:
+               level = I915_CACHE_NONE;
+               break;
+       case I915_CACHING_CACHED:
+               level = I915_CACHE_LLC;
+               break;
+       default:
+               return -EINVAL;
+       }
+       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
+       if (&obj->base == NULL) {
+               ret = -ENOENT;
+               goto unlock;
+       }
+       ret = i915_gem_object_set_cache_level(obj, level);
+       drm_gem_object_unreference(&obj->base);
+ unlock:
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+ }
  /*
   * Prepare buffer for display plane (scanout, cursors, etc).
   * Can be called from an uninterruptible phase (modesetting) and allows
@@@ -3061,10 -3260,6 +3259,6 @@@ i915_gem_object_pin_to_display_plane(st
        u32 old_read_domains, old_write_domain;
        int ret;
  
-       ret = i915_gem_object_flush_gpu_write_domain(obj);
-       if (ret)
-               return ret;
        if (pipelined != obj->ring) {
                ret = i915_gem_object_sync(obj, pipelined);
                if (ret)
         * (e.g. libkms for the bootup splash), we have to ensure that we
         * always use map_and_fenceable for all scanout buffers.
         */
-       ret = i915_gem_object_pin(obj, alignment, true);
+       ret = i915_gem_object_pin(obj, alignment, true, false);
        if (ret)
                return ret;
  
        /* It should now be out of any other write domains, and we can update
         * the domain values for our changes.
         */
-       BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
+       obj->base.write_domain = 0;
        obj->base.read_domains |= I915_GEM_DOMAIN_GTT;
  
        trace_i915_gem_object_change_domain(obj,
@@@ -3118,13 -3313,7 +3312,7 @@@ i915_gem_object_finish_gpu(struct drm_i
        if ((obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0)
                return 0;
  
-       if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
-               ret = i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain);
-               if (ret)
-                       return ret;
-       }
-       ret = i915_gem_object_wait_rendering(obj);
+       ret = i915_gem_object_wait_rendering(obj, false);
        if (ret)
                return ret;
  
@@@ -3148,16 -3337,10 +3336,10 @@@ i915_gem_object_set_to_cpu_domain(struc
        if (obj->base.write_domain == I915_GEM_DOMAIN_CPU)
                return 0;
  
-       ret = i915_gem_object_flush_gpu_write_domain(obj);
+       ret = i915_gem_object_wait_rendering(obj, !write);
        if (ret)
                return ret;
  
-       if (write || obj->pending_gpu_write) {
-               ret = i915_gem_object_wait_rendering(obj);
-               if (ret)
-                       return ret;
-       }
        i915_gem_object_flush_gtt_write_domain(obj);
  
        old_write_domain = obj->base.write_domain;
@@@ -3237,7 -3420,8 +3419,8 @@@ i915_gem_ring_throttle(struct drm_devic
  int
  i915_gem_object_pin(struct drm_i915_gem_object *obj,
                    uint32_t alignment,
-                   bool map_and_fenceable)
+                   bool map_and_fenceable,
+                   bool nonblocking)
  {
        int ret;
  
  
        if (obj->gtt_space == NULL) {
                ret = i915_gem_object_bind_to_gtt(obj, alignment,
-                                                 map_and_fenceable);
+                                                 map_and_fenceable,
+                                                 nonblocking);
                if (ret)
                        return ret;
        }
@@@ -3320,7 -3505,7 +3504,7 @@@ i915_gem_pin_ioctl(struct drm_device *d
        obj->user_pin_count++;
        obj->pin_filp = file;
        if (obj->user_pin_count == 1) {
-               ret = i915_gem_object_pin(obj, args->alignment, true);
+               ret = i915_gem_object_pin(obj, args->alignment, true, false);
                if (ret)
                        goto out;
        }
@@@ -3400,6 -3585,10 +3584,10 @@@ i915_gem_busy_ioctl(struct drm_device *
        ret = i915_gem_object_flush_active(obj);
  
        args->busy = obj->active;
+       if (obj->ring) {
+               BUILD_BUG_ON(I915_NUM_RINGS > 16);
+               args->busy |= intel_ring_flag(obj->ring) << 16;
+       }
  
        drm_gem_object_unreference(&obj->base);
  unlock:
@@@ -3448,9 -3637,8 +3636,8 @@@ i915_gem_madvise_ioctl(struct drm_devic
        if (obj->madv != __I915_MADV_PURGED)
                obj->madv = args->madv;
  
-       /* if the object is no longer bound, discard its backing storage */
-       if (i915_gem_object_is_purgeable(obj) &&
-           obj->gtt_space == NULL)
+       /* if the object is no longer attached, discard its backing storage */
+       if (i915_gem_object_is_purgeable(obj) && obj->pages == NULL)
                i915_gem_object_truncate(obj);
  
        args->retained = obj->madv != __I915_MADV_PURGED;
@@@ -3462,10 -3650,32 +3649,32 @@@ unlock
        return ret;
  }
  
+ void i915_gem_object_init(struct drm_i915_gem_object *obj,
+                         const struct drm_i915_gem_object_ops *ops)
+ {
+       INIT_LIST_HEAD(&obj->mm_list);
+       INIT_LIST_HEAD(&obj->gtt_list);
+       INIT_LIST_HEAD(&obj->ring_list);
+       INIT_LIST_HEAD(&obj->exec_list);
+       obj->ops = ops;
+       obj->fence_reg = I915_FENCE_REG_NONE;
+       obj->madv = I915_MADV_WILLNEED;
+       /* Avoid an unnecessary call to unbind on the first bind. */
+       obj->map_and_fenceable = true;
+       i915_gem_info_add_obj(obj->base.dev->dev_private, obj->base.size);
+ }
+ static const struct drm_i915_gem_object_ops i915_gem_object_ops = {
+       .get_pages = i915_gem_object_get_pages_gtt,
+       .put_pages = i915_gem_object_put_pages_gtt,
+ };
  struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
                                                  size_t size)
  {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj;
        struct address_space *mapping;
        u32 mask;
        mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
        mapping_set_gfp_mask(mapping, mask);
  
-       i915_gem_info_add_obj(dev_priv, size);
+       i915_gem_object_init(obj, &i915_gem_object_ops);
  
        obj->base.write_domain = I915_GEM_DOMAIN_CPU;
        obj->base.read_domains = I915_GEM_DOMAIN_CPU;
        } else
                obj->cache_level = I915_CACHE_NONE;
  
-       obj->base.driver_private = NULL;
-       obj->fence_reg = I915_FENCE_REG_NONE;
-       INIT_LIST_HEAD(&obj->mm_list);
-       INIT_LIST_HEAD(&obj->gtt_list);
-       INIT_LIST_HEAD(&obj->ring_list);
-       INIT_LIST_HEAD(&obj->exec_list);
-       INIT_LIST_HEAD(&obj->gpu_write_list);
-       obj->madv = I915_MADV_WILLNEED;
-       /* Avoid an unnecessary call to unbind on the first bind. */
-       obj->map_and_fenceable = true;
        return obj;
  }
  
@@@ -3540,9 -3739,6 +3738,6 @@@ void i915_gem_free_object(struct drm_ge
  
        trace_i915_gem_object_destroy(obj);
  
-       if (gem_obj->import_attach)
-               drm_prime_gem_destroy(gem_obj, obj->sg_table);
        if (obj->phys_obj)
                i915_gem_detach_phys_object(dev, obj);
  
                dev_priv->mm.interruptible = was_interruptible;
        }
  
-       if (obj->base.map_list.map)
-               drm_gem_free_mmap_offset(&obj->base);
+       obj->pages_pin_count = 0;
+       i915_gem_object_put_pages(obj);
+       i915_gem_object_free_mmap_offset(obj);
+       BUG_ON(obj->pages);
+       if (obj->base.import_attach)
+               drm_prime_gem_destroy(&obj->base, NULL);
  
        drm_gem_object_release(&obj->base);
        i915_gem_info_remove_obj(dev_priv, obj->base.size);
@@@ -3590,7 -3792,7 +3791,7 @@@ i915_gem_idle(struct drm_device *dev
  
        /* Under UMS, be paranoid and evict. */
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               i915_gem_evict_everything(dev, false);
+               i915_gem_evict_everything(dev);
  
        i915_gem_reset_fences(dev);
  
@@@ -3891,7 -4093,6 +4092,6 @@@ i915_gem_entervt_ioctl(struct drm_devic
        }
  
        BUG_ON(!list_empty(&dev_priv->mm.active_list));
-       BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
        BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
        mutex_unlock(&dev->struct_mutex);
  
@@@ -3939,7 -4140,6 +4139,6 @@@ init_ring_lists(struct intel_ring_buffe
  {
        INIT_LIST_HEAD(&ring->active_list);
        INIT_LIST_HEAD(&ring->request_list);
-       INIT_LIST_HEAD(&ring->gpu_write_list);
  }
  
  void
@@@ -3949,10 -4149,10 +4148,10 @@@ i915_gem_load(struct drm_device *dev
        drm_i915_private_t *dev_priv = dev->dev_private;
  
        INIT_LIST_HEAD(&dev_priv->mm.active_list);
-       INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
        INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
+       INIT_LIST_HEAD(&dev_priv->mm.unbound_list);
+       INIT_LIST_HEAD(&dev_priv->mm.bound_list);
        INIT_LIST_HEAD(&dev_priv->mm.fence_list);
-       INIT_LIST_HEAD(&dev_priv->mm.gtt_list);
        for (i = 0; i < I915_NUM_RINGS; i++)
                init_ring_lists(&dev_priv->ring[i]);
        for (i = 0; i < I915_MAX_NUM_FENCES; i++)
@@@ -4197,18 -4397,6 +4396,6 @@@ void i915_gem_release(struct drm_devic
  }
  
  static int
- i915_gpu_is_active(struct drm_device *dev)
- {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       int lists_empty;
-       lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
-                     list_empty(&dev_priv->mm.active_list);
-       return !lists_empty;
- }
- static int
  i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
  {
        struct drm_i915_private *dev_priv =
                             struct drm_i915_private,
                             mm.inactive_shrinker);
        struct drm_device *dev = dev_priv->dev;
-       struct drm_i915_gem_object *obj, *next;
+       struct drm_i915_gem_object *obj;
        int nr_to_scan = sc->nr_to_scan;
        int cnt;
  
        if (!mutex_trylock(&dev->struct_mutex))
                return 0;
  
-       /* "fast-path" to count number of available objects */
-       if (nr_to_scan == 0) {
-               cnt = 0;
-               list_for_each_entry(obj,
-                                   &dev_priv->mm.inactive_list,
-                                   mm_list)
-                       cnt++;
-               mutex_unlock(&dev->struct_mutex);
-               return cnt / 100 * sysctl_vfs_cache_pressure;
-       }
- rescan:
-       /* first scan for clean buffers */
-       i915_gem_retire_requests(dev);
-       list_for_each_entry_safe(obj, next,
-                                &dev_priv->mm.inactive_list,
-                                mm_list) {
-               if (i915_gem_object_is_purgeable(obj)) {
-                       if (i915_gem_object_unbind(obj) == 0 &&
-                           --nr_to_scan == 0)
-                               break;
-               }
+       if (nr_to_scan) {
+               nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan);
+               if (nr_to_scan > 0)
+                       i915_gem_shrink_all(dev_priv);
        }
  
-       /* second pass, evict/count anything still on the inactive list */
        cnt = 0;
-       list_for_each_entry_safe(obj, next,
-                                &dev_priv->mm.inactive_list,
-                                mm_list) {
-               if (nr_to_scan &&
-                   i915_gem_object_unbind(obj) == 0)
-                       nr_to_scan--;
-               else
-                       cnt++;
-       }
+       list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list)
+               if (obj->pages_pin_count == 0)
+                       cnt += obj->base.size >> PAGE_SHIFT;
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list)
+               if (obj->pin_count == 0 && obj->pages_pin_count == 0)
+                       cnt += obj->base.size >> PAGE_SHIFT;
  
-       if (nr_to_scan && i915_gpu_is_active(dev)) {
-               /*
-                * We are desperate for pages, so as a last resort, wait
-                * for the GPU to finish and discard whatever we can.
-                * This has a dramatic impact to reduce the number of
-                * OOM-killer events whilst running the GPU aggressively.
-                */
-               if (i915_gpu_idle(dev) == 0)
-                       goto rescan;
-       }
        mutex_unlock(&dev->struct_mutex);
-       return cnt / 100 * sysctl_vfs_cache_pressure;
+       return cnt;
  }
@@@ -85,8 -85,8 +85,8 @@@
   *
   */
  
 -#include "drmP.h"
 -#include "i915_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  
  /* This is a HW constraint. The value below is the largest known requirement
@@@ -97,8 -97,7 +97,7 @@@
  
  static struct i915_hw_context *
  i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
- static int do_switch(struct drm_i915_gem_object *from_obj,
-                    struct i915_hw_context *to, u32 seqno);
+ static int do_switch(struct i915_hw_context *to);
  
  static int get_context_size(struct drm_device *dev)
  {
                break;
        case 7:
                reg = I915_READ(GEN7_CXT_SIZE);
-               ret = GEN7_CXT_TOTAL_SIZE(reg) * 64;
+               if (IS_HASWELL(dev))
+                       ret = HSW_CXT_TOTAL_SIZE(reg) * 64;
+               else
+                       ret = GEN7_CXT_TOTAL_SIZE(reg) * 64;
                break;
        default:
                BUG();
@@@ -219,20 -221,21 +221,21 @@@ static int create_default_context(struc
         * default context.
         */
        dev_priv->ring[RCS].default_context = ctx;
-       ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false);
-       if (ret) {
-               do_destroy(ctx);
-               return ret;
-       }
+       ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false, false);
+       if (ret)
+               goto err_destroy;
  
-       ret = do_switch(NULL, ctx, 0);
-       if (ret) {
-               i915_gem_object_unpin(ctx->obj);
-               do_destroy(ctx);
-       } else {
-               DRM_DEBUG_DRIVER("Default HW context loaded\n");
-       }
+       ret = do_switch(ctx);
+       if (ret)
+               goto err_unpin;
  
+       DRM_DEBUG_DRIVER("Default HW context loaded\n");
+       return 0;
+ err_unpin:
+       i915_gem_object_unpin(ctx->obj);
+ err_destroy:
+       do_destroy(ctx);
        return ret;
  }
  
@@@ -359,18 -362,19 +362,19 @@@ mi_set_context(struct intel_ring_buffe
        return ret;
  }
  
- static int do_switch(struct drm_i915_gem_object *from_obj,
-                    struct i915_hw_context *to,
-                    u32 seqno)
+ static int do_switch(struct i915_hw_context *to)
  {
-       struct intel_ring_buffer *ring = NULL;
+       struct intel_ring_buffer *ring = to->ring;
+       struct drm_i915_gem_object *from_obj = ring->last_context_obj;
        u32 hw_flags = 0;
        int ret;
  
-       BUG_ON(to == NULL);
        BUG_ON(from_obj != NULL && from_obj->pin_count == 0);
  
-       ret = i915_gem_object_pin(to->obj, CONTEXT_ALIGN, false);
+       if (from_obj == to->obj)
+               return 0;
+       ret = i915_gem_object_pin(to->obj, CONTEXT_ALIGN, false, false);
        if (ret)
                return ret;
  
        else if (WARN_ON_ONCE(from_obj == to->obj)) /* not yet expected */
                hw_flags |= MI_FORCE_RESTORE;
  
-       ring = to->ring;
        ret = mi_set_context(ring, to, hw_flags);
        if (ret) {
                i915_gem_object_unpin(to->obj);
         * MI_SET_CONTEXT instead of when the next seqno has completed.
         */
        if (from_obj != NULL) {
+               u32 seqno = i915_gem_next_request_seqno(ring);
                from_obj->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION;
                i915_gem_object_move_to_active(from_obj, ring, seqno);
                /* As long as MI_SET_CONTEXT is serializing, ie. it flushes the
                 * swapped, but there is no way to do that yet.
                 */
                from_obj->dirty = 1;
-               BUG_ON(from_obj->ring != to->ring);
+               BUG_ON(from_obj->ring != ring);
                i915_gem_object_unpin(from_obj);
  
                drm_gem_object_unreference(&from_obj->base);
@@@ -448,9 -452,7 +452,7 @@@ int i915_switch_context(struct intel_ri
                        int to_id)
  {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
-       struct drm_i915_file_private *file_priv = NULL;
        struct i915_hw_context *to;
-       struct drm_i915_gem_object *from_obj = ring->last_context_obj;
  
        if (dev_priv->hw_contexts_disabled)
                return 0;
        if (ring != &dev_priv->ring[RCS])
                return 0;
  
-       if (file)
-               file_priv = file->driver_priv;
        if (to_id == DEFAULT_CONTEXT_ID) {
                to = ring->default_context;
        } else {
-               to = i915_gem_context_get(file_priv, to_id);
+               if (file == NULL)
+                       return -EINVAL;
+               to = i915_gem_context_get(file->driver_priv, to_id);
                if (to == NULL)
                        return -ENOENT;
        }
  
-       if (from_obj == to->obj)
-               return 0;
-       return do_switch(from_obj, to, i915_gem_next_request_seqno(to->ring));
+       return do_switch(to);
  }
  
  int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
   * Authors:
   *    Dave Airlie <airlied@redhat.com>
   */
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "i915_drv.h"
  #include <linux/dma-buf.h>
  
  static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachment,
-                                     enum dma_data_direction dir)
+                                            enum dma_data_direction dir)
  {
        struct drm_i915_gem_object *obj = attachment->dmabuf->priv;
-       struct drm_device *dev = obj->base.dev;
-       int npages = obj->base.size / PAGE_SIZE;
-       struct sg_table *sg = NULL;
-       int ret;
-       int nents;
+       struct sg_table *st;
+       struct scatterlist *src, *dst;
+       int ret, i;
  
-       ret = i915_mutex_lock_interruptible(dev);
+       ret = i915_mutex_lock_interruptible(obj->base.dev);
        if (ret)
                return ERR_PTR(ret);
  
-       if (!obj->pages) {
-               ret = i915_gem_object_get_pages_gtt(obj, __GFP_NORETRY | __GFP_NOWARN);
-               if (ret)
-                       goto out;
+       ret = i915_gem_object_get_pages(obj);
+       if (ret) {
+               st = ERR_PTR(ret);
+               goto out;
+       }
+       /* Copy sg so that we make an independent mapping */
+       st = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
+       if (st == NULL) {
+               st = ERR_PTR(-ENOMEM);
+               goto out;
        }
  
-       /* link the pages into an SG then map the sg */
-       sg = drm_prime_pages_to_sg(obj->pages, npages);
-       nents = dma_map_sg(attachment->dev, sg->sgl, sg->nents, dir);
+       ret = sg_alloc_table(st, obj->pages->nents, GFP_KERNEL);
+       if (ret) {
+               kfree(st);
+               st = ERR_PTR(ret);
+               goto out;
+       }
+       src = obj->pages->sgl;
+       dst = st->sgl;
+       for (i = 0; i < obj->pages->nents; i++) {
+               sg_set_page(dst, sg_page(src), PAGE_SIZE, 0);
+               dst = sg_next(dst);
+               src = sg_next(src);
+       }
+       if (!dma_map_sg(attachment->dev, st->sgl, st->nents, dir)) {
+               sg_free_table(st);
+               kfree(st);
+               st = ERR_PTR(-ENOMEM);
+               goto out;
+       }
+       i915_gem_object_pin_pages(obj);
  out:
-       mutex_unlock(&dev->struct_mutex);
-       return sg;
+       mutex_unlock(&obj->base.dev->struct_mutex);
+       return st;
  }
  
  static void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
-                           struct sg_table *sg, enum dma_data_direction dir)
+                                  struct sg_table *sg,
+                                  enum dma_data_direction dir)
  {
        dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir);
        sg_free_table(sg);
@@@ -78,7 -105,9 +105,9 @@@ static void *i915_gem_dmabuf_vmap(struc
  {
        struct drm_i915_gem_object *obj = dma_buf->priv;
        struct drm_device *dev = obj->base.dev;
-       int ret;
+       struct scatterlist *sg;
+       struct page **pages;
+       int ret, i;
  
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                goto out_unlock;
        }
  
-       if (!obj->pages) {
-               ret = i915_gem_object_get_pages_gtt(obj, __GFP_NORETRY | __GFP_NOWARN);
-               if (ret) {
-                       mutex_unlock(&dev->struct_mutex);
-                       return ERR_PTR(ret);
-               }
-       }
+       ret = i915_gem_object_get_pages(obj);
+       if (ret)
+               goto error;
  
-       obj->dma_buf_vmapping = vmap(obj->pages, obj->base.size / PAGE_SIZE, 0, PAGE_KERNEL);
-       if (!obj->dma_buf_vmapping) {
-               DRM_ERROR("failed to vmap object\n");
-               goto out_unlock;
-       }
+       ret = -ENOMEM;
+       pages = drm_malloc_ab(obj->pages->nents, sizeof(struct page *));
+       if (pages == NULL)
+               goto error;
+       for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i)
+               pages[i] = sg_page(sg);
+       obj->dma_buf_vmapping = vmap(pages, obj->pages->nents, 0, PAGE_KERNEL);
+       drm_free_large(pages);
+       if (!obj->dma_buf_vmapping)
+               goto error;
  
        obj->vmapping_count = 1;
+       i915_gem_object_pin_pages(obj);
  out_unlock:
        mutex_unlock(&dev->struct_mutex);
        return obj->dma_buf_vmapping;
+ error:
+       mutex_unlock(&dev->struct_mutex);
+       return ERR_PTR(ret);
  }
  
  static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
        if (ret)
                return;
  
-       --obj->vmapping_count;
-       if (obj->vmapping_count == 0) {
+       if (--obj->vmapping_count == 0) {
                vunmap(obj->dma_buf_vmapping);
                obj->dma_buf_vmapping = NULL;
+               i915_gem_object_unpin_pages(obj);
        }
        mutex_unlock(&dev->struct_mutex);
  }
@@@ -151,6 -191,22 +191,22 @@@ static int i915_gem_dmabuf_mmap(struct 
        return -EINVAL;
  }
  
+ static int i915_gem_begin_cpu_access(struct dma_buf *dma_buf, size_t start, size_t length, enum dma_data_direction direction)
+ {
+       struct drm_i915_gem_object *obj = dma_buf->priv;
+       struct drm_device *dev = obj->base.dev;
+       int ret;
+       bool write = (direction == DMA_BIDIRECTIONAL || direction == DMA_TO_DEVICE);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
+       ret = i915_gem_object_set_to_cpu_domain(obj, write);
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+ }
  static const struct dma_buf_ops i915_dmabuf_ops =  {
        .map_dma_buf = i915_gem_map_dma_buf,
        .unmap_dma_buf = i915_gem_unmap_dma_buf,
        .mmap = i915_gem_dmabuf_mmap,
        .vmap = i915_gem_dmabuf_vmap,
        .vunmap = i915_gem_dmabuf_vunmap,
+       .begin_cpu_access = i915_gem_begin_cpu_access,
  };
  
  struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
-                               struct drm_gem_object *gem_obj, int flags)
+                                     struct drm_gem_object *gem_obj, int flags)
  {
        struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
  
-       return dma_buf_export(obj, &i915_dmabuf_ops,
-                                                 obj->base.size, 0600);
+       return dma_buf_export(obj, &i915_dmabuf_ops, obj->base.size, 0600);
+ }
+ static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj)
+ {
+       struct sg_table *sg;
+       sg = dma_buf_map_attachment(obj->base.import_attach, DMA_BIDIRECTIONAL);
+       if (IS_ERR(sg))
+               return PTR_ERR(sg);
+       obj->pages = sg;
+       obj->has_dma_mapping = true;
+       return 0;
  }
  
+ static void i915_gem_object_put_pages_dmabuf(struct drm_i915_gem_object *obj)
+ {
+       dma_buf_unmap_attachment(obj->base.import_attach,
+                                obj->pages, DMA_BIDIRECTIONAL);
+       obj->has_dma_mapping = false;
+ }
+ static const struct drm_i915_gem_object_ops i915_gem_object_dmabuf_ops = {
+       .get_pages = i915_gem_object_get_pages_dmabuf,
+       .put_pages = i915_gem_object_put_pages_dmabuf,
+ };
  struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
-                               struct dma_buf *dma_buf)
+                                            struct dma_buf *dma_buf)
  {
        struct dma_buf_attachment *attach;
-       struct sg_table *sg;
        struct drm_i915_gem_object *obj;
-       int npages;
-       int size;
        int ret;
  
        /* is this one of own objects? */
        if (IS_ERR(attach))
                return ERR_CAST(attach);
  
-       sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
-       if (IS_ERR(sg)) {
-               ret = PTR_ERR(sg);
-               goto fail_detach;
-       }
-       size = dma_buf->size;
-       npages = size / PAGE_SIZE;
  
        obj = kzalloc(sizeof(*obj), GFP_KERNEL);
        if (obj == NULL) {
                ret = -ENOMEM;
-               goto fail_unmap;
+               goto fail_detach;
        }
  
-       ret = drm_gem_private_object_init(dev, &obj->base, size);
+       ret = drm_gem_private_object_init(dev, &obj->base, dma_buf->size);
        if (ret) {
                kfree(obj);
-               goto fail_unmap;
+               goto fail_detach;
        }
  
-       obj->sg_table = sg;
+       i915_gem_object_init(obj, &i915_gem_object_dmabuf_ops);
        obj->base.import_attach = attach;
  
        return &obj->base;
  
- fail_unmap:
-       dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
  fail_detach:
        dma_buf_detach(dma_buf, attach);
        return ERR_PTR(ret);
   *
   */
  
 -#include "drmP.h"
 -#include "drm.h"
 +#include <drm/drmP.h>
  #include "i915_drv.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_trace.h"
  
  static bool
@@@ -43,7 -44,8 +43,8 @@@ mark_free(struct drm_i915_gem_object *o
  
  int
  i915_gem_evict_something(struct drm_device *dev, int min_size,
-                        unsigned alignment, bool mappable)
+                        unsigned alignment, unsigned cache_level,
+                        bool mappable, bool nonblocking)
  {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct list_head eviction_list, unwind_list;
        INIT_LIST_HEAD(&unwind_list);
        if (mappable)
                drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space,
-                                           min_size, alignment, 0,
+                                           min_size, alignment, cache_level,
                                            0, dev_priv->mm.gtt_mappable_end);
        else
                drm_mm_init_scan(&dev_priv->mm.gtt_space,
-                                min_size, alignment, 0);
+                                min_size, alignment, cache_level);
  
        /* First see if there is a large enough contiguous idle region... */
        list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) {
                        goto found;
        }
  
-       /* Now merge in the soon-to-be-expired objects... */
-       list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
-               /* Does the object require an outstanding flush? */
-               if (obj->base.write_domain)
-                       continue;
-               if (mark_free(obj, &unwind_list))
-                       goto found;
-       }
+       if (nonblocking)
+               goto none;
  
-       /* Finally add anything with a pending flush (in order of retirement) */
-       list_for_each_entry(obj, &dev_priv->mm.flushing_list, mm_list) {
-               if (mark_free(obj, &unwind_list))
-                       goto found;
-       }
+       /* Now merge in the soon-to-be-expired objects... */
        list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
-               if (!obj->base.write_domain)
-                       continue;
                if (mark_free(obj, &unwind_list))
                        goto found;
        }
  
+ none:
        /* Nothing found, clean up and bail out! */
        while (!list_empty(&unwind_list)) {
                obj = list_first_entry(&unwind_list,
@@@ -163,7 -152,7 +151,7 @@@ found
  }
  
  int
- i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
+ i915_gem_evict_everything(struct drm_device *dev)
  {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj, *next;
        int ret;
  
        lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
-                      list_empty(&dev_priv->mm.flushing_list) &&
                       list_empty(&dev_priv->mm.active_list));
        if (lists_empty)
                return -ENOSPC;
  
-       trace_i915_gem_evict_everything(dev, purgeable_only);
+       trace_i915_gem_evict_everything(dev);
  
        /* The gpu_idle will flush everything in the write domain to the
         * active list. Then we must move everything off the active list
  
        i915_gem_retire_requests(dev);
  
-       BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
        /* Having flushed everything, unbind() should never raise an error */
        list_for_each_entry_safe(obj, next,
-                                &dev_priv->mm.inactive_list, mm_list) {
-               if (!purgeable_only || obj->madv != I915_MADV_WILLNEED) {
-                       if (obj->pin_count == 0)
-                               WARN_ON(i915_gem_object_unbind(obj));
-               }
-       }
+                                &dev_priv->mm.inactive_list, mm_list)
+               if (obj->pin_count == 0)
+                       WARN_ON(i915_gem_object_unbind(obj));
  
        return 0;
  }
   *
   */
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "i915_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "i915_trace.h"
  #include "intel_drv.h"
  #include <linux/dma_remapping.h>
  
- struct change_domains {
-       uint32_t invalidate_domains;
-       uint32_t flush_domains;
-       uint32_t flush_rings;
-       uint32_t flips;
- };
- /*
-  * Set the next domain for the specified object. This
-  * may not actually perform the necessary flushing/invaliding though,
-  * as that may want to be batched with other set_domain operations
-  *
-  * This is (we hope) the only really tricky part of gem. The goal
-  * is fairly simple -- track which caches hold bits of the object
-  * and make sure they remain coherent. A few concrete examples may
-  * help to explain how it works. For shorthand, we use the notation
-  * (read_domains, write_domain), e.g. (CPU, CPU) to indicate the
-  * a pair of read and write domain masks.
-  *
-  * Case 1: the batch buffer
-  *
-  *    1. Allocated
-  *    2. Written by CPU
-  *    3. Mapped to GTT
-  *    4. Read by GPU
-  *    5. Unmapped from GTT
-  *    6. Freed
-  *
-  *    Let's take these a step at a time
-  *
-  *    1. Allocated
-  *            Pages allocated from the kernel may still have
-  *            cache contents, so we set them to (CPU, CPU) always.
-  *    2. Written by CPU (using pwrite)
-  *            The pwrite function calls set_domain (CPU, CPU) and
-  *            this function does nothing (as nothing changes)
-  *    3. Mapped by GTT
-  *            This function asserts that the object is not
-  *            currently in any GPU-based read or write domains
-  *    4. Read by GPU
-  *            i915_gem_execbuffer calls set_domain (COMMAND, 0).
-  *            As write_domain is zero, this function adds in the
-  *            current read domains (CPU+COMMAND, 0).
-  *            flush_domains is set to CPU.
-  *            invalidate_domains is set to COMMAND
-  *            clflush is run to get data out of the CPU caches
-  *            then i915_dev_set_domain calls i915_gem_flush to
-  *            emit an MI_FLUSH and drm_agp_chipset_flush
-  *    5. Unmapped from GTT
-  *            i915_gem_object_unbind calls set_domain (CPU, CPU)
-  *            flush_domains and invalidate_domains end up both zero
-  *            so no flushing/invalidating happens
-  *    6. Freed
-  *            yay, done
-  *
-  * Case 2: The shared render buffer
-  *
-  *    1. Allocated
-  *    2. Mapped to GTT
-  *    3. Read/written by GPU
-  *    4. set_domain to (CPU,CPU)
-  *    5. Read/written by CPU
-  *    6. Read/written by GPU
-  *
-  *    1. Allocated
-  *            Same as last example, (CPU, CPU)
-  *    2. Mapped to GTT
-  *            Nothing changes (assertions find that it is not in the GPU)
-  *    3. Read/written by GPU
-  *            execbuffer calls set_domain (RENDER, RENDER)
-  *            flush_domains gets CPU
-  *            invalidate_domains gets GPU
-  *            clflush (obj)
-  *            MI_FLUSH and drm_agp_chipset_flush
-  *    4. set_domain (CPU, CPU)
-  *            flush_domains gets GPU
-  *            invalidate_domains gets CPU
-  *            wait_rendering (obj) to make sure all drawing is complete.
-  *            This will include an MI_FLUSH to get the data from GPU
-  *            to memory
-  *            clflush (obj) to invalidate the CPU cache
-  *            Another MI_FLUSH in i915_gem_flush (eliminate this somehow?)
-  *    5. Read/written by CPU
-  *            cache lines are loaded and dirtied
-  *    6. Read written by GPU
-  *            Same as last GPU access
-  *
-  * Case 3: The constant buffer
-  *
-  *    1. Allocated
-  *    2. Written by CPU
-  *    3. Read by GPU
-  *    4. Updated (written) by CPU again
-  *    5. Read by GPU
-  *
-  *    1. Allocated
-  *            (CPU, CPU)
-  *    2. Written by CPU
-  *            (CPU, CPU)
-  *    3. Read by GPU
-  *            (CPU+RENDER, 0)
-  *            flush_domains = CPU
-  *            invalidate_domains = RENDER
-  *            clflush (obj)
-  *            MI_FLUSH
-  *            drm_agp_chipset_flush
-  *    4. Updated (written) by CPU again
-  *            (CPU, CPU)
-  *            flush_domains = 0 (no previous write domain)
-  *            invalidate_domains = 0 (no new read domains)
-  *    5. Read by GPU
-  *            (CPU+RENDER, 0)
-  *            flush_domains = CPU
-  *            invalidate_domains = RENDER
-  *            clflush (obj)
-  *            MI_FLUSH
-  *            drm_agp_chipset_flush
-  */
- static void
- i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj,
-                                 struct intel_ring_buffer *ring,
-                                 struct change_domains *cd)
- {
-       uint32_t invalidate_domains = 0, flush_domains = 0;
-       /*
-        * If the object isn't moving to a new write domain,
-        * let the object stay in multiple read domains
-        */
-       if (obj->base.pending_write_domain == 0)
-               obj->base.pending_read_domains |= obj->base.read_domains;
-       /*
-        * Flush the current write domain if
-        * the new read domains don't match. Invalidate
-        * any read domains which differ from the old
-        * write domain
-        */
-       if (obj->base.write_domain &&
-           (((obj->base.write_domain != obj->base.pending_read_domains ||
-              obj->ring != ring)) ||
-            (obj->fenced_gpu_access && !obj->pending_fenced_gpu_access))) {
-               flush_domains |= obj->base.write_domain;
-               invalidate_domains |=
-                       obj->base.pending_read_domains & ~obj->base.write_domain;
-       }
-       /*
-        * Invalidate any read caches which may have
-        * stale data. That is, any new read domains.
-        */
-       invalidate_domains |= obj->base.pending_read_domains & ~obj->base.read_domains;
-       if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU)
-               i915_gem_clflush_object(obj);
-       if (obj->base.pending_write_domain)
-               cd->flips |= atomic_read(&obj->pending_flip);
-       /* The actual obj->write_domain will be updated with
-        * pending_write_domain after we emit the accumulated flush for all
-        * of our domain changes in execbuffers (which clears objects'
-        * write_domains).  So if we have a current write domain that we
-        * aren't changing, set pending_write_domain to that.
-        */
-       if (flush_domains == 0 && obj->base.pending_write_domain == 0)
-               obj->base.pending_write_domain = obj->base.write_domain;
-       cd->invalidate_domains |= invalidate_domains;
-       cd->flush_domains |= flush_domains;
-       if (flush_domains & I915_GEM_GPU_DOMAINS)
-               cd->flush_rings |= intel_ring_flag(obj->ring);
-       if (invalidate_domains & I915_GEM_GPU_DOMAINS)
-               cd->flush_rings |= intel_ring_flag(ring);
- }
  struct eb_objects {
        int and;
        struct hlist_head buckets[0];
@@@ -217,6 -44,7 +43,7 @@@ eb_create(int size
  {
        struct eb_objects *eb;
        int count = PAGE_SIZE / sizeof(struct hlist_head) / 2;
+       BUILD_BUG_ON(!is_power_of_2(PAGE_SIZE / sizeof(struct hlist_head)));
        while (count > size)
                count >>= 1;
        eb = kzalloc(count*sizeof(struct hlist_head) +
@@@ -268,6 -96,7 +95,7 @@@ eb_destroy(struct eb_objects *eb
  static inline int use_cpu_reloc(struct drm_i915_gem_object *obj)
  {
        return (obj->base.write_domain == I915_GEM_DOMAIN_CPU ||
+               !obj->map_and_fenceable ||
                obj->cache_level != I915_CACHE_NONE);
  }
  
@@@ -382,7 -211,8 +210,8 @@@ i915_gem_execbuffer_relocate_entry(stru
                if (ret)
                        return ret;
  
-               vaddr = kmap_atomic(obj->pages[reloc->offset >> PAGE_SHIFT]);
+               vaddr = kmap_atomic(i915_gem_object_get_page(obj,
+                                                            reloc->offset >> PAGE_SHIFT));
                *(uint32_t *)(vaddr + page_offset) = reloc->delta;
                kunmap_atomic(vaddr);
        } else {
@@@ -503,7 -333,8 +332,8 @@@ i915_gem_execbuffer_relocate(struct drm
        return ret;
  }
  
- #define  __EXEC_OBJECT_HAS_FENCE (1<<31)
+ #define  __EXEC_OBJECT_HAS_PIN (1<<31)
+ #define  __EXEC_OBJECT_HAS_FENCE (1<<30)
  
  static int
  need_reloc_mappable(struct drm_i915_gem_object *obj)
  }
  
  static int
pin_and_fence_object(struct drm_i915_gem_object *obj,
-                    struct intel_ring_buffer *ring)
i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj,
+                                  struct intel_ring_buffer *ring)
  {
+       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
        struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
        bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
        bool need_fence, need_mappable;
                obj->tiling_mode != I915_TILING_NONE;
        need_mappable = need_fence || need_reloc_mappable(obj);
  
-       ret = i915_gem_object_pin(obj, entry->alignment, need_mappable);
+       ret = i915_gem_object_pin(obj, entry->alignment, need_mappable, false);
        if (ret)
                return ret;
  
+       entry->flags |= __EXEC_OBJECT_HAS_PIN;
        if (has_fenced_gpu_access) {
                if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
                        ret = i915_gem_object_get_fence(obj);
                        if (ret)
-                               goto err_unpin;
+                               return ret;
  
                        if (i915_gem_object_pin_fence(obj))
                                entry->flags |= __EXEC_OBJECT_HAS_FENCE;
                }
        }
  
+       /* Ensure ppgtt mapping exists if needed */
+       if (dev_priv->mm.aliasing_ppgtt && !obj->has_aliasing_ppgtt_mapping) {
+               i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
+                                      obj, obj->cache_level);
+               obj->has_aliasing_ppgtt_mapping = 1;
+       }
        entry->offset = obj->gtt_offset;
        return 0;
+ }
  
- err_unpin:
-       i915_gem_object_unpin(obj);
-       return ret;
+ static void
+ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj)
+ {
+       struct drm_i915_gem_exec_object2 *entry;
+       if (!obj->gtt_space)
+               return;
+       entry = obj->exec_entry;
+       if (entry->flags & __EXEC_OBJECT_HAS_FENCE)
+               i915_gem_object_unpin_fence(obj);
+       if (entry->flags & __EXEC_OBJECT_HAS_PIN)
+               i915_gem_object_unpin(obj);
+       entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | __EXEC_OBJECT_HAS_PIN);
  }
  
  static int
@@@ -557,11 -414,10 +413,10 @@@ i915_gem_execbuffer_reserve(struct inte
                            struct drm_file *file,
                            struct list_head *objects)
  {
-       drm_i915_private_t *dev_priv = ring->dev->dev_private;
        struct drm_i915_gem_object *obj;
-       int ret, retry;
-       bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
        struct list_head ordered_objects;
+       bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
+       int retry;
  
        INIT_LIST_HEAD(&ordered_objects);
        while (!list_empty(objects)) {
  
                obj->base.pending_read_domains = 0;
                obj->base.pending_write_domain = 0;
+               obj->pending_fenced_gpu_access = false;
        }
        list_splice(&ordered_objects, objects);
  
         * 2.  Bind new objects.
         * 3.  Decrement pin count.
         *
-        * This avoid unnecessary unbinding of later objects in order to makr
+        * This avoid unnecessary unbinding of later objects in order to make
         * room for the earlier objects *unless* we need to defragment.
         */
        retry = 0;
        do {
-               ret = 0;
+               int ret = 0;
  
                /* Unbind any ill-fitting objects or pin. */
                list_for_each_entry(obj, objects, exec_list) {
                            (need_mappable && !obj->map_and_fenceable))
                                ret = i915_gem_object_unbind(obj);
                        else
-                               ret = pin_and_fence_object(obj, ring);
+                               ret = i915_gem_execbuffer_reserve_object(obj, ring);
                        if (ret)
                                goto err;
                }
                        if (obj->gtt_space)
                                continue;
  
-                       ret = pin_and_fence_object(obj, ring);
-                       if (ret) {
-                               int ret_ignore;
-                               /* This can potentially raise a harmless
-                                * -EINVAL if we failed to bind in the above
-                                * call. It cannot raise -EINTR since we know
-                                * that the bo is freshly bound and so will
-                                * not need to be flushed or waited upon.
-                                */
-                               ret_ignore = i915_gem_object_unbind(obj);
-                               (void)ret_ignore;
-                               WARN_ON(obj->gtt_space);
-                               break;
-                       }
+                       ret = i915_gem_execbuffer_reserve_object(obj, ring);
+                       if (ret)
+                               goto err;
                }
  
-               /* Decrement pin count for bound objects */
-               list_for_each_entry(obj, objects, exec_list) {
-                       struct drm_i915_gem_exec_object2 *entry;
-                       if (!obj->gtt_space)
-                               continue;
-                       entry = obj->exec_entry;
-                       if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
-                               i915_gem_object_unpin_fence(obj);
-                               entry->flags &= ~__EXEC_OBJECT_HAS_FENCE;
-                       }
-                       i915_gem_object_unpin(obj);
-                       /* ... and ensure ppgtt mapping exist if needed. */
-                       if (dev_priv->mm.aliasing_ppgtt && !obj->has_aliasing_ppgtt_mapping) {
-                               i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
-                                                      obj, obj->cache_level);
+ err:          /* Decrement pin count for bound objects */
+               list_for_each_entry(obj, objects, exec_list)
+                       i915_gem_execbuffer_unreserve_object(obj);
  
-                               obj->has_aliasing_ppgtt_mapping = 1;
-                       }
-               }
-               if (ret != -ENOSPC || retry > 1)
+               if (ret != -ENOSPC || retry++)
                        return ret;
  
-               /* First attempt, just clear anything that is purgeable.
-                * Second attempt, clear the entire GTT.
-                */
-               ret = i915_gem_evict_everything(ring->dev, retry == 0);
+               ret = i915_gem_evict_everything(ring->dev);
                if (ret)
                        return ret;
-               retry++;
        } while (1);
- err:
-       list_for_each_entry_continue_reverse(obj, objects, exec_list) {
-               struct drm_i915_gem_exec_object2 *entry;
-               if (!obj->gtt_space)
-                       continue;
-               entry = obj->exec_entry;
-               if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
-                       i915_gem_object_unpin_fence(obj);
-                       entry->flags &= ~__EXEC_OBJECT_HAS_FENCE;
-               }
-               i915_gem_object_unpin(obj);
-       }
-       return ret;
  }
  
  static int
@@@ -809,18 -611,6 +610,6 @@@ err
        return ret;
  }
  
- static void
- i915_gem_execbuffer_flush(struct drm_device *dev,
-                         uint32_t invalidate_domains,
-                         uint32_t flush_domains)
- {
-       if (flush_domains & I915_GEM_DOMAIN_CPU)
-               intel_gtt_chipset_flush();
-       if (flush_domains & I915_GEM_DOMAIN_GTT)
-               wmb();
- }
  static int
  i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, u32 flips)
  {
        return 0;
  }
  
  static int
  i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring,
                                struct list_head *objects)
  {
        struct drm_i915_gem_object *obj;
-       struct change_domains cd;
+       uint32_t flush_domains = 0;
+       uint32_t flips = 0;
        int ret;
  
-       memset(&cd, 0, sizeof(cd));
-       list_for_each_entry(obj, objects, exec_list)
-               i915_gem_object_set_to_gpu_domain(obj, ring, &cd);
-       if (cd.invalidate_domains | cd.flush_domains) {
-               i915_gem_execbuffer_flush(ring->dev,
-                                         cd.invalidate_domains,
-                                         cd.flush_domains);
-       }
-       if (cd.flips) {
-               ret = i915_gem_execbuffer_wait_for_flips(ring, cd.flips);
+       list_for_each_entry(obj, objects, exec_list) {
+               ret = i915_gem_object_sync(obj, ring);
                if (ret)
                        return ret;
+               if (obj->base.write_domain & I915_GEM_DOMAIN_CPU)
+                       i915_gem_clflush_object(obj);
+               if (obj->base.pending_write_domain)
+                       flips |= atomic_read(&obj->pending_flip);
+               flush_domains |= obj->base.write_domain;
        }
  
-       list_for_each_entry(obj, objects, exec_list) {
-               ret = i915_gem_object_sync(obj, ring);
+       if (flips) {
+               ret = i915_gem_execbuffer_wait_for_flips(ring, flips);
                if (ret)
                        return ret;
        }
  
+       if (flush_domains & I915_GEM_DOMAIN_CPU)
+               intel_gtt_chipset_flush();
+       if (flush_domains & I915_GEM_DOMAIN_GTT)
+               wmb();
        /* Unconditionally invalidate gpu caches and ensure that we do flush
         * any residual writes from the previous batch.
         */
-       ret = i915_gem_flush_ring(ring,
-                                 I915_GEM_GPU_DOMAINS,
-                                 ring->gpu_caches_dirty ? I915_GEM_GPU_DOMAINS : 0);
-       if (ret)
-               return ret;
-       ring->gpu_caches_dirty = false;
-       return 0;
+       return intel_ring_invalidate_all_caches(ring);
  }
  
  static bool
@@@ -942,9 -729,8 +728,8 @@@ i915_gem_execbuffer_move_to_active(stru
        struct drm_i915_gem_object *obj;
  
        list_for_each_entry(obj, objects, exec_list) {
-                 u32 old_read = obj->base.read_domains;
-                 u32 old_write = obj->base.write_domain;
+               u32 old_read = obj->base.read_domains;
+               u32 old_write = obj->base.write_domain;
  
                obj->base.read_domains = obj->base.pending_read_domains;
                obj->base.write_domain = obj->base.pending_write_domain;
                i915_gem_object_move_to_active(obj, ring, seqno);
                if (obj->base.write_domain) {
                        obj->dirty = 1;
-                       obj->pending_gpu_write = true;
-                       list_move_tail(&obj->gpu_write_list,
-                                      &ring->gpu_write_list);
+                       obj->last_write_seqno = seqno;
                        if (obj->pin_count) /* check for potential scanout */
-                               intel_mark_busy(ring->dev, obj);
+                               intel_mark_fb_busy(obj);
                }
  
                trace_i915_gem_object_change_domain(obj, old_read, old_write);
        }
-       intel_mark_busy(ring->dev, NULL);
  }
  
  static void
@@@ -971,16 -753,11 +752,11 @@@ i915_gem_execbuffer_retire_commands(str
                                    struct drm_file *file,
                                    struct intel_ring_buffer *ring)
  {
-       struct drm_i915_gem_request *request;
        /* Unconditionally force add_request to emit a full flush. */
        ring->gpu_caches_dirty = true;
  
        /* Add a breadcrumb for the completion of the batch buffer */
-       request = kzalloc(sizeof(*request), GFP_KERNEL);
-       if (request == NULL || i915_add_request(ring, file, request)) {
-               kfree(request);
-       }
+       (void)i915_add_request(ring, file, NULL);
  }
  
  static int
@@@ -1326,8 -1103,7 +1102,7 @@@ i915_gem_execbuffer(struct drm_device *
                return -ENOMEM;
        }
        ret = copy_from_user(exec_list,
-                            (struct drm_i915_relocation_entry __user *)
-                            (uintptr_t) args->buffers_ptr,
+                            (void __user *)(uintptr_t)args->buffers_ptr,
                             sizeof(*exec_list) * args->buffer_count);
        if (ret != 0) {
                DRM_DEBUG("copy %d exec entries failed %d\n",
                for (i = 0; i < args->buffer_count; i++)
                        exec_list[i].offset = exec2_list[i].offset;
                /* ... and back out to userspace */
-               ret = copy_to_user((struct drm_i915_relocation_entry __user *)
-                                  (uintptr_t) args->buffers_ptr,
+               ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr,
                                   exec_list,
                                   sizeof(*exec_list) * args->buffer_count);
                if (ret) {
@@@ -1421,8 -1196,7 +1195,7 @@@ i915_gem_execbuffer2(struct drm_device 
        ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list);
        if (!ret) {
                /* Copy the new buffer offsets back to the user's exec list. */
-               ret = copy_to_user((struct drm_i915_relocation_entry __user *)
-                                  (uintptr_t) args->buffers_ptr,
+               ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr,
                                   exec2_list,
                                   sizeof(*exec2_list) * args->buffer_count);
                if (ret) {
@@@ -22,8 -22,9 +22,8 @@@
   *
   */
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "i915_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "i915_trace.h"
  #include "intel_drv.h"
@@@ -166,8 -167,7 +166,7 @@@ void i915_gem_cleanup_aliasing_ppgtt(st
  }
  
  static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt,
-                                        struct scatterlist *sg_list,
-                                        unsigned sg_len,
+                                        const struct sg_table *pages,
                                         unsigned first_entry,
                                         uint32_t pte_flags)
  {
        struct scatterlist *sg;
  
        /* init sg walking */
-       sg = sg_list;
+       sg = pages->sgl;
        i = 0;
        segment_len = sg_dma_len(sg) >> PAGE_SHIFT;
        m = 0;
  
-       while (i < sg_len) {
+       while (i < pages->nents) {
                pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
  
                for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) {
                        pt_vaddr[j] = pte | pte_flags;
  
                        /* grab the next page */
-                       m++;
-                       if (m == segment_len) {
-                               sg = sg_next(sg);
-                               i++;
-                               if (i == sg_len)
+                       if (++m == segment_len) {
+                               if (++i == pages->nents)
                                        break;
  
+                               sg = sg_next(sg);
                                segment_len = sg_dma_len(sg) >> PAGE_SHIFT;
                                m = 0;
                        }
        }
  }
  
- static void i915_ppgtt_insert_pages(struct i915_hw_ppgtt *ppgtt,
-                                   unsigned first_entry, unsigned num_entries,
-                                   struct page **pages, uint32_t pte_flags)
- {
-       uint32_t *pt_vaddr, pte;
-       unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
-       unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
-       unsigned last_pte, i;
-       dma_addr_t page_addr;
-       while (num_entries) {
-               last_pte = first_pte + num_entries;
-               last_pte = min_t(unsigned, last_pte, I915_PPGTT_PT_ENTRIES);
-               pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
-               for (i = first_pte; i < last_pte; i++) {
-                       page_addr = page_to_phys(*pages);
-                       pte = GEN6_PTE_ADDR_ENCODE(page_addr);
-                       pt_vaddr[i] = pte | pte_flags;
-                       pages++;
-               }
-               kunmap_atomic(pt_vaddr);
-               num_entries -= last_pte - first_pte;
-               first_pte = 0;
-               act_pd++;
-       }
- }
  void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
                            struct drm_i915_gem_object *obj,
                            enum i915_cache_level cache_level)
  {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t pte_flags = GEN6_PTE_VALID;
  
        switch (cache_level) {
                pte_flags |= GEN6_PTE_CACHE_LLC;
                break;
        case I915_CACHE_NONE:
-               if (IS_HASWELL(dev))
+               if (IS_HASWELL(obj->base.dev))
                        pte_flags |= HSW_PTE_UNCACHED;
                else
                        pte_flags |= GEN6_PTE_UNCACHED;
                BUG();
        }
  
-       if (obj->sg_table) {
-               i915_ppgtt_insert_sg_entries(ppgtt,
-                                            obj->sg_table->sgl,
-                                            obj->sg_table->nents,
-                                            obj->gtt_space->start >> PAGE_SHIFT,
-                                            pte_flags);
-       } else if (dev_priv->mm.gtt->needs_dmar) {
-               BUG_ON(!obj->sg_list);
-               i915_ppgtt_insert_sg_entries(ppgtt,
-                                            obj->sg_list,
-                                            obj->num_sg,
-                                            obj->gtt_space->start >> PAGE_SHIFT,
-                                            pte_flags);
-       } else
-               i915_ppgtt_insert_pages(ppgtt,
-                                       obj->gtt_space->start >> PAGE_SHIFT,
-                                       obj->base.size >> PAGE_SHIFT,
-                                       obj->pages,
-                                       pte_flags);
+       i915_ppgtt_insert_sg_entries(ppgtt,
+                                    obj->pages,
+                                    obj->gtt_space->start >> PAGE_SHIFT,
+                                    pte_flags);
  }
  
  void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
@@@ -350,7 -298,7 +297,7 @@@ void i915_gem_restore_gtt_mappings(stru
        intel_gtt_clear_range(dev_priv->mm.gtt_start / PAGE_SIZE,
                              (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE);
  
-       list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
                i915_gem_clflush_object(obj);
                i915_gem_gtt_bind_object(obj, obj->cache_level);
        }
  
  int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
  {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       /* don't map imported dma buf objects */
-       if (dev_priv->mm.gtt->needs_dmar && !obj->sg_table)
-               return intel_gtt_map_memory(obj->pages,
-                                           obj->base.size >> PAGE_SHIFT,
-                                           &obj->sg_list,
-                                           &obj->num_sg);
-       else
+       if (obj->has_dma_mapping)
                return 0;
+       if (!dma_map_sg(&obj->base.dev->pdev->dev,
+                       obj->pages->sgl, obj->pages->nents,
+                       PCI_DMA_BIDIRECTIONAL))
+               return -ENOSPC;
+       return 0;
  }
  
  void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
                              enum i915_cache_level cache_level)
  {
        struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned int agp_type = cache_level_to_agp_type(dev, cache_level);
  
-       if (obj->sg_table) {
-               intel_gtt_insert_sg_entries(obj->sg_table->sgl,
-                                           obj->sg_table->nents,
-                                           obj->gtt_space->start >> PAGE_SHIFT,
-                                           agp_type);
-       } else if (dev_priv->mm.gtt->needs_dmar) {
-               BUG_ON(!obj->sg_list);
-               intel_gtt_insert_sg_entries(obj->sg_list,
-                                           obj->num_sg,
-                                           obj->gtt_space->start >> PAGE_SHIFT,
-                                           agp_type);
-       } else
-               intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
-                                      obj->base.size >> PAGE_SHIFT,
-                                      obj->pages,
-                                      agp_type);
+       intel_gtt_insert_sg_entries(obj->pages,
+                                   obj->gtt_space->start >> PAGE_SHIFT,
+                                   agp_type);
        obj->has_global_gtt_mapping = 1;
  }
  
@@@ -417,14 -347,31 +346,31 @@@ void i915_gem_gtt_finish_object(struct 
  
        interruptible = do_idling(dev_priv);
  
-       if (obj->sg_list) {
-               intel_gtt_unmap_memory(obj->sg_list, obj->num_sg);
-               obj->sg_list = NULL;
-       }
+       if (!obj->has_dma_mapping)
+               dma_unmap_sg(&dev->pdev->dev,
+                            obj->pages->sgl, obj->pages->nents,
+                            PCI_DMA_BIDIRECTIONAL);
  
        undo_idling(dev_priv, interruptible);
  }
  
+ static void i915_gtt_color_adjust(struct drm_mm_node *node,
+                                 unsigned long color,
+                                 unsigned long *start,
+                                 unsigned long *end)
+ {
+       if (node->color != color)
+               *start += 4096;
+       if (!list_empty(&node->node_list)) {
+               node = list_entry(node->node_list.next,
+                                 struct drm_mm_node,
+                                 node_list);
+               if (node->allocated && node->color != color)
+                       *end -= 4096;
+       }
+ }
  void i915_gem_init_global_gtt(struct drm_device *dev,
                              unsigned long start,
                              unsigned long mappable_end,
  
        /* Substract the guard page ... */
        drm_mm_init(&dev_priv->mm.gtt_space, start, end - start - PAGE_SIZE);
+       if (!HAS_LLC(dev))
+               dev_priv->mm.gtt_space.color_adjust = i915_gtt_color_adjust;
  
        dev_priv->mm.gtt_start = start;
        dev_priv->mm.gtt_mappable_end = mappable_end;
   *
   */
  
 -#include "linux/string.h"
 -#include "linux/bitops.h"
 -#include "drmP.h"
 -#include "drm.h"
 -#include "i915_drm.h"
 +#include <linux/string.h>
 +#include <linux/bitops.h>
 +#include <drm/drmP.h>
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  
  /** @file i915_gem_tiling.c
@@@ -469,18 -470,20 +469,20 @@@ i915_gem_swizzle_page(struct page *page
  void
  i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj)
  {
+       struct scatterlist *sg;
        int page_count = obj->base.size >> PAGE_SHIFT;
        int i;
  
        if (obj->bit_17 == NULL)
                return;
  
-       for (i = 0; i < page_count; i++) {
-               char new_bit_17 = page_to_phys(obj->pages[i]) >> 17;
+       for_each_sg(obj->pages->sgl, sg, page_count, i) {
+               struct page *page = sg_page(sg);
+               char new_bit_17 = page_to_phys(page) >> 17;
                if ((new_bit_17 & 0x1) !=
                    (test_bit(i, obj->bit_17) != 0)) {
-                       i915_gem_swizzle_page(obj->pages[i]);
-                       set_page_dirty(obj->pages[i]);
+                       i915_gem_swizzle_page(page);
+                       set_page_dirty(page);
                }
        }
  }
  void
  i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj)
  {
+       struct scatterlist *sg;
        int page_count = obj->base.size >> PAGE_SHIFT;
        int i;
  
                }
        }
  
-       for (i = 0; i < page_count; i++) {
-               if (page_to_phys(obj->pages[i]) & (1 << 17))
+       for_each_sg(obj->pages->sgl, sg, page_count, i) {
+               struct page *page = sg_page(sg);
+               if (page_to_phys(page) & (1 << 17))
                        __set_bit(i, obj->bit_17);
                else
                        __clear_bit(i, obj->bit_17);
@@@ -30,8 -30,9 +30,8 @@@
  
  #include <linux/sysrq.h>
  #include <linux/slab.h>
 -#include "drmP.h"
 -#include "drm.h"
 -#include "i915_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "i915_trace.h"
  #include "intel_drv.h"
@@@ -295,11 -296,21 +295,21 @@@ static void i915_hotplug_work_func(stru
        drm_helper_hpd_irq_event(dev);
  }
  
- static void i915_handle_rps_change(struct drm_device *dev)
+ /* defined intel_pm.c */
+ extern spinlock_t mchdev_lock;
+ static void ironlake_handle_rps_change(struct drm_device *dev)
  {
        drm_i915_private_t *dev_priv = dev->dev_private;
        u32 busy_up, busy_down, max_avg, min_avg;
-       u8 new_delay = dev_priv->cur_delay;
+       u8 new_delay;
+       unsigned long flags;
+       spin_lock_irqsave(&mchdev_lock, flags);
+       I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
+       new_delay = dev_priv->ips.cur_delay;
  
        I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG);
        busy_up = I915_READ(RCPREVBSYTUPAVG);
  
        /* Handle RCS change request from hw */
        if (busy_up > max_avg) {
-               if (dev_priv->cur_delay != dev_priv->max_delay)
-                       new_delay = dev_priv->cur_delay - 1;
-               if (new_delay < dev_priv->max_delay)
-                       new_delay = dev_priv->max_delay;
+               if (dev_priv->ips.cur_delay != dev_priv->ips.max_delay)
+                       new_delay = dev_priv->ips.cur_delay - 1;
+               if (new_delay < dev_priv->ips.max_delay)
+                       new_delay = dev_priv->ips.max_delay;
        } else if (busy_down < min_avg) {
-               if (dev_priv->cur_delay != dev_priv->min_delay)
-                       new_delay = dev_priv->cur_delay + 1;
-               if (new_delay > dev_priv->min_delay)
-                       new_delay = dev_priv->min_delay;
+               if (dev_priv->ips.cur_delay != dev_priv->ips.min_delay)
+                       new_delay = dev_priv->ips.cur_delay + 1;
+               if (new_delay > dev_priv->ips.min_delay)
+                       new_delay = dev_priv->ips.min_delay;
        }
  
        if (ironlake_set_drps(dev, new_delay))
-               dev_priv->cur_delay = new_delay;
+               dev_priv->ips.cur_delay = new_delay;
+       spin_unlock_irqrestore(&mchdev_lock, flags);
  
        return;
  }
@@@ -334,7 -347,7 +346,7 @@@ static void notify_ring(struct drm_devi
        if (ring->obj == NULL)
                return;
  
-       trace_i915_gem_request_complete(ring, ring->get_seqno(ring));
+       trace_i915_gem_request_complete(ring, ring->get_seqno(ring, false));
  
        wake_up_all(&ring->irq_queue);
        if (i915_enable_hangcheck) {
  static void gen6_pm_rps_work(struct work_struct *work)
  {
        drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
-                                                   rps_work);
+                                                   rps.work);
        u32 pm_iir, pm_imr;
        u8 new_delay;
  
-       spin_lock_irq(&dev_priv->rps_lock);
-       pm_iir = dev_priv->pm_iir;
-       dev_priv->pm_iir = 0;
+       spin_lock_irq(&dev_priv->rps.lock);
+       pm_iir = dev_priv->rps.pm_iir;
+       dev_priv->rps.pm_iir = 0;
        pm_imr = I915_READ(GEN6_PMIMR);
        I915_WRITE(GEN6_PMIMR, 0);
-       spin_unlock_irq(&dev_priv->rps_lock);
+       spin_unlock_irq(&dev_priv->rps.lock);
  
        if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0)
                return;
        mutex_lock(&dev_priv->dev->struct_mutex);
  
        if (pm_iir & GEN6_PM_RP_UP_THRESHOLD)
-               new_delay = dev_priv->cur_delay + 1;
+               new_delay = dev_priv->rps.cur_delay + 1;
        else
-               new_delay = dev_priv->cur_delay - 1;
+               new_delay = dev_priv->rps.cur_delay - 1;
  
-       gen6_set_rps(dev_priv->dev, new_delay);
+       /* sysfs frequency interfaces may have snuck in while servicing the
+        * interrupt
+        */
+       if (!(new_delay > dev_priv->rps.max_delay ||
+             new_delay < dev_priv->rps.min_delay)) {
+               gen6_set_rps(dev_priv->dev, new_delay);
+       }
  
        mutex_unlock(&dev_priv->dev->struct_mutex);
  }
@@@ -443,7 -462,7 +461,7 @@@ static void ivybridge_handle_parity_err
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long flags;
  
-       if (!IS_IVYBRIDGE(dev))
+       if (!HAS_L3_GPU_CACHE(dev))
                return;
  
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
@@@ -487,19 -506,19 +505,19 @@@ static void gen6_queue_rps_work(struct 
         * IIR bits should never already be set because IMR should
         * prevent an interrupt from being shown in IIR. The warning
         * displays a case where we've unsafely cleared
-        * dev_priv->pm_iir. Although missing an interrupt of the same
+        * dev_priv->rps.pm_iir. Although missing an interrupt of the same
         * type is not a problem, it displays a problem in the logic.
         *
-        * The mask bit in IMR is cleared by rps_work.
+        * The mask bit in IMR is cleared by dev_priv->rps.work.
         */
  
-       spin_lock_irqsave(&dev_priv->rps_lock, flags);
-       dev_priv->pm_iir |= pm_iir;
-       I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir);
+       spin_lock_irqsave(&dev_priv->rps.lock, flags);
+       dev_priv->rps.pm_iir |= pm_iir;
+       I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
        POSTING_READ(GEN6_PMIMR);
-       spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
+       spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
  
-       queue_work(dev_priv->wq, &dev_priv->rps_work);
+       queue_work(dev_priv->wq, &dev_priv->rps.work);
  }
  
  static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS)
@@@ -792,10 -811,8 +810,8 @@@ static irqreturn_t ironlake_irq_handler
                        ibx_irq_handler(dev, pch_iir);
        }
  
-       if (de_iir & DE_PCU_EVENT) {
-               I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
-               i915_handle_rps_change(dev);
-       }
+       if (IS_GEN5(dev) &&  de_iir & DE_PCU_EVENT)
+               ironlake_handle_rps_change(dev);
  
        if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS)
                gen6_queue_rps_work(dev_priv, pm_iir);
@@@ -842,26 -859,55 +858,55 @@@ static void i915_error_work_func(struc
        }
  }
  
+ /* NB: please notice the memset */
+ static void i915_get_extra_instdone(struct drm_device *dev,
+                                   uint32_t *instdone)
+ {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG);
+       switch(INTEL_INFO(dev)->gen) {
+       case 2:
+       case 3:
+               instdone[0] = I915_READ(INSTDONE);
+               break;
+       case 4:
+       case 5:
+       case 6:
+               instdone[0] = I915_READ(INSTDONE_I965);
+               instdone[1] = I915_READ(INSTDONE1);
+               break;
+       default:
+               WARN_ONCE(1, "Unsupported platform\n");
+       case 7:
+               instdone[0] = I915_READ(GEN7_INSTDONE_1);
+               instdone[1] = I915_READ(GEN7_SC_INSTDONE);
+               instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE);
+               instdone[3] = I915_READ(GEN7_ROW_INSTDONE);
+               break;
+       }
+ }
  #ifdef CONFIG_DEBUG_FS
  static struct drm_i915_error_object *
  i915_error_object_create(struct drm_i915_private *dev_priv,
                         struct drm_i915_gem_object *src)
  {
        struct drm_i915_error_object *dst;
-       int page, page_count;
+       int i, count;
        u32 reloc_offset;
  
        if (src == NULL || src->pages == NULL)
                return NULL;
  
-       page_count = src->base.size / PAGE_SIZE;
+       count = src->base.size / PAGE_SIZE;
  
-       dst = kmalloc(sizeof(*dst) + page_count * sizeof(u32 *), GFP_ATOMIC);
+       dst = kmalloc(sizeof(*dst) + count * sizeof(u32 *), GFP_ATOMIC);
        if (dst == NULL)
                return NULL;
  
        reloc_offset = src->gtt_offset;
-       for (page = 0; page < page_count; page++) {
+       for (i = 0; i < count; i++) {
                unsigned long flags;
                void *d;
  
                        memcpy_fromio(d, s, PAGE_SIZE);
                        io_mapping_unmap_atomic(s);
                } else {
+                       struct page *page;
                        void *s;
  
-                       drm_clflush_pages(&src->pages[page], 1);
+                       page = i915_gem_object_get_page(src, i);
+                       drm_clflush_pages(&page, 1);
  
-                       s = kmap_atomic(src->pages[page]);
+                       s = kmap_atomic(page);
                        memcpy(d, s, PAGE_SIZE);
                        kunmap_atomic(s);
  
-                       drm_clflush_pages(&src->pages[page], 1);
+                       drm_clflush_pages(&page, 1);
                }
                local_irq_restore(flags);
  
-               dst->pages[page] = d;
+               dst->pages[i] = d;
  
                reloc_offset += PAGE_SIZE;
        }
-       dst->page_count = page_count;
+       dst->page_count = count;
        dst->gtt_offset = src->gtt_offset;
  
        return dst;
  
  unwind:
-       while (page--)
-               kfree(dst->pages[page]);
+       while (i--)
+               kfree(dst->pages[i]);
        kfree(dst);
        return NULL;
  }
@@@ -948,7 -997,8 +996,8 @@@ static void capture_bo(struct drm_i915_
  {
        err->size = obj->base.size;
        err->name = obj->base.name;
-       err->seqno = obj->last_rendering_seqno;
+       err->rseqno = obj->last_read_seqno;
+       err->wseqno = obj->last_write_seqno;
        err->gtt_offset = obj->gtt_offset;
        err->read_domains = obj->base.read_domains;
        err->write_domain = obj->base.write_domain;
@@@ -1038,12 -1088,12 +1087,12 @@@ i915_error_first_batchbuffer(struct drm
        if (!ring->get_seqno)
                return NULL;
  
-       seqno = ring->get_seqno(ring);
+       seqno = ring->get_seqno(ring, false);
        list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
                if (obj->ring != ring)
                        continue;
  
-               if (i915_seqno_passed(seqno, obj->last_rendering_seqno))
+               if (i915_seqno_passed(seqno, obj->last_read_seqno))
                        continue;
  
                if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0)
@@@ -1079,10 -1129,8 +1128,8 @@@ static void i915_record_ring_state(stru
                error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base));
                error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base));
                error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base));
-               if (ring->id == RCS) {
-                       error->instdone1 = I915_READ(INSTDONE1);
+               if (ring->id == RCS)
                        error->bbaddr = I915_READ64(BB_ADDR);
-               }
        } else {
                error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX);
                error->ipeir[ring->id] = I915_READ(IPEIR);
  
        error->waiting[ring->id] = waitqueue_active(&ring->irq_queue);
        error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base));
-       error->seqno[ring->id] = ring->get_seqno(ring);
+       error->seqno[ring->id] = ring->get_seqno(ring, false);
        error->acthd[ring->id] = intel_ring_get_active_head(ring);
        error->head[ring->id] = I915_READ_HEAD(ring);
        error->tail[ring->id] = I915_READ_TAIL(ring);
@@@ -1198,6 -1246,11 +1245,11 @@@ static void i915_capture_error_state(st
                error->done_reg = I915_READ(DONE_REG);
        }
  
+       if (INTEL_INFO(dev)->gen == 7)
+               error->err_int = I915_READ(GEN7_ERR_INT);
+       i915_get_extra_instdone(dev, error->extra_instdone);
        i915_gem_record_fences(dev, error);
        i915_gem_record_rings(dev, error);
  
        list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list)
                i++;
        error->active_bo_count = i;
-       list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list)
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list)
                if (obj->pin_count)
                        i++;
        error->pinned_bo_count = i - error->active_bo_count;
                error->pinned_bo_count =
                        capture_pinned_bo(error->pinned_bo,
                                          error->pinned_bo_count,
-                                         &dev_priv->mm.gtt_list);
+                                         &dev_priv->mm.bound_list);
  
        do_gettimeofday(&error->time);
  
@@@ -1273,24 -1326,26 +1325,26 @@@ void i915_destroy_error_state(struct dr
  static void i915_report_and_clear_eir(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t instdone[I915_NUM_INSTDONE_REG];
        u32 eir = I915_READ(EIR);
-       int pipe;
+       int pipe, i;
  
        if (!eir)
                return;
  
        pr_err("render error detected, EIR: 0x%08x\n", eir);
  
+       i915_get_extra_instdone(dev, instdone);
        if (IS_G4X(dev)) {
                if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) {
                        u32 ipeir = I915_READ(IPEIR_I965);
  
                        pr_err("  IPEIR: 0x%08x\n", I915_READ(IPEIR_I965));
                        pr_err("  IPEHR: 0x%08x\n", I915_READ(IPEHR_I965));
-                       pr_err("  INSTDONE: 0x%08x\n",
-                              I915_READ(INSTDONE_I965));
+                       for (i = 0; i < ARRAY_SIZE(instdone); i++)
+                               pr_err("  INSTDONE_%d: 0x%08x\n", i, instdone[i]);
                        pr_err("  INSTPS: 0x%08x\n", I915_READ(INSTPS));
-                       pr_err("  INSTDONE1: 0x%08x\n", I915_READ(INSTDONE1));
                        pr_err("  ACTHD: 0x%08x\n", I915_READ(ACTHD_I965));
                        I915_WRITE(IPEIR_I965, ipeir);
                        POSTING_READ(IPEIR_I965);
        if (eir & I915_ERROR_INSTRUCTION) {
                pr_err("instruction error\n");
                pr_err("  INSTPM: 0x%08x\n", I915_READ(INSTPM));
+               for (i = 0; i < ARRAY_SIZE(instdone); i++)
+                       pr_err("  INSTDONE_%d: 0x%08x\n", i, instdone[i]);
                if (INTEL_INFO(dev)->gen < 4) {
                        u32 ipeir = I915_READ(IPEIR);
  
                        pr_err("  IPEIR: 0x%08x\n", I915_READ(IPEIR));
                        pr_err("  IPEHR: 0x%08x\n", I915_READ(IPEHR));
-                       pr_err("  INSTDONE: 0x%08x\n", I915_READ(INSTDONE));
                        pr_err("  ACTHD: 0x%08x\n", I915_READ(ACTHD));
                        I915_WRITE(IPEIR, ipeir);
                        POSTING_READ(IPEIR);
  
                        pr_err("  IPEIR: 0x%08x\n", I915_READ(IPEIR_I965));
                        pr_err("  IPEHR: 0x%08x\n", I915_READ(IPEHR_I965));
-                       pr_err("  INSTDONE: 0x%08x\n",
-                              I915_READ(INSTDONE_I965));
                        pr_err("  INSTPS: 0x%08x\n", I915_READ(INSTPS));
-                       pr_err("  INSTDONE1: 0x%08x\n", I915_READ(INSTDONE1));
                        pr_err("  ACTHD: 0x%08x\n", I915_READ(ACTHD_I965));
                        I915_WRITE(IPEIR_I965, ipeir);
                        POSTING_READ(IPEIR_I965);
@@@ -1589,7 -1642,8 +1641,8 @@@ ring_last_seqno(struct intel_ring_buffe
  static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
  {
        if (list_empty(&ring->request_list) ||
-           i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) {
+           i915_seqno_passed(ring->get_seqno(ring, false),
+                             ring_last_seqno(ring))) {
                /* Issue a wake-up to catch stuck h/w. */
                if (waitqueue_active(&ring->irq_queue)) {
                        DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
@@@ -1655,7 -1709,7 +1708,7 @@@ void i915_hangcheck_elapsed(unsigned lo
  {
        struct drm_device *dev = (struct drm_device *)data;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       uint32_t acthd[I915_NUM_RINGS], instdone, instdone1;
+       uint32_t acthd[I915_NUM_RINGS], instdone[I915_NUM_INSTDONE_REG];
        struct intel_ring_buffer *ring;
        bool err = false, idle;
        int i;
                return;
        }
  
-       if (INTEL_INFO(dev)->gen < 4) {
-               instdone = I915_READ(INSTDONE);
-               instdone1 = 0;
-       } else {
-               instdone = I915_READ(INSTDONE_I965);
-               instdone1 = I915_READ(INSTDONE1);
-       }
+       i915_get_extra_instdone(dev, instdone);
        if (memcmp(dev_priv->last_acthd, acthd, sizeof(acthd)) == 0 &&
-           dev_priv->last_instdone == instdone &&
-           dev_priv->last_instdone1 == instdone1) {
+           memcmp(dev_priv->prev_instdone, instdone, sizeof(instdone)) == 0) {
                if (i915_hangcheck_hung(dev))
                        return;
        } else {
                dev_priv->hangcheck_count = 0;
  
                memcpy(dev_priv->last_acthd, acthd, sizeof(acthd));
-               dev_priv->last_instdone = instdone;
-               dev_priv->last_instdone1 = instdone1;
+               memcpy(dev_priv->prev_instdone, instdone, sizeof(instdone));
        }
  
  repeat:
@@@ -2646,7 -2691,7 +2690,7 @@@ void intel_irq_init(struct drm_device *
  
        INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
        INIT_WORK(&dev_priv->error_work, i915_error_work_func);
-       INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
+       INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
        INIT_WORK(&dev_priv->parity_error_work, ivybridge_parity_work);
  
        dev->driver->get_vblank_counter = i915_get_vblank_counter;
  #include <linux/dmi.h>
  #include <linux/i2c.h>
  #include <linux/slab.h>
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 -#include "drm_crtc_helper.h"
 -#include "drm_edid.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/drm_edid.h>
  #include "intel_drv.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  
  /* Here's the desired hotplug mode */
@@@ -46,6 -47,7 +46,7 @@@
  struct intel_crt {
        struct intel_encoder base;
        bool force_hotplug_required;
+       u32 adpa_reg;
  };
  
  static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
                            struct intel_crt, base);
  }
  
- static void pch_crt_dpms(struct drm_encoder *encoder, int mode)
+ static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder)
  {
-       struct drm_device *dev = encoder->dev;
+       return container_of(encoder, struct intel_crt, base);
+ }
+ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
+                                  enum pipe *pipe)
+ {
+       struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crt *crt = intel_encoder_to_crt(encoder);
+       u32 tmp;
+       tmp = I915_READ(crt->adpa_reg);
+       if (!(tmp & ADPA_DAC_ENABLE))
+               return false;
+       if (HAS_PCH_CPT(dev))
+               *pipe = PORT_TO_PIPE_CPT(tmp);
+       else
+               *pipe = PORT_TO_PIPE(tmp);
+       return true;
+ }
+ static void intel_disable_crt(struct intel_encoder *encoder)
+ {
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       struct intel_crt *crt = intel_encoder_to_crt(encoder);
        u32 temp;
  
-       temp = I915_READ(PCH_ADPA);
+       temp = I915_READ(crt->adpa_reg);
+       temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
        temp &= ~ADPA_DAC_ENABLE;
+       I915_WRITE(crt->adpa_reg, temp);
+ }
  
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               temp |= ADPA_DAC_ENABLE;
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-       case DRM_MODE_DPMS_OFF:
-               /* Just leave port enable cleared */
-               break;
-       }
+ static void intel_enable_crt(struct intel_encoder *encoder)
+ {
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       struct intel_crt *crt = intel_encoder_to_crt(encoder);
+       u32 temp;
  
-       I915_WRITE(PCH_ADPA, temp);
+       temp = I915_READ(crt->adpa_reg);
+       temp |= ADPA_DAC_ENABLE;
+       I915_WRITE(crt->adpa_reg, temp);
  }
  
- static void gmch_crt_dpms(struct drm_encoder *encoder, int mode)
+ /* Note: The caller is required to filter out dpms modes not supported by the
+  * platform. */
+ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
  {
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crt *crt = intel_encoder_to_crt(encoder);
        u32 temp;
  
-       temp = I915_READ(ADPA);
+       temp = I915_READ(crt->adpa_reg);
        temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
        temp &= ~ADPA_DAC_ENABLE;
  
-       if (IS_VALLEYVIEW(dev) && mode != DRM_MODE_DPMS_ON)
-               mode = DRM_MODE_DPMS_OFF;
        switch (mode) {
        case DRM_MODE_DPMS_ON:
                temp |= ADPA_DAC_ENABLE;
                break;
        }
  
-       I915_WRITE(ADPA, temp);
+       I915_WRITE(crt->adpa_reg, temp);
+ }
+ static void intel_crt_dpms(struct drm_connector *connector, int mode)
+ {
+       struct drm_device *dev = connector->dev;
+       struct intel_encoder *encoder = intel_attached_encoder(connector);
+       struct drm_crtc *crtc;
+       int old_dpms;
+       /* PCH platforms and VLV only support on/off. */
+       if (INTEL_INFO(dev)->gen < 5 && mode != DRM_MODE_DPMS_ON)
+               mode = DRM_MODE_DPMS_OFF;
+       if (mode == connector->dpms)
+               return;
+       old_dpms = connector->dpms;
+       connector->dpms = mode;
+       /* Only need to change hw state when actually enabled */
+       crtc = encoder->base.crtc;
+       if (!crtc) {
+               encoder->connectors_active = false;
+               return;
+       }
+       /* We need the pipe to run for anything but OFF. */
+       if (mode == DRM_MODE_DPMS_OFF)
+               encoder->connectors_active = false;
+       else
+               encoder->connectors_active = true;
+       if (mode < old_dpms) {
+               /* From off to on, enable the pipe first. */
+               intel_crtc_update_dpms(crtc);
+               intel_crt_set_dpms(encoder, mode);
+       } else {
+               intel_crt_set_dpms(encoder, mode);
+               intel_crtc_update_dpms(crtc);
+       }
+       intel_modeset_check_state(connector->dev);
  }
  
  static int intel_crt_mode_valid(struct drm_connector *connector,
@@@ -144,19 -216,15 +215,15 @@@ static void intel_crt_mode_set(struct d
  
        struct drm_device *dev = encoder->dev;
        struct drm_crtc *crtc = encoder->crtc;
+       struct intel_crt *crt =
+               intel_encoder_to_crt(to_intel_encoder(encoder));
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_i915_private *dev_priv = dev->dev_private;
        int dpll_md_reg;
        u32 adpa, dpll_md;
-       u32 adpa_reg;
  
        dpll_md_reg = DPLL_MD(intel_crtc->pipe);
  
-       if (HAS_PCH_SPLIT(dev))
-               adpa_reg = PCH_ADPA;
-       else
-               adpa_reg = ADPA;
        /*
         * Disable separate mode multiplier used when cloning SDVO to CRT
         * XXX this needs to be adjusted when we really are cloning
        if (!HAS_PCH_SPLIT(dev))
                I915_WRITE(BCLRPAT(intel_crtc->pipe), 0);
  
-       I915_WRITE(adpa_reg, adpa);
+       I915_WRITE(crt->adpa_reg, adpa);
  }
  
  static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
@@@ -544,14 -612,12 +611,12 @@@ intel_crt_detect(struct drm_connector *
                return connector->status;
  
        /* for pre-945g platforms use load detect */
-       if (intel_get_load_detect_pipe(&crt->base, connector, NULL,
-                                      &tmp)) {
+       if (intel_get_load_detect_pipe(connector, NULL, &tmp)) {
                if (intel_crt_detect_ddc(connector))
                        status = connector_status_connected;
                else
                        status = intel_crt_load_detect(crt);
-               intel_release_load_detect_pipe(&crt->base, connector,
-                                              &tmp);
+               intel_release_load_detect_pipe(connector, &tmp);
        } else
                status = connector_status_unknown;
  
@@@ -602,25 -668,15 +667,15 @@@ static void intel_crt_reset(struct drm_
   * Routines for controlling stuff on the analog port
   */
  
- static const struct drm_encoder_helper_funcs pch_encoder_funcs = {
+ static const struct drm_encoder_helper_funcs crt_encoder_funcs = {
        .mode_fixup = intel_crt_mode_fixup,
-       .prepare = intel_encoder_prepare,
-       .commit = intel_encoder_commit,
        .mode_set = intel_crt_mode_set,
-       .dpms = pch_crt_dpms,
- };
- static const struct drm_encoder_helper_funcs gmch_encoder_funcs = {
-       .mode_fixup = intel_crt_mode_fixup,
-       .prepare = intel_encoder_prepare,
-       .commit = intel_encoder_commit,
-       .mode_set = intel_crt_mode_set,
-       .dpms = gmch_crt_dpms,
+       .disable = intel_encoder_noop,
  };
  
  static const struct drm_connector_funcs intel_crt_connector_funcs = {
        .reset = intel_crt_reset,
-       .dpms = drm_helper_connector_dpms,
+       .dpms = intel_crt_dpms,
        .detect = intel_crt_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = intel_crt_destroy,
@@@ -661,7 -717,6 +716,6 @@@ void intel_crt_init(struct drm_device *
        struct intel_crt *crt;
        struct intel_connector *intel_connector;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       const struct drm_encoder_helper_funcs *encoder_helper_funcs;
  
        /* Skip machines without VGA that falsely report hotplug events */
        if (dmi_check_system(intel_no_crt))
        intel_connector_attach_encoder(intel_connector, &crt->base);
  
        crt->base.type = INTEL_OUTPUT_ANALOG;
-       crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
-                               1 << INTEL_ANALOG_CLONE_BIT |
-                               1 << INTEL_SDVO_LVDS_CLONE_BIT);
+       crt->base.cloneable = true;
        if (IS_HASWELL(dev))
                crt->base.crtc_mask = (1 << 0);
        else
-               crt->base.crtc_mask = (1 << 0) | (1 << 1);
+               crt->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
  
        if (IS_GEN2(dev))
                connector->interlace_allowed = 0;
        connector->doublescan_allowed = 0;
  
        if (HAS_PCH_SPLIT(dev))
-               encoder_helper_funcs = &pch_encoder_funcs;
+               crt->adpa_reg = PCH_ADPA;
+       else if (IS_VALLEYVIEW(dev))
+               crt->adpa_reg = VLV_ADPA;
        else
-               encoder_helper_funcs = &gmch_encoder_funcs;
+               crt->adpa_reg = ADPA;
+       crt->base.disable = intel_disable_crt;
+       crt->base.enable = intel_enable_crt;
+       crt->base.get_hw_state = intel_crt_get_hw_state;
+       intel_connector->get_hw_state = intel_connector_get_hw_state;
  
-       drm_encoder_helper_add(&crt->base.base, encoder_helper_funcs);
+       drm_encoder_helper_add(&crt->base.base, &crt_encoder_funcs);
        drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
  
        drm_sysfs_connector_add(connector);
  #include <linux/slab.h>
  #include <linux/vgaarb.h>
  #include <drm/drm_edid.h>
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "intel_drv.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "i915_trace.h"
 -#include "drm_dp_helper.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drm_dp_helper.h>
 +#include <drm/drm_crtc_helper.h>
  #include <linux/dma_remapping.h>
  
  #define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))
@@@ -1006,7 -1006,7 +1006,7 @@@ void intel_wait_for_pipe_off(struct drm
                /* Wait for the Pipe State to go off */
                if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0,
                             100))
-                       DRM_DEBUG_KMS("pipe_off wait timed out\n");
+                       WARN(1, "pipe_off wait timed out\n");
        } else {
                u32 last_line, line_mask;
                int reg = PIPEDSL(pipe);
                } while (((I915_READ(reg) & line_mask) != last_line) &&
                         time_after(timeout, jiffies));
                if (time_after(jiffies, timeout))
-                       DRM_DEBUG_KMS("pipe_off wait timed out\n");
+                       WARN(1, "pipe_off wait timed out\n");
        }
  }
  
@@@ -1431,6 -1431,8 +1431,8 @@@ static void assert_pch_ports_disabled(s
   * protect mechanism may be enabled.
   *
   * Note!  This is for pre-ILK only.
+  *
+  * Unfortunately needed by dvo_ns2501 since the dvo depends on it running.
   */
  static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
  {
@@@ -1860,59 -1862,6 +1862,6 @@@ static void intel_disable_plane(struct 
        intel_wait_for_vblank(dev_priv->dev, pipe);
  }
  
- static void disable_pch_dp(struct drm_i915_private *dev_priv,
-                          enum pipe pipe, int reg, u32 port_sel)
- {
-       u32 val = I915_READ(reg);
-       if (dp_pipe_enabled(dev_priv, pipe, port_sel, val)) {
-               DRM_DEBUG_KMS("Disabling pch dp %x on pipe %d\n", reg, pipe);
-               I915_WRITE(reg, val & ~DP_PORT_EN);
-       }
- }
- static void disable_pch_hdmi(struct drm_i915_private *dev_priv,
-                            enum pipe pipe, int reg)
- {
-       u32 val = I915_READ(reg);
-       if (hdmi_pipe_enabled(dev_priv, pipe, val)) {
-               DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n",
-                             reg, pipe);
-               I915_WRITE(reg, val & ~PORT_ENABLE);
-       }
- }
- /* Disable any ports connected to this transcoder */
- static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
-                                   enum pipe pipe)
- {
-       u32 reg, val;
-       val = I915_READ(PCH_PP_CONTROL);
-       I915_WRITE(PCH_PP_CONTROL, val | PANEL_UNLOCK_REGS);
-       disable_pch_dp(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B);
-       disable_pch_dp(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C);
-       disable_pch_dp(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D);
-       reg = PCH_ADPA;
-       val = I915_READ(reg);
-       if (adpa_pipe_enabled(dev_priv, pipe, val))
-               I915_WRITE(reg, val & ~ADPA_DAC_ENABLE);
-       reg = PCH_LVDS;
-       val = I915_READ(reg);
-       if (lvds_pipe_enabled(dev_priv, pipe, val)) {
-               DRM_DEBUG_KMS("disable lvds on pipe %d val 0x%08x\n", pipe, val);
-               I915_WRITE(reg, val & ~LVDS_PORT_EN);
-               POSTING_READ(reg);
-               udelay(100);
-       }
-       disable_pch_hdmi(dev_priv, pipe, HDMIB);
-       disable_pch_hdmi(dev_priv, pipe, HDMIC);
-       disable_pch_hdmi(dev_priv, pipe, HDMID);
- }
  int
  intel_pin_and_fence_fb_obj(struct drm_device *dev,
                           struct drm_i915_gem_object *obj,
@@@ -2201,16 -2150,17 +2150,17 @@@ intel_finish_fb(struct drm_framebuffer 
  
  static int
  intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
-                   struct drm_framebuffer *old_fb)
+                   struct drm_framebuffer *fb)
  {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_framebuffer *old_fb;
        int ret;
  
        /* no fb bound */
-       if (!crtc->fb) {
+       if (!fb) {
                DRM_ERROR("No FB bound\n");
                return 0;
        }
  
        mutex_lock(&dev->struct_mutex);
        ret = intel_pin_and_fence_fb_obj(dev,
-                                        to_intel_framebuffer(crtc->fb)->obj,
+                                        to_intel_framebuffer(fb)->obj,
                                         NULL);
        if (ret != 0) {
                mutex_unlock(&dev->struct_mutex);
                return ret;
        }
  
-       if (old_fb)
-               intel_finish_fb(old_fb);
+       if (crtc->fb)
+               intel_finish_fb(crtc->fb);
  
-       ret = dev_priv->display.update_plane(crtc, crtc->fb, x, y);
+       ret = dev_priv->display.update_plane(crtc, fb, x, y);
        if (ret) {
-               intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
+               intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj);
                mutex_unlock(&dev->struct_mutex);
                DRM_ERROR("failed to update base address\n");
                return ret;
        }
  
+       old_fb = crtc->fb;
+       crtc->fb = fb;
+       crtc->x = x;
+       crtc->y = y;
        if (old_fb) {
                intel_wait_for_vblank(dev, intel_crtc->pipe);
                intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj);
@@@ -2709,11 -2664,10 +2664,10 @@@ static void ivb_manual_fdi_link_train(s
        DRM_DEBUG_KMS("FDI train done.\n");
  }
  
- static void ironlake_fdi_pll_enable(struct drm_crtc *crtc)
+ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
  {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
        u32 reg, temp;
  
        }
  }
  
+ static void ironlake_fdi_pll_disable(struct intel_crtc *intel_crtc)
+ {
+       struct drm_device *dev = intel_crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe = intel_crtc->pipe;
+       u32 reg, temp;
+       /* Switch from PCDclk to Rawclk */
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_PCDCLK);
+       /* Disable CPU FDI TX PLL */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE);
+       POSTING_READ(reg);
+       udelay(100);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE);
+       /* Wait for the clocks to turn off. */
+       POSTING_READ(reg);
+       udelay(100);
+ }
  static void cpt_phase_pointer_disable(struct drm_device *dev, int pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@@ -2838,13 -2821,13 +2821,13 @@@ static void intel_crtc_wait_for_pending
  static bool intel_crtc_driving_pch(struct drm_crtc *crtc)
  {
        struct drm_device *dev = crtc->dev;
-       struct intel_encoder *encoder;
+       struct intel_encoder *intel_encoder;
  
        /*
         * If there's a non-PCH eDP on this crtc, it must be DP_A, and that
         * must be driven by its own crtc; no sharing is possible.
         */
-       for_each_encoder_on_crtc(dev, crtc, encoder) {
+       for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
  
                /* On Haswell, LPT PCH handles the VGA connection via FDI, and Haswell
                 * CPU handles all others */
                        /* It is still unclear how this will work on PPT, so throw up a warning */
                        WARN_ON(!HAS_PCH_LPT(dev));
  
-                       if (encoder->type == DRM_MODE_ENCODER_DAC) {
+                       if (intel_encoder->type == INTEL_OUTPUT_ANALOG) {
                                DRM_DEBUG_KMS("Haswell detected DAC encoder, assuming is PCH\n");
                                return true;
                        } else {
                                DRM_DEBUG_KMS("Haswell detected encoder %d, assuming is CPU\n",
-                                               encoder->type);
+                                             intel_encoder->type);
                                return false;
                        }
                }
  
-               switch (encoder->type) {
+               switch (intel_encoder->type) {
                case INTEL_OUTPUT_EDP:
-                       if (!intel_encoder_is_pch_edp(&encoder->base))
+                       if (!intel_encoder_is_pch_edp(&intel_encoder->base))
                                return false;
                        continue;
                }
@@@ -3181,11 -3164,14 +3164,14 @@@ static void ironlake_crtc_enable(struc
        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_encoder *encoder;
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
        u32 temp;
        bool is_pch_port;
  
+       WARN_ON(!crtc->enabled);
        if (intel_crtc->active)
                return;
  
  
        is_pch_port = intel_crtc_driving_pch(crtc);
  
-       if (is_pch_port)
-               ironlake_fdi_pll_enable(crtc);
-       else
-               ironlake_fdi_disable(crtc);
+       if (is_pch_port) {
+               ironlake_fdi_pll_enable(intel_crtc);
+       } else {
+               assert_fdi_tx_disabled(dev_priv, pipe);
+               assert_fdi_rx_disabled(dev_priv, pipe);
+       }
+       for_each_encoder_on_crtc(dev, crtc, encoder)
+               if (encoder->pre_enable)
+                       encoder->pre_enable(encoder);
  
        /* Enable panel fitting for LVDS */
        if (dev_priv->pch_pf_size &&
        mutex_unlock(&dev->struct_mutex);
  
        intel_crtc_update_cursor(crtc, true);
+       for_each_encoder_on_crtc(dev, crtc, encoder)
+               encoder->enable(encoder);
+       if (HAS_PCH_CPT(dev))
+               intel_cpt_verify_modeset(dev, intel_crtc->pipe);
  }
  
  static void ironlake_crtc_disable(struct drm_crtc *crtc)
        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_encoder *encoder;
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
        u32 reg, temp;
  
        if (!intel_crtc->active)
                return;
  
+       for_each_encoder_on_crtc(dev, crtc, encoder)
+               encoder->disable(encoder);
        intel_crtc_wait_for_pending_flips(crtc);
        drm_vblank_off(dev, pipe);
        intel_crtc_update_cursor(crtc, false);
        I915_WRITE(PF_CTL(pipe), 0);
        I915_WRITE(PF_WIN_SZ(pipe), 0);
  
-       ironlake_fdi_disable(crtc);
+       for_each_encoder_on_crtc(dev, crtc, encoder)
+               if (encoder->post_disable)
+                       encoder->post_disable(encoder);
  
-       /* This is a horrible layering violation; we should be doing this in
-        * the connector/encoder ->prepare instead, but we don't always have
-        * enough information there about the config to know whether it will
-        * actually be necessary or just cause undesired flicker.
-        */
-       intel_disable_pch_ports(dev_priv, pipe);
+       ironlake_fdi_disable(crtc);
  
        intel_disable_transcoder(dev_priv, pipe);
  
        /* disable PCH DPLL */
        intel_disable_pch_pll(intel_crtc);
  
-       /* Switch from PCDclk to Rawclk */
-       reg = FDI_RX_CTL(pipe);
-       temp = I915_READ(reg);
-       I915_WRITE(reg, temp & ~FDI_PCDCLK);
-       /* Disable CPU FDI TX PLL */
-       reg = FDI_TX_CTL(pipe);
-       temp = I915_READ(reg);
-       I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE);
-       POSTING_READ(reg);
-       udelay(100);
-       reg = FDI_RX_CTL(pipe);
-       temp = I915_READ(reg);
-       I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE);
-       /* Wait for the clocks to turn off. */
-       POSTING_READ(reg);
-       udelay(100);
+       ironlake_fdi_pll_disable(intel_crtc);
  
        intel_crtc->active = false;
        intel_update_watermarks(dev);
        mutex_unlock(&dev->struct_mutex);
  }
  
- static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
- {
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
-       /* XXX: When our outputs are all unaware of DPMS modes other than off
-        * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
-        */
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-               DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
-               ironlake_crtc_enable(crtc);
-               break;
-       case DRM_MODE_DPMS_OFF:
-               DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
-               ironlake_crtc_disable(crtc);
-               break;
-       }
- }
  static void ironlake_crtc_off(struct drm_crtc *crtc)
  {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@@ -3386,9 -3343,12 +3343,12 @@@ static void i9xx_crtc_enable(struct drm
        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_encoder *encoder;
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
  
+       WARN_ON(!crtc->enabled);
        if (intel_crtc->active)
                return;
  
        /* Give the overlay scaler a chance to enable if it's on this pipe */
        intel_crtc_dpms_overlay(intel_crtc, true);
        intel_crtc_update_cursor(crtc, true);
+       for_each_encoder_on_crtc(dev, crtc, encoder)
+               encoder->enable(encoder);
  }
  
  static void i9xx_crtc_disable(struct drm_crtc *crtc)
        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_encoder *encoder;
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
  
        if (!intel_crtc->active)
                return;
  
+       for_each_encoder_on_crtc(dev, crtc, encoder)
+               encoder->disable(encoder);
        /* Give the overlay scaler a chance to disable if it's on this pipe */
        intel_crtc_wait_for_pending_flips(crtc);
        drm_vblank_off(dev, pipe);
        intel_update_watermarks(dev);
  }
  
- static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
- {
-       /* XXX: When our outputs are all unaware of DPMS modes other than off
-        * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
-        */
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-               i9xx_crtc_enable(crtc);
-               break;
-       case DRM_MODE_DPMS_OFF:
-               i9xx_crtc_disable(crtc);
-               break;
-       }
- }
  static void i9xx_crtc_off(struct drm_crtc *crtc)
  {
  }
  
- /**
-  * Sets the power management mode of the pipe and plane.
-  */
- static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
+ static void intel_crtc_update_sarea(struct drm_crtc *crtc,
+                                   bool enabled)
  {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       bool enabled;
-       if (intel_crtc->dpms_mode == mode)
-               return;
-       intel_crtc->dpms_mode = mode;
-       dev_priv->display.dpms(crtc, mode);
  
        if (!dev->primary->master)
                return;
        if (!master_priv->sarea_priv)
                return;
  
-       enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF;
        switch (pipe) {
        case 0:
                master_priv->sarea_priv->pipeA_w = enabled ? crtc->mode.hdisplay : 0;
        }
  }
  
+ /**
+  * Sets the power management mode of the pipe and plane.
+  */
+ void intel_crtc_update_dpms(struct drm_crtc *crtc)
+ {
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_encoder *intel_encoder;
+       bool enable = false;
+       for_each_encoder_on_crtc(dev, crtc, intel_encoder)
+               enable |= intel_encoder->connectors_active;
+       if (enable)
+               dev_priv->display.crtc_enable(crtc);
+       else
+               dev_priv->display.crtc_disable(crtc);
+       intel_crtc_update_sarea(crtc, enable);
+ }
+ static void intel_crtc_noop(struct drm_crtc *crtc)
+ {
+ }
  static void intel_crtc_disable(struct drm_crtc *crtc)
  {
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
        struct drm_device *dev = crtc->dev;
+       struct drm_connector *connector;
        struct drm_i915_private *dev_priv = dev->dev_private;
  
-       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+       /* crtc should still be enabled when we disable it. */
+       WARN_ON(!crtc->enabled);
+       dev_priv->display.crtc_disable(crtc);
+       intel_crtc_update_sarea(crtc, false);
        dev_priv->display.off(crtc);
  
        assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane);
                mutex_lock(&dev->struct_mutex);
                intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
                mutex_unlock(&dev->struct_mutex);
+               crtc->fb = NULL;
+       }
+       /* Update computed state. */
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (!connector->encoder || !connector->encoder->crtc)
+                       continue;
+               if (connector->encoder->crtc != crtc)
+                       continue;
+               connector->dpms = DRM_MODE_DPMS_OFF;
+               to_intel_encoder(connector->encoder)->connectors_active = false;
        }
  }
  
- /* Prepare for a mode set.
-  *
-  * Note we could be a lot smarter here.  We need to figure out which outputs
-  * will be enabled, which disabled (in short, how the config will changes)
-  * and perform the minimum necessary steps to accomplish that, e.g. updating
-  * watermarks, FBC configuration, making sure PLLs are programmed correctly,
-  * panel fitting is in the proper state, etc.
-  */
- static void i9xx_crtc_prepare(struct drm_crtc *crtc)
+ void intel_modeset_disable(struct drm_device *dev)
  {
-       i9xx_crtc_disable(crtc);
+       struct drm_crtc *crtc;
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (crtc->enabled)
+                       intel_crtc_disable(crtc);
+       }
  }
  
static void i9xx_crtc_commit(struct drm_crtc *crtc)
void intel_encoder_noop(struct drm_encoder *encoder)
  {
-       i9xx_crtc_enable(crtc);
  }
  
static void ironlake_crtc_prepare(struct drm_crtc *crtc)
void intel_encoder_destroy(struct drm_encoder *encoder)
  {
-       ironlake_crtc_disable(crtc);
+       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
+       drm_encoder_cleanup(encoder);
+       kfree(intel_encoder);
  }
  
- static void ironlake_crtc_commit(struct drm_crtc *crtc)
+ /* Simple dpms helper for encodres with just one connector, no cloning and only
+  * one kind of off state. It clamps all !ON modes to fully OFF and changes the
+  * state of the entire output pipe. */
+ void intel_encoder_dpms(struct intel_encoder *encoder, int mode)
  {
-       ironlake_crtc_enable(crtc);
+       if (mode == DRM_MODE_DPMS_ON) {
+               encoder->connectors_active = true;
+               intel_crtc_update_dpms(encoder->base.crtc);
+       } else {
+               encoder->connectors_active = false;
+               intel_crtc_update_dpms(encoder->base.crtc);
+       }
  }
  
- void intel_encoder_prepare(struct drm_encoder *encoder)
+ /* Cross check the actual hw state with our own modeset state tracking (and it's
+  * internal consistency). */
+ static void intel_connector_check_state(struct intel_connector *connector)
  {
-       struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
-       /* lvds has its own version of prepare see intel_lvds_prepare */
-       encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
+       if (connector->get_hw_state(connector)) {
+               struct intel_encoder *encoder = connector->encoder;
+               struct drm_crtc *crtc;
+               bool encoder_enabled;
+               enum pipe pipe;
+               DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                             connector->base.base.id,
+                             drm_get_connector_name(&connector->base));
+               WARN(connector->base.dpms == DRM_MODE_DPMS_OFF,
+                    "wrong connector dpms state\n");
+               WARN(connector->base.encoder != &encoder->base,
+                    "active connector not linked to encoder\n");
+               WARN(!encoder->connectors_active,
+                    "encoder->connectors_active not set\n");
+               encoder_enabled = encoder->get_hw_state(encoder, &pipe);
+               WARN(!encoder_enabled, "encoder not enabled\n");
+               if (WARN_ON(!encoder->base.crtc))
+                       return;
+               crtc = encoder->base.crtc;
+               WARN(!crtc->enabled, "crtc not enabled\n");
+               WARN(!to_intel_crtc(crtc)->active, "crtc not active\n");
+               WARN(pipe != to_intel_crtc(crtc)->pipe,
+                    "encoder active on the wrong pipe\n");
+       }
  }
  
- void intel_encoder_commit(struct drm_encoder *encoder)
+ /* Even simpler default implementation, if there's really no special case to
+  * consider. */
+ void intel_connector_dpms(struct drm_connector *connector, int mode)
  {
-       struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
-       struct drm_device *dev = encoder->dev;
-       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+       struct intel_encoder *encoder = intel_attached_encoder(connector);
  
-       /* lvds has its own version of commit see intel_lvds_commit */
-       encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
+       /* All the simple cases only support two dpms states. */
+       if (mode != DRM_MODE_DPMS_ON)
+               mode = DRM_MODE_DPMS_OFF;
  
-       if (HAS_PCH_CPT(dev))
-               intel_cpt_verify_modeset(dev, intel_crtc->pipe);
+       if (mode == connector->dpms)
+               return;
+       connector->dpms = mode;
+       /* Only need to change hw state when actually enabled */
+       if (encoder->base.crtc)
+               intel_encoder_dpms(encoder, mode);
+       else
+               WARN_ON(encoder->connectors_active != false);
+       intel_modeset_check_state(connector->dev);
  }
  
- void intel_encoder_destroy(struct drm_encoder *encoder)
+ /* Simple connector->get_hw_state implementation for encoders that support only
+  * one connector and no cloning and hence the encoder state determines the state
+  * of the connector. */
+ bool intel_connector_get_hw_state(struct intel_connector *connector)
  {
-       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
+       enum pipe pipe = 0;
+       struct intel_encoder *encoder = connector->encoder;
  
-       drm_encoder_cleanup(encoder);
-       kfree(intel_encoder);
+       return encoder->get_hw_state(encoder, &pipe);
  }
  
  static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
        if (!(adjusted_mode->private_flags & INTEL_MODE_CRTC_TIMINGS_SET))
                drm_mode_set_crtcinfo(adjusted_mode, 0);
  
+       /* WaPruneModeWithIncorrectHsyncOffset: Cantiga+ cannot handle modes
+        * with a hsync front porch of 0.
+        */
+       if ((INTEL_INFO(dev)->gen > 4 || IS_G4X(dev)) &&
+               adjusted_mode->hsync_start == adjusted_mode->hdisplay)
+               return false;
        return true;
  }
  
@@@ -3728,6 -3767,7 +3767,7 @@@ static inline bool intel_panel_use_ssc(
   * true if they don't match).
   */
  static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
+                                        struct drm_framebuffer *fb,
                                         unsigned int *pipe_bpp,
                                         struct drm_display_mode *mode)
  {
         * also stays within the max display bpc discovered above.
         */
  
-       switch (crtc->fb->depth) {
+       switch (fb->depth) {
        case 8:
                bpc = 8; /* since we go through a colormap */
                break;
@@@ -4216,7 -4256,7 +4256,7 @@@ static int i9xx_crtc_mode_set(struct dr
                              struct drm_display_mode *mode,
                              struct drm_display_mode *adjusted_mode,
                              int x, int y,
-                             struct drm_framebuffer *old_fb)
+                             struct drm_framebuffer *fb)
  {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        I915_WRITE(DSPCNTR(plane), dspcntr);
        POSTING_READ(DSPCNTR(plane));
  
-       ret = intel_pipe_set_base(crtc, x, y, old_fb);
+       ret = intel_pipe_set_base(crtc, x, y, fb);
  
        intel_update_watermarks(dev);
  
@@@ -4560,63 -4600,78 +4600,78 @@@ static int ironlake_get_refclk(struct d
        return 120000;
  }
  
- static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
-                                 struct drm_display_mode *mode,
+ static void ironlake_set_pipeconf(struct drm_crtc *crtc,
                                  struct drm_display_mode *adjusted_mode,
-                                 int x, int y,
-                                 struct drm_framebuffer *old_fb)
+                                 bool dither)
  {
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = crtc->dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
-       int refclk, num_connectors = 0;
-       intel_clock_t clock, reduced_clock;
-       u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
-       bool ok, has_reduced_clock = false, is_sdvo = false;
-       bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
-       struct intel_encoder *encoder, *edp_encoder = NULL;
+       uint32_t val;
+       val = I915_READ(PIPECONF(pipe));
+       val &= ~PIPE_BPC_MASK;
+       switch (intel_crtc->bpp) {
+       case 18:
+               val |= PIPE_6BPC;
+               break;
+       case 24:
+               val |= PIPE_8BPC;
+               break;
+       case 30:
+               val |= PIPE_10BPC;
+               break;
+       case 36:
+               val |= PIPE_12BPC;
+               break;
+       default:
+               val |= PIPE_8BPC;
+               break;
+       }
+       val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK);
+       if (dither)
+               val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
+       val &= ~PIPECONF_INTERLACE_MASK;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+               val |= PIPECONF_INTERLACED_ILK;
+       else
+               val |= PIPECONF_PROGRESSIVE;
+       I915_WRITE(PIPECONF(pipe), val);
+       POSTING_READ(PIPECONF(pipe));
+ }
+ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
+                                   struct drm_display_mode *adjusted_mode,
+                                   intel_clock_t *clock,
+                                   bool *has_reduced_clock,
+                                   intel_clock_t *reduced_clock)
+ {
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_encoder *intel_encoder;
+       int refclk;
        const intel_limit_t *limit;
-       int ret;
-       struct fdi_m_n m_n = {0};
-       u32 temp;
-       int target_clock, pixel_multiplier, lane, link_bw, factor;
-       unsigned int pipe_bpp;
-       bool dither;
-       bool is_cpu_edp = false, is_pch_edp = false;
+       bool ret, is_sdvo = false, is_tv = false, is_lvds = false;
  
-       for_each_encoder_on_crtc(dev, crtc, encoder) {
-               switch (encoder->type) {
+       for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
+               switch (intel_encoder->type) {
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
                        break;
                case INTEL_OUTPUT_SDVO:
                case INTEL_OUTPUT_HDMI:
                        is_sdvo = true;
-                       if (encoder->needs_tv_clock)
+                       if (intel_encoder->needs_tv_clock)
                                is_tv = true;
                        break;
                case INTEL_OUTPUT_TVOUT:
                        is_tv = true;
                        break;
-               case INTEL_OUTPUT_ANALOG:
-                       is_crt = true;
-                       break;
-               case INTEL_OUTPUT_DISPLAYPORT:
-                       is_dp = true;
-                       break;
-               case INTEL_OUTPUT_EDP:
-                       is_dp = true;
-                       if (intel_encoder_is_pch_edp(&encoder->base))
-                               is_pch_edp = true;
-                       else
-                               is_cpu_edp = true;
-                       edp_encoder = encoder;
-                       break;
                }
-               num_connectors++;
        }
  
        refclk = ironlake_get_refclk(crtc);
         * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
         */
        limit = intel_limit(crtc, refclk);
-       ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
-                            &clock);
-       if (!ok) {
-               DRM_ERROR("Couldn't find PLL settings for mode!\n");
-               return -EINVAL;
-       }
-       /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc, true);
+       ret = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
+                             clock);
+       if (!ret)
+               return false;
  
        if (is_lvds && dev_priv->lvds_downclock_avail) {
                /*
                 * by using the FP0/FP1. In such case we will disable the LVDS
                 * downclock feature.
                */
-               has_reduced_clock = limit->find_pll(limit, crtc,
-                                                   dev_priv->lvds_downclock,
-                                                   refclk,
-                                                   &clock,
-                                                   &reduced_clock);
+               *has_reduced_clock = limit->find_pll(limit, crtc,
+                                                    dev_priv->lvds_downclock,
+                                                    refclk,
+                                                    clock,
+                                                    reduced_clock);
        }
  
        if (is_sdvo && is_tv)
-               i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock);
+               i9xx_adjust_sdvo_tv_clock(adjusted_mode, clock);
+       return true;
+ }
+ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode,
+                                 int x, int y,
+                                 struct drm_framebuffer *fb)
+ {
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+       int num_connectors = 0;
+       intel_clock_t clock, reduced_clock;
+       u32 dpll, fp = 0, fp2 = 0;
+       bool ok, has_reduced_clock = false, is_sdvo = false;
+       bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
+       struct intel_encoder *encoder, *edp_encoder = NULL;
+       int ret;
+       struct fdi_m_n m_n = {0};
+       u32 temp;
+       int target_clock, pixel_multiplier, lane, link_bw, factor;
+       unsigned int pipe_bpp;
+       bool dither;
+       bool is_cpu_edp = false, is_pch_edp = false;
+       for_each_encoder_on_crtc(dev, crtc, encoder) {
+               switch (encoder->type) {
+               case INTEL_OUTPUT_LVDS:
+                       is_lvds = true;
+                       break;
+               case INTEL_OUTPUT_SDVO:
+               case INTEL_OUTPUT_HDMI:
+                       is_sdvo = true;
+                       if (encoder->needs_tv_clock)
+                               is_tv = true;
+                       break;
+               case INTEL_OUTPUT_TVOUT:
+                       is_tv = true;
+                       break;
+               case INTEL_OUTPUT_ANALOG:
+                       is_crt = true;
+                       break;
+               case INTEL_OUTPUT_DISPLAYPORT:
+                       is_dp = true;
+                       break;
+               case INTEL_OUTPUT_EDP:
+                       is_dp = true;
+                       if (intel_encoder_is_pch_edp(&encoder->base))
+                               is_pch_edp = true;
+                       else
+                               is_cpu_edp = true;
+                       edp_encoder = encoder;
+                       break;
+               }
+               num_connectors++;
+       }
+       ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock,
+                                    &has_reduced_clock, &reduced_clock);
+       if (!ok) {
+               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               return -EINVAL;
+       }
  
+       /* Ensure that the cursor is valid for the new mode before changing... */
+       intel_crtc_update_cursor(crtc, true);
  
        /* FDI link */
        pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
                target_clock = adjusted_mode->clock;
  
        /* determine panel color depth */
-       temp = I915_READ(PIPECONF(pipe));
-       temp &= ~PIPE_BPC_MASK;
-       dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, mode);
-       switch (pipe_bpp) {
-       case 18:
-               temp |= PIPE_6BPC;
-               break;
-       case 24:
-               temp |= PIPE_8BPC;
-               break;
-       case 30:
-               temp |= PIPE_10BPC;
-               break;
-       case 36:
-               temp |= PIPE_12BPC;
-               break;
-       default:
+       dither = intel_choose_pipe_bpp_dither(crtc, fb, &pipe_bpp, mode);
+       if (is_lvds && dev_priv->lvds_dither)
+               dither = true;
+       if (pipe_bpp != 18 && pipe_bpp != 24 && pipe_bpp != 30 &&
+           pipe_bpp != 36) {
                WARN(1, "intel_choose_pipe_bpp returned invalid value %d\n",
-                       pipe_bpp);
-               temp |= PIPE_8BPC;
+                    pipe_bpp);
                pipe_bpp = 24;
-               break;
        }
        intel_crtc->bpp = pipe_bpp;
-       I915_WRITE(PIPECONF(pipe), temp);
  
        if (!lane) {
                /*
        else
                dpll |= PLL_REF_INPUT_DREFCLK;
  
-       /* setup pipeconf */
-       pipeconf = I915_READ(PIPECONF(pipe));
-       /* Set up the display plane register */
-       dspcntr = DISPPLANE_GAMMA_ENABLE;
        DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
        drm_mode_debug_printmodeline(mode);
  
                I915_WRITE(PCH_LVDS, temp);
        }
  
-       pipeconf &= ~PIPECONF_DITHER_EN;
-       pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
-       if ((is_lvds && dev_priv->lvds_dither) || dither) {
-               pipeconf |= PIPECONF_DITHER_EN;
-               pipeconf |= PIPECONF_DITHER_TYPE_SP;
-       }
        if (is_dp && !is_cpu_edp) {
                intel_dp_set_m_n(crtc, mode, adjusted_mode);
        } else {
                }
        }
  
-       pipeconf &= ~PIPECONF_INTERLACE_MASK;
        if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
-               pipeconf |= PIPECONF_INTERLACED_ILK;
                /* the chip adds 2 halflines automatically */
                adjusted_mode->crtc_vtotal -= 1;
                adjusted_mode->crtc_vblank_end -= 1;
                           adjusted_mode->crtc_hsync_start
                           - adjusted_mode->crtc_htotal/2);
        } else {
-               pipeconf |= PIPECONF_PROGRESSIVE;
                I915_WRITE(VSYNCSHIFT(pipe), 0);
        }
  
        if (is_cpu_edp)
                ironlake_set_pll_edp(crtc, adjusted_mode->clock);
  
-       I915_WRITE(PIPECONF(pipe), pipeconf);
-       POSTING_READ(PIPECONF(pipe));
+       ironlake_set_pipeconf(crtc, adjusted_mode, dither);
  
        intel_wait_for_vblank(dev, pipe);
  
-       I915_WRITE(DSPCNTR(plane), dspcntr);
+       /* Set up the display plane register */
+       I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE);
        POSTING_READ(DSPCNTR(plane));
  
-       ret = intel_pipe_set_base(crtc, x, y, old_fb);
+       ret = intel_pipe_set_base(crtc, x, y, fb);
  
        intel_update_watermarks(dev);
  
@@@ -4966,7 -5056,7 +5056,7 @@@ static int intel_crtc_mode_set(struct d
                               struct drm_display_mode *mode,
                               struct drm_display_mode *adjusted_mode,
                               int x, int y,
-                              struct drm_framebuffer *old_fb)
+                              struct drm_framebuffer *fb)
  {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        drm_vblank_pre_modeset(dev, pipe);
  
        ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode,
-                                             x, y, old_fb);
+                                             x, y, fb);
        drm_vblank_post_modeset(dev, pipe);
  
-       if (ret)
-               intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF;
-       else
-               intel_crtc->dpms_mode = DRM_MODE_DPMS_ON;
        return ret;
  }
  
@@@ -5057,6 -5142,91 +5142,91 @@@ static void g4x_write_eld(struct drm_co
        I915_WRITE(G4X_AUD_CNTL_ST, i);
  }
  
+ static void haswell_write_eld(struct drm_connector *connector,
+                                    struct drm_crtc *crtc)
+ {
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       uint8_t *eld = connector->eld;
+       struct drm_device *dev = crtc->dev;
+       uint32_t eldv;
+       uint32_t i;
+       int len;
+       int pipe = to_intel_crtc(crtc)->pipe;
+       int tmp;
+       int hdmiw_hdmiedid = HSW_AUD_EDID_DATA(pipe);
+       int aud_cntl_st = HSW_AUD_DIP_ELD_CTRL(pipe);
+       int aud_config = HSW_AUD_CFG(pipe);
+       int aud_cntrl_st2 = HSW_AUD_PIN_ELD_CP_VLD;
+       DRM_DEBUG_DRIVER("HDMI: Haswell Audio initialize....\n");
+       /* Audio output enable */
+       DRM_DEBUG_DRIVER("HDMI audio: enable codec\n");
+       tmp = I915_READ(aud_cntrl_st2);
+       tmp |= (AUDIO_OUTPUT_ENABLE_A << (pipe * 4));
+       I915_WRITE(aud_cntrl_st2, tmp);
+       /* Wait for 1 vertical blank */
+       intel_wait_for_vblank(dev, pipe);
+       /* Set ELD valid state */
+       tmp = I915_READ(aud_cntrl_st2);
+       DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%8x\n", tmp);
+       tmp |= (AUDIO_ELD_VALID_A << (pipe * 4));
+       I915_WRITE(aud_cntrl_st2, tmp);
+       tmp = I915_READ(aud_cntrl_st2);
+       DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%8x\n", tmp);
+       /* Enable HDMI mode */
+       tmp = I915_READ(aud_config);
+       DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%8x\n", tmp);
+       /* clear N_programing_enable and N_value_index */
+       tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE);
+       I915_WRITE(aud_config, tmp);
+       DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe));
+       eldv = AUDIO_ELD_VALID_A << (pipe * 4);
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+               DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n");
+               eld[5] |= (1 << 2);     /* Conn_Type, 0x1 = DisplayPort */
+               I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */
+       } else
+               I915_WRITE(aud_config, 0);
+       if (intel_eld_uptodate(connector,
+                              aud_cntrl_st2, eldv,
+                              aud_cntl_st, IBX_ELD_ADDRESS,
+                              hdmiw_hdmiedid))
+               return;
+       i = I915_READ(aud_cntrl_st2);
+       i &= ~eldv;
+       I915_WRITE(aud_cntrl_st2, i);
+       if (!eld[0])
+               return;
+       i = I915_READ(aud_cntl_st);
+       i &= ~IBX_ELD_ADDRESS;
+       I915_WRITE(aud_cntl_st, i);
+       i = (i >> 29) & DIP_PORT_SEL_MASK;              /* DIP_Port_Select, 0x1 = PortB */
+       DRM_DEBUG_DRIVER("port num:%d\n", i);
+       len = min_t(uint8_t, eld[2], 21);       /* 84 bytes of hw ELD buffer */
+       DRM_DEBUG_DRIVER("ELD size %d\n", len);
+       for (i = 0; i < len; i++)
+               I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i));
+       i = I915_READ(aud_cntrl_st2);
+       i |= eldv;
+       I915_WRITE(aud_cntrl_st2, i);
+ }
  static void ironlake_write_eld(struct drm_connector *connector,
                                     struct drm_crtc *crtc)
  {
        int aud_config;
        int aud_cntl_st;
        int aud_cntrl_st2;
+       int pipe = to_intel_crtc(crtc)->pipe;
  
        if (HAS_PCH_IBX(connector->dev)) {
-               hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID_A;
-               aud_config = IBX_AUD_CONFIG_A;
-               aud_cntl_st = IBX_AUD_CNTL_ST_A;
+               hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe);
+               aud_config = IBX_AUD_CFG(pipe);
+               aud_cntl_st = IBX_AUD_CNTL_ST(pipe);
                aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
        } else {
-               hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID_A;
-               aud_config = CPT_AUD_CONFIG_A;
-               aud_cntl_st = CPT_AUD_CNTL_ST_A;
+               hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe);
+               aud_config = CPT_AUD_CFG(pipe);
+               aud_cntl_st = CPT_AUD_CNTL_ST(pipe);
                aud_cntrl_st2 = CPT_AUD_CNTRL_ST2;
        }
  
-       i = to_intel_crtc(crtc)->pipe;
-       hdmiw_hdmiedid += i * 0x100;
-       aud_cntl_st += i * 0x100;
-       aud_config += i * 0x100;
-       DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(i));
+       DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe));
  
        i = I915_READ(aud_cntl_st);
-       i = (i >> 29) & 0x3;            /* DIP_Port_Select, 0x1 = PortB */
+       i = (i >> 29) & DIP_PORT_SEL_MASK;              /* DIP_Port_Select, 0x1 = PortB */
        if (!i) {
                DRM_DEBUG_DRIVER("Audio directed to unknown port\n");
                /* operate blindly on all ports */
@@@ -5337,8 -5503,6 +5503,6 @@@ static int intel_crtc_cursor_set(struc
        uint32_t addr;
        int ret;
  
-       DRM_DEBUG_KMS("\n");
        /* if we want to turn off the cursor ignore width and height */
        if (!handle) {
                DRM_DEBUG_KMS("cursor off\n");
@@@ -5584,17 -5748,18 +5748,18 @@@ mode_fits_in_fbdev(struct drm_device *d
        return fb;
  }
  
- bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
-                               struct drm_connector *connector,
+ bool intel_get_load_detect_pipe(struct drm_connector *connector,
                                struct drm_display_mode *mode,
                                struct intel_load_detect_pipe *old)
  {
        struct intel_crtc *intel_crtc;
+       struct intel_encoder *intel_encoder =
+               intel_attached_encoder(connector);
        struct drm_crtc *possible_crtc;
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_crtc *crtc = NULL;
        struct drm_device *dev = encoder->dev;
-       struct drm_framebuffer *old_fb;
+       struct drm_framebuffer *fb;
        int i = -1;
  
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
        if (encoder->crtc) {
                crtc = encoder->crtc;
  
-               intel_crtc = to_intel_crtc(crtc);
-               old->dpms_mode = intel_crtc->dpms_mode;
+               old->dpms_mode = connector->dpms;
                old->load_detect_temp = false;
  
                /* Make sure the crtc and connector are running */
-               if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
-                       struct drm_encoder_helper_funcs *encoder_funcs;
-                       struct drm_crtc_helper_funcs *crtc_funcs;
-                       crtc_funcs = crtc->helper_private;
-                       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
-                       encoder_funcs = encoder->helper_private;
-                       encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
-               }
+               if (connector->dpms != DRM_MODE_DPMS_ON)
+                       connector->funcs->dpms(connector, DRM_MODE_DPMS_ON);
  
                return true;
        }
                return false;
        }
  
-       encoder->crtc = crtc;
-       connector->encoder = encoder;
+       intel_encoder->new_crtc = to_intel_crtc(crtc);
+       to_intel_connector(connector)->new_encoder = intel_encoder;
  
        intel_crtc = to_intel_crtc(crtc);
-       old->dpms_mode = intel_crtc->dpms_mode;
+       old->dpms_mode = connector->dpms;
        old->load_detect_temp = true;
        old->release_fb = NULL;
  
        if (!mode)
                mode = &load_detect_mode;
  
-       old_fb = crtc->fb;
        /* We need a framebuffer large enough to accommodate all accesses
         * that the plane may generate whilst we perform load detection.
         * We can not rely on the fbcon either being present (we get called
         * not even exist) or that it is large enough to satisfy the
         * requested mode.
         */
-       crtc->fb = mode_fits_in_fbdev(dev, mode);
-       if (crtc->fb == NULL) {
+       fb = mode_fits_in_fbdev(dev, mode);
+       if (fb == NULL) {
                DRM_DEBUG_KMS("creating tmp fb for load-detection\n");
-               crtc->fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32);
-               old->release_fb = crtc->fb;
+               fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32);
+               old->release_fb = fb;
        } else
                DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
-       if (IS_ERR(crtc->fb)) {
+       if (IS_ERR(fb)) {
                DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
-               crtc->fb = old_fb;
-               return false;
+               goto fail;
        }
  
-       if (!drm_crtc_helper_set_mode(crtc, mode, 0, 0, old_fb)) {
+       if (!intel_set_mode(crtc, mode, 0, 0, fb)) {
                DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
                if (old->release_fb)
                        old->release_fb->funcs->destroy(old->release_fb);
-               crtc->fb = old_fb;
-               return false;
+               goto fail;
        }
  
        /* let the connector get through one full cycle before testing */
        intel_wait_for_vblank(dev, intel_crtc->pipe);
  
        return true;
+ fail:
+       connector->encoder = NULL;
+       encoder->crtc = NULL;
+       return false;
  }
  
- void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
-                                   struct drm_connector *connector,
+ void intel_release_load_detect_pipe(struct drm_connector *connector,
                                    struct intel_load_detect_pipe *old)
  {
+       struct intel_encoder *intel_encoder =
+               intel_attached_encoder(connector);
        struct drm_encoder *encoder = &intel_encoder->base;
-       struct drm_device *dev = encoder->dev;
-       struct drm_crtc *crtc = encoder->crtc;
-       struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
  
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
                      connector->base.id, drm_get_connector_name(connector),
                      encoder->base.id, drm_get_encoder_name(encoder));
  
        if (old->load_detect_temp) {
-               connector->encoder = NULL;
-               drm_helper_disable_unused_functions(dev);
+               struct drm_crtc *crtc = encoder->crtc;
+               to_intel_connector(connector)->new_encoder = NULL;
+               intel_encoder->new_crtc = NULL;
+               intel_set_mode(crtc, NULL, 0, 0, NULL);
  
                if (old->release_fb)
                        old->release_fb->funcs->destroy(old->release_fb);
        }
  
        /* Switch crtc and encoder back off if necessary */
-       if (old->dpms_mode != DRM_MODE_DPMS_ON) {
-               encoder_funcs->dpms(encoder, old->dpms_mode);
-               crtc_funcs->dpms(crtc, old->dpms_mode);
-       }
+       if (old->dpms_mode != DRM_MODE_DPMS_ON)
+               connector->funcs->dpms(connector, old->dpms_mode);
  }
  
  /* Returns the clock of the currently programmed mode of the given pipe. */
@@@ -5850,46 -6004,6 +6004,6 @@@ struct drm_display_mode *intel_crtc_mod
        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;
-       if (!list_empty(&dev_priv->mm.active_list)) {
-               /* Still processing requests, so just re-arm the timer. */
-               mod_timer(&dev_priv->idle_timer, jiffies +
-                         msecs_to_jiffies(GPU_IDLE_TIMEOUT));
-               return;
-       }
-       dev_priv->busy = false;
-       queue_work(dev_priv->wq, &dev_priv->idle_work);
- }
- #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;
-       struct intel_framebuffer *intel_fb;
-       intel_fb = to_intel_framebuffer(crtc->fb);
-       if (intel_fb && intel_fb->obj->active) {
-               /* The framebuffer is still being accessed by the GPU. */
-               mod_timer(&intel_crtc->idle_timer, jiffies +
-                         msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
-               return;
-       }
-       intel_crtc->busy = false;
-       queue_work(dev_priv->wq, &dev_priv->idle_work);
- }
  static void intel_increase_pllclock(struct drm_crtc *crtc)
  {
        struct drm_device *dev = crtc->dev;
                if (dpll & DISPLAY_RATE_SELECT_FPA1)
                        DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
        }
-       /* Schedule downclock */
-       mod_timer(&intel_crtc->idle_timer, jiffies +
-                 msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
  }
  
  static void intel_decrease_pllclock(struct drm_crtc *crtc)
  
  }
  
- /**
-  * 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)
+ void intel_mark_busy(struct drm_device *dev)
+ {
+       i915_update_gfx_val(dev->dev_private);
+ }
+ void intel_mark_idle(struct drm_device *dev)
  {
-       drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
-                                                   idle_work);
-       struct drm_device *dev = dev_priv->dev;
+ }
+ void intel_mark_fb_busy(struct drm_i915_gem_object *obj)
+ {
+       struct drm_device *dev = obj->base.dev;
        struct drm_crtc *crtc;
-       struct intel_crtc *intel_crtc;
  
        if (!i915_powersave)
                return;
  
-       mutex_lock(&dev->struct_mutex);
-       i915_update_gfx_val(dev_priv);
        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);
+               if (to_intel_framebuffer(crtc->fb)->obj == obj)
+                       intel_increase_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_i915_gem_object *obj)
+ void intel_mark_fb_idle(struct drm_i915_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;
-       if (!dev_priv->busy) {
-               intel_sanitize_pm(dev);
-               dev_priv->busy = true;
-       } else
-               mod_timer(&dev_priv->idle_timer, jiffies +
-                         msecs_to_jiffies(GPU_IDLE_TIMEOUT));
+       struct drm_device *dev = obj->base.dev;
+       struct drm_crtc *crtc;
  
-       if (obj == NULL)
+       if (!i915_powersave)
                return;
  
        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);
-                               intel_crtc->busy = true;
-                       } else {
-                               /* Busy -> busy, put off timer */
-                               mod_timer(&intel_crtc->idle_timer, jiffies +
-                                         msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
-                       }
-               }
+               if (to_intel_framebuffer(crtc->fb)->obj == obj)
+                       intel_decrease_pllclock(crtc);
        }
  }
  
@@@ -6394,7 -6461,7 +6461,7 @@@ static int intel_gen7_queue_flip(struc
        default:
                WARN_ONCE(1, "unknown plane in flip command\n");
                ret = -ENODEV;
-               goto err;
+               goto err_unpin;
        }
  
        ret = intel_ring_begin(ring, 4);
@@@ -6502,7 -6569,7 +6569,7 @@@ static int intel_crtc_page_flip(struct 
                goto cleanup_pending;
  
        intel_disable_fbc(dev);
-       intel_mark_busy(dev, obj);
+       intel_mark_fb_busy(obj);
        mutex_unlock(&dev->struct_mutex);
  
        trace_i915_flip_request(intel_crtc->plane, obj);
@@@ -6527,81 -6594,807 +6594,807 @@@ free_work
        return ret;
  }
  
- static void intel_sanitize_modesetting(struct drm_device *dev,
-                                      int pipe, int plane)
+ static struct drm_crtc_helper_funcs intel_helper_funcs = {
+       .mode_set_base_atomic = intel_pipe_set_base_atomic,
+       .load_lut = intel_crtc_load_lut,
+       .disable = intel_crtc_noop,
+ };
+ bool intel_encoder_check_is_cloned(struct intel_encoder *encoder)
  {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 reg, val;
-       int i;
+       struct intel_encoder *other_encoder;
+       struct drm_crtc *crtc = &encoder->new_crtc->base;
  
-       /* Clear any frame start delays used for debugging left by the BIOS */
-       for_each_pipe(i) {
-               reg = PIPECONF(i);
-               I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
+       if (WARN_ON(!crtc))
+               return false;
+       list_for_each_entry(other_encoder,
+                           &crtc->dev->mode_config.encoder_list,
+                           base.head) {
+               if (&other_encoder->new_crtc->base != crtc ||
+                   encoder == other_encoder)
+                       continue;
+               else
+                       return true;
        }
  
-       if (HAS_PCH_SPLIT(dev))
-               return;
+       return false;
+ }
  
-       /* Who knows what state these registers were left in by the BIOS or
-        * grub?
-        *
-        * If we leave the registers in a conflicting state (e.g. with the
-        * display plane reading from the other pipe than the one we intend
-        * to use) then when we attempt to teardown the active mode, we will
-        * not disable the pipes and planes in the correct order -- leaving
-        * a plane reading from a disabled pipe and possibly leading to
-        * undefined behaviour.
+ static bool intel_encoder_crtc_ok(struct drm_encoder *encoder,
+                                 struct drm_crtc *crtc)
+ {
+       struct drm_device *dev;
+       struct drm_crtc *tmp;
+       int crtc_mask = 1;
+       WARN(!crtc, "checking null crtc?\n");
+       dev = crtc->dev;
+       list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
+               if (tmp == crtc)
+                       break;
+               crtc_mask <<= 1;
+       }
+       if (encoder->possible_crtcs & crtc_mask)
+               return true;
+       return false;
+ }
+ /**
+  * intel_modeset_update_staged_output_state
+  *
+  * Updates the staged output configuration state, e.g. after we've read out the
+  * current hw state.
+  */
+ static void intel_modeset_update_staged_output_state(struct drm_device *dev)
+ {
+       struct intel_encoder *encoder;
+       struct intel_connector *connector;
+       list_for_each_entry(connector, &dev->mode_config.connector_list,
+                           base.head) {
+               connector->new_encoder =
+                       to_intel_encoder(connector->base.encoder);
+       }
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               encoder->new_crtc =
+                       to_intel_crtc(encoder->base.crtc);
+       }
+ }
+ /**
+  * intel_modeset_commit_output_state
+  *
+  * This function copies the stage display pipe configuration to the real one.
+  */
+ static void intel_modeset_commit_output_state(struct drm_device *dev)
+ {
+       struct intel_encoder *encoder;
+       struct intel_connector *connector;
+       list_for_each_entry(connector, &dev->mode_config.connector_list,
+                           base.head) {
+               connector->base.encoder = &connector->new_encoder->base;
+       }
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               encoder->base.crtc = &encoder->new_crtc->base;
+       }
+ }
+ static struct drm_display_mode *
+ intel_modeset_adjusted_mode(struct drm_crtc *crtc,
+                           struct drm_display_mode *mode)
+ {
+       struct drm_device *dev = crtc->dev;
+       struct drm_display_mode *adjusted_mode;
+       struct drm_encoder_helper_funcs *encoder_funcs;
+       struct intel_encoder *encoder;
+       adjusted_mode = drm_mode_duplicate(dev, mode);
+       if (!adjusted_mode)
+               return ERR_PTR(-ENOMEM);
+       /* Pass our mode to the connectors and the CRTC to give them a chance to
+        * adjust it according to limitations or connector properties, and also
+        * a chance to reject the mode entirely.
         */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
  
-       reg = DSPCNTR(plane);
-       val = I915_READ(reg);
+               if (&encoder->new_crtc->base != crtc)
+                       continue;
+               encoder_funcs = encoder->base.helper_private;
+               if (!(encoder_funcs->mode_fixup(&encoder->base, mode,
+                                               adjusted_mode))) {
+                       DRM_DEBUG_KMS("Encoder fixup failed\n");
+                       goto fail;
+               }
+       }
  
-       if ((val & DISPLAY_PLANE_ENABLE) == 0)
-               return;
-       if (!!(val & DISPPLANE_SEL_PIPE_MASK) == pipe)
-               return;
+       if (!(intel_crtc_mode_fixup(crtc, mode, adjusted_mode))) {
+               DRM_DEBUG_KMS("CRTC fixup failed\n");
+               goto fail;
+       }
+       DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
  
-       /* This display plane is active and attached to the other CPU pipe. */
-       pipe = !pipe;
+       return adjusted_mode;
+ fail:
+       drm_mode_destroy(dev, adjusted_mode);
+       return ERR_PTR(-EINVAL);
+ }
  
-       /* Disable the plane and wait for it to stop reading from the pipe. */
-       intel_disable_plane(dev_priv, plane, pipe);
-       intel_disable_pipe(dev_priv, pipe);
+ /* Computes which crtcs are affected and sets the relevant bits in the mask. For
+  * simplicity we use the crtc's pipe number (because it's easier to obtain). */
+ static void
+ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes,
+                            unsigned *prepare_pipes, unsigned *disable_pipes)
+ {
+       struct intel_crtc *intel_crtc;
+       struct drm_device *dev = crtc->dev;
+       struct intel_encoder *encoder;
+       struct intel_connector *connector;
+       struct drm_crtc *tmp_crtc;
+       *disable_pipes = *modeset_pipes = *prepare_pipes = 0;
+       /* Check which crtcs have changed outputs connected to them, these need
+        * to be part of the prepare_pipes mask. We don't (yet) support global
+        * modeset across multiple crtcs, so modeset_pipes will only have one
+        * bit set at most. */
+       list_for_each_entry(connector, &dev->mode_config.connector_list,
+                           base.head) {
+               if (connector->base.encoder == &connector->new_encoder->base)
+                       continue;
+               if (connector->base.encoder) {
+                       tmp_crtc = connector->base.encoder->crtc;
+                       *prepare_pipes |= 1 << to_intel_crtc(tmp_crtc)->pipe;
+               }
+               if (connector->new_encoder)
+                       *prepare_pipes |=
+                               1 << connector->new_encoder->new_crtc->pipe;
+       }
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               if (encoder->base.crtc == &encoder->new_crtc->base)
+                       continue;
+               if (encoder->base.crtc) {
+                       tmp_crtc = encoder->base.crtc;
+                       *prepare_pipes |= 1 << to_intel_crtc(tmp_crtc)->pipe;
+               }
+               if (encoder->new_crtc)
+                       *prepare_pipes |= 1 << encoder->new_crtc->pipe;
+       }
+       /* Check for any pipes that will be fully disabled ... */
+       list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
+                           base.head) {
+               bool used = false;
+               /* Don't try to disable disabled crtcs. */
+               if (!intel_crtc->base.enabled)
+                       continue;
+               list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                                   base.head) {
+                       if (encoder->new_crtc == intel_crtc)
+                               used = true;
+               }
+               if (!used)
+                       *disable_pipes |= 1 << intel_crtc->pipe;
+       }
+       /* set_mode is also used to update properties on life display pipes. */
+       intel_crtc = to_intel_crtc(crtc);
+       if (crtc->enabled)
+               *prepare_pipes |= 1 << intel_crtc->pipe;
+       /* We only support modeset on one single crtc, hence we need to do that
+        * only for the passed in crtc iff we change anything else than just
+        * disable crtcs.
+        *
+        * This is actually not true, to be fully compatible with the old crtc
+        * helper we automatically disable _any_ output (i.e. doesn't need to be
+        * connected to the crtc we're modesetting on) if it's disconnected.
+        * Which is a rather nutty api (since changed the output configuration
+        * without userspace's explicit request can lead to confusion), but
+        * alas. Hence we currently need to modeset on all pipes we prepare. */
+       if (*prepare_pipes)
+               *modeset_pipes = *prepare_pipes;
+       /* ... and mask these out. */
+       *modeset_pipes &= ~(*disable_pipes);
+       *prepare_pipes &= ~(*disable_pipes);
  }
  
- static void intel_crtc_reset(struct drm_crtc *crtc)
+ static bool intel_crtc_in_use(struct drm_crtc *crtc)
  {
+       struct drm_encoder *encoder;
        struct drm_device *dev = crtc->dev;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
  
-       /* Reset flags back to the 'unknown' status so that they
-        * will be correctly set on the initial modeset.
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+               if (encoder->crtc == crtc)
+                       return true;
+       return false;
+ }
+ static void
+ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
+ {
+       struct intel_encoder *intel_encoder;
+       struct intel_crtc *intel_crtc;
+       struct drm_connector *connector;
+       list_for_each_entry(intel_encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               if (!intel_encoder->base.crtc)
+                       continue;
+               intel_crtc = to_intel_crtc(intel_encoder->base.crtc);
+               if (prepare_pipes & (1 << intel_crtc->pipe))
+                       intel_encoder->connectors_active = false;
+       }
+       intel_modeset_commit_output_state(dev);
+       /* Update computed state. */
+       list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
+                           base.head) {
+               intel_crtc->base.enabled = intel_crtc_in_use(&intel_crtc->base);
+       }
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (!connector->encoder || !connector->encoder->crtc)
+                       continue;
+               intel_crtc = to_intel_crtc(connector->encoder->crtc);
+               if (prepare_pipes & (1 << intel_crtc->pipe)) {
+                       struct drm_property *dpms_property =
+                               dev->mode_config.dpms_property;
+                       connector->dpms = DRM_MODE_DPMS_ON;
+                       drm_connector_property_set_value(connector,
+                                                        dpms_property,
+                                                        DRM_MODE_DPMS_ON);
+                       intel_encoder = to_intel_encoder(connector->encoder);
+                       intel_encoder->connectors_active = true;
+               }
+       }
+ }
+ #define for_each_intel_crtc_masked(dev, mask, intel_crtc) \
+       list_for_each_entry((intel_crtc), \
+                           &(dev)->mode_config.crtc_list, \
+                           base.head) \
+               if (mask & (1 <<(intel_crtc)->pipe)) \
+ void
+ intel_modeset_check_state(struct drm_device *dev)
+ {
+       struct intel_crtc *crtc;
+       struct intel_encoder *encoder;
+       struct intel_connector *connector;
+       list_for_each_entry(connector, &dev->mode_config.connector_list,
+                           base.head) {
+               /* This also checks the encoder/connector hw state with the
+                * ->get_hw_state callbacks. */
+               intel_connector_check_state(connector);
+               WARN(&connector->new_encoder->base != connector->base.encoder,
+                    "connector's staged encoder doesn't match current encoder\n");
+       }
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               bool enabled = false;
+               bool active = false;
+               enum pipe pipe, tracked_pipe;
+               DRM_DEBUG_KMS("[ENCODER:%d:%s]\n",
+                             encoder->base.base.id,
+                             drm_get_encoder_name(&encoder->base));
+               WARN(&encoder->new_crtc->base != encoder->base.crtc,
+                    "encoder's stage crtc doesn't match current crtc\n");
+               WARN(encoder->connectors_active && !encoder->base.crtc,
+                    "encoder's active_connectors set, but no crtc\n");
+               list_for_each_entry(connector, &dev->mode_config.connector_list,
+                                   base.head) {
+                       if (connector->base.encoder != &encoder->base)
+                               continue;
+                       enabled = true;
+                       if (connector->base.dpms != DRM_MODE_DPMS_OFF)
+                               active = true;
+               }
+               WARN(!!encoder->base.crtc != enabled,
+                    "encoder's enabled state mismatch "
+                    "(expected %i, found %i)\n",
+                    !!encoder->base.crtc, enabled);
+               WARN(active && !encoder->base.crtc,
+                    "active encoder with no crtc\n");
+               WARN(encoder->connectors_active != active,
+                    "encoder's computed active state doesn't match tracked active state "
+                    "(expected %i, found %i)\n", active, encoder->connectors_active);
+               active = encoder->get_hw_state(encoder, &pipe);
+               WARN(active != encoder->connectors_active,
+                    "encoder's hw state doesn't match sw tracking "
+                    "(expected %i, found %i)\n",
+                    encoder->connectors_active, active);
+               if (!encoder->base.crtc)
+                       continue;
+               tracked_pipe = to_intel_crtc(encoder->base.crtc)->pipe;
+               WARN(active && pipe != tracked_pipe,
+                    "active encoder's pipe doesn't match"
+                    "(expected %i, found %i)\n",
+                    tracked_pipe, pipe);
+       }
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+                           base.head) {
+               bool enabled = false;
+               bool active = false;
+               DRM_DEBUG_KMS("[CRTC:%d]\n",
+                             crtc->base.base.id);
+               WARN(crtc->active && !crtc->base.enabled,
+                    "active crtc, but not enabled in sw tracking\n");
+               list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                                   base.head) {
+                       if (encoder->base.crtc != &crtc->base)
+                               continue;
+                       enabled = true;
+                       if (encoder->connectors_active)
+                               active = true;
+               }
+               WARN(active != crtc->active,
+                    "crtc's computed active state doesn't match tracked active state "
+                    "(expected %i, found %i)\n", active, crtc->active);
+               WARN(enabled != crtc->base.enabled,
+                    "crtc's computed enabled state doesn't match tracked enabled state "
+                    "(expected %i, found %i)\n", enabled, crtc->base.enabled);
+               assert_pipe(dev->dev_private, crtc->pipe, crtc->active);
+       }
+ }
+ bool intel_set_mode(struct drm_crtc *crtc,
+                   struct drm_display_mode *mode,
+                   int x, int y, struct drm_framebuffer *fb)
+ {
+       struct drm_device *dev = crtc->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
+       struct drm_encoder_helper_funcs *encoder_funcs;
+       struct drm_encoder *encoder;
+       struct intel_crtc *intel_crtc;
+       unsigned disable_pipes, prepare_pipes, modeset_pipes;
+       bool ret = true;
+       intel_modeset_affected_pipes(crtc, &modeset_pipes,
+                                    &prepare_pipes, &disable_pipes);
+       DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n",
+                     modeset_pipes, prepare_pipes, disable_pipes);
+       for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
+               intel_crtc_disable(&intel_crtc->base);
+       saved_hwmode = crtc->hwmode;
+       saved_mode = crtc->mode;
+       /* Hack: Because we don't (yet) support global modeset on multiple
+        * crtcs, we don't keep track of the new mode for more than one crtc.
+        * Hence simply check whether any bit is set in modeset_pipes in all the
+        * pieces of code that are not yet converted to deal with mutliple crtcs
+        * changing their mode at the same time. */
+       adjusted_mode = NULL;
+       if (modeset_pipes) {
+               adjusted_mode = intel_modeset_adjusted_mode(crtc, mode);
+               if (IS_ERR(adjusted_mode)) {
+                       return false;
+               }
+       }
+       for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) {
+               if (intel_crtc->base.enabled)
+                       dev_priv->display.crtc_disable(&intel_crtc->base);
+       }
+       /* crtc->mode is already used by the ->mode_set callbacks, hence we need
+        * to set it here already despite that we pass it down the callchain.
         */
-       intel_crtc->dpms_mode = -1;
+       if (modeset_pipes)
+               crtc->mode = *mode;
+       /* Only after disabling all output pipelines that will be changed can we
+        * update the the output configuration. */
+       intel_modeset_update_state(dev, prepare_pipes);
  
-       /* We need to fix up any BIOS configuration that conflicts with
-        * our expectations.
+       /* Set up the DPLL and any encoders state that needs to adjust or depend
+        * on the DPLL.
         */
-       intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane);
+       for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
+               ret = !intel_crtc_mode_set(&intel_crtc->base,
+                                          mode, adjusted_mode,
+                                          x, y, fb);
+               if (!ret)
+                   goto done;
+               list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+                       if (encoder->crtc != &intel_crtc->base)
+                               continue;
+                       DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n",
+                               encoder->base.id, drm_get_encoder_name(encoder),
+                               mode->base.id, mode->name);
+                       encoder_funcs = encoder->helper_private;
+                       encoder_funcs->mode_set(encoder, mode, adjusted_mode);
+               }
+       }
+       /* Now enable the clocks, plane, pipe, and connectors that we set up. */
+       for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc)
+               dev_priv->display.crtc_enable(&intel_crtc->base);
+       if (modeset_pipes) {
+               /* Store real post-adjustment hardware mode. */
+               crtc->hwmode = *adjusted_mode;
+               /* Calculate and store various constants which
+                * are later needed by vblank and swap-completion
+                * timestamping. They are derived from true hwmode.
+                */
+               drm_calc_timestamping_constants(crtc);
+       }
+       /* FIXME: add subpixel order */
+ done:
+       drm_mode_destroy(dev, adjusted_mode);
+       if (!ret && crtc->enabled) {
+               crtc->hwmode = saved_hwmode;
+               crtc->mode = saved_mode;
+       } else {
+               intel_modeset_check_state(dev);
+       }
+       return ret;
  }
  
- static struct drm_crtc_helper_funcs intel_helper_funcs = {
-       .dpms = intel_crtc_dpms,
-       .mode_fixup = intel_crtc_mode_fixup,
-       .mode_set = intel_crtc_mode_set,
-       .mode_set_base = intel_pipe_set_base,
-       .mode_set_base_atomic = intel_pipe_set_base_atomic,
-       .load_lut = intel_crtc_load_lut,
-       .disable = intel_crtc_disable,
- };
+ #undef for_each_intel_crtc_masked
+ static void intel_set_config_free(struct intel_set_config *config)
+ {
+       if (!config)
+               return;
+       kfree(config->save_connector_encoders);
+       kfree(config->save_encoder_crtcs);
+       kfree(config);
+ }
+ static int intel_set_config_save_state(struct drm_device *dev,
+                                      struct intel_set_config *config)
+ {
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+       int count;
+       config->save_encoder_crtcs =
+               kcalloc(dev->mode_config.num_encoder,
+                       sizeof(struct drm_crtc *), GFP_KERNEL);
+       if (!config->save_encoder_crtcs)
+               return -ENOMEM;
+       config->save_connector_encoders =
+               kcalloc(dev->mode_config.num_connector,
+                       sizeof(struct drm_encoder *), GFP_KERNEL);
+       if (!config->save_connector_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(encoder, &dev->mode_config.encoder_list, head) {
+               config->save_encoder_crtcs[count++] = encoder->crtc;
+       }
+       count = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               config->save_connector_encoders[count++] = connector->encoder;
+       }
+       return 0;
+ }
+ static void intel_set_config_restore_state(struct drm_device *dev,
+                                          struct intel_set_config *config)
+ {
+       struct intel_encoder *encoder;
+       struct intel_connector *connector;
+       int count;
+       count = 0;
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+               encoder->new_crtc =
+                       to_intel_crtc(config->save_encoder_crtcs[count++]);
+       }
+       count = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) {
+               connector->new_encoder =
+                       to_intel_encoder(config->save_connector_encoders[count++]);
+       }
+ }
+ static void
+ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
+                                     struct intel_set_config *config)
+ {
+       /* 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_KMS("crtc has no fb, full mode set\n");
+                       config->mode_changed = true;
+               } else if (set->fb == NULL) {
+                       config->mode_changed = true;
+               } else if (set->fb->depth != set->crtc->fb->depth) {
+                       config->mode_changed = true;
+               } else if (set->fb->bits_per_pixel !=
+                          set->crtc->fb->bits_per_pixel) {
+                       config->mode_changed = true;
+               } else
+                       config->fb_changed = true;
+       }
+       if (set->fb && (set->x != set->crtc->x || set->y != set->crtc->y))
+               config->fb_changed = true;
+       if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
+               DRM_DEBUG_KMS("modes are different, full mode set\n");
+               drm_mode_debug_printmodeline(&set->crtc->mode);
+               drm_mode_debug_printmodeline(set->mode);
+               config->mode_changed = true;
+       }
+ }
+ static int
+ intel_modeset_stage_output_state(struct drm_device *dev,
+                                struct drm_mode_set *set,
+                                struct intel_set_config *config)
+ {
+       struct drm_crtc *new_crtc;
+       struct intel_connector *connector;
+       struct intel_encoder *encoder;
+       int count, ro;
+       /* The upper layers ensure that we either disabl a crtc or have a list
+        * of connectors. For paranoia, double-check this. */
+       WARN_ON(!set->fb && (set->num_connectors != 0));
+       WARN_ON(set->fb && (set->num_connectors == 0));
+       count = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list,
+                           base.head) {
+               /* Otherwise traverse passed in connector list and get encoders
+                * for them. */
+               for (ro = 0; ro < set->num_connectors; ro++) {
+                       if (set->connectors[ro] == &connector->base) {
+                               connector->new_encoder = connector->encoder;
+                               break;
+                       }
+               }
+               /* If we disable the crtc, disable all its connectors. Also, if
+                * the connector is on the changing crtc but not on the new
+                * connector list, disable it. */
+               if ((!set->fb || ro == set->num_connectors) &&
+                   connector->base.encoder &&
+                   connector->base.encoder->crtc == set->crtc) {
+                       connector->new_encoder = NULL;
+                       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
+                               connector->base.base.id,
+                               drm_get_connector_name(&connector->base));
+               }
+               if (&connector->new_encoder->base != connector->base.encoder) {
+                       DRM_DEBUG_KMS("encoder changed, full mode switch\n");
+                       config->mode_changed = true;
+               }
+               /* Disable all disconnected encoders. */
+               if (connector->base.status == connector_status_disconnected)
+                       connector->new_encoder = NULL;
+       }
+       /* connector->new_encoder is now updated for all connectors. */
+       /* Update crtc of enabled connectors. */
+       count = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list,
+                           base.head) {
+               if (!connector->new_encoder)
+                       continue;
+               new_crtc = connector->new_encoder->base.crtc;
+               for (ro = 0; ro < set->num_connectors; ro++) {
+                       if (set->connectors[ro] == &connector->base)
+                               new_crtc = set->crtc;
+               }
+               /* Make sure the new CRTC will work with the encoder */
+               if (!intel_encoder_crtc_ok(&connector->new_encoder->base,
+                                          new_crtc)) {
+                       return -EINVAL;
+               }
+               connector->encoder->new_crtc = to_intel_crtc(new_crtc);
+               DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
+                       connector->base.base.id,
+                       drm_get_connector_name(&connector->base),
+                       new_crtc->base.id);
+       }
+       /* Check for any encoders that needs to be disabled. */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               list_for_each_entry(connector,
+                                   &dev->mode_config.connector_list,
+                                   base.head) {
+                       if (connector->new_encoder == encoder) {
+                               WARN_ON(!connector->new_encoder->new_crtc);
+                               goto next_encoder;
+                       }
+               }
+               encoder->new_crtc = NULL;
+ next_encoder:
+               /* Only now check for crtc changes so we don't miss encoders
+                * that will be disabled. */
+               if (&encoder->new_crtc->base != encoder->base.crtc) {
+                       DRM_DEBUG_KMS("crtc changed, full mode switch\n");
+                       config->mode_changed = true;
+               }
+       }
+       /* Now we've also updated encoder->new_crtc for all encoders. */
+       return 0;
+ }
+ static int intel_crtc_set_config(struct drm_mode_set *set)
+ {
+       struct drm_device *dev;
+       struct drm_mode_set save_set;
+       struct intel_set_config *config;
+       int ret;
+       BUG_ON(!set);
+       BUG_ON(!set->crtc);
+       BUG_ON(!set->crtc->helper_private);
+       if (!set->mode)
+               set->fb = NULL;
+       /* The fb helper likes to play gross jokes with ->mode_set_config.
+        * Unfortunately the crtc helper doesn't do much at all for this case,
+        * so we have to cope with this madness until the fb helper is fixed up. */
+       if (set->fb && set->num_connectors == 0)
+               return 0;
+       if (set->fb) {
+               DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
+                               set->crtc->base.id, set->fb->base.id,
+                               (int)set->num_connectors, set->x, set->y);
+       } else {
+               DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
+       }
+       dev = set->crtc->dev;
+       ret = -ENOMEM;
+       config = kzalloc(sizeof(*config), GFP_KERNEL);
+       if (!config)
+               goto out_config;
+       ret = intel_set_config_save_state(dev, config);
+       if (ret)
+               goto out_config;
+       save_set.crtc = set->crtc;
+       save_set.mode = &set->crtc->mode;
+       save_set.x = set->crtc->x;
+       save_set.y = set->crtc->y;
+       save_set.fb = set->crtc->fb;
+       /* Compute whether we need a full modeset, only an fb base update or no
+        * change at all. In the future we might also check whether only the
+        * mode changed, e.g. for LVDS where we only change the panel fitter in
+        * such cases. */
+       intel_set_config_compute_mode_changes(set, config);
+       ret = intel_modeset_stage_output_state(dev, set, config);
+       if (ret)
+               goto fail;
+       if (config->mode_changed) {
+               if (set->mode) {
+                       DRM_DEBUG_KMS("attempting to set mode from"
+                                       " userspace\n");
+                       drm_mode_debug_printmodeline(set->mode);
+               }
+               if (!intel_set_mode(set->crtc, set->mode,
+                                   set->x, set->y, set->fb)) {
+                       DRM_ERROR("failed to set mode on [CRTC:%d]\n",
+                                 set->crtc->base.id);
+                       ret = -EINVAL;
+                       goto fail;
+               }
+       } else if (config->fb_changed) {
+               ret = intel_pipe_set_base(set->crtc,
+                                         set->x, set->y, set->fb);
+       }
+       intel_set_config_free(config);
+       return 0;
+ fail:
+       intel_set_config_restore_state(dev, config);
+       /* Try to restore the config */
+       if (config->mode_changed &&
+           !intel_set_mode(save_set.crtc, save_set.mode,
+                           save_set.x, save_set.y, save_set.fb))
+               DRM_ERROR("failed to restore config after modeset failure\n");
+ out_config:
+       intel_set_config_free(config);
+       return ret;
+ }
  
  static const struct drm_crtc_funcs intel_crtc_funcs = {
-       .reset = intel_crtc_reset,
        .cursor_set = intel_crtc_cursor_set,
        .cursor_move = intel_crtc_cursor_move,
        .gamma_set = intel_crtc_gamma_set,
-       .set_config = drm_crtc_helper_set_config,
+       .set_config = intel_crtc_set_config,
        .destroy = intel_crtc_destroy,
        .page_flip = intel_crtc_page_flip,
  };
@@@ -6655,24 -7448,9 +7448,9 @@@ static void intel_crtc_init(struct drm_
        dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
        dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
  
-       intel_crtc_reset(&intel_crtc->base);
-       intel_crtc->active = true; /* force the pipe off on setup_init_config */
        intel_crtc->bpp = 24; /* default for pre-Ironlake */
  
-       if (HAS_PCH_SPLIT(dev)) {
-               intel_helper_funcs.prepare = ironlake_crtc_prepare;
-               intel_helper_funcs.commit = ironlake_crtc_commit;
-       } else {
-               intel_helper_funcs.prepare = i9xx_crtc_prepare;
-               intel_helper_funcs.commit = i9xx_crtc_commit;
-       }
        drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
-       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,
        return 0;
  }
  
- static int intel_encoder_clones(struct drm_device *dev, int type_mask)
+ static int intel_encoder_clones(struct intel_encoder *encoder)
  {
-       struct intel_encoder *encoder;
+       struct drm_device *dev = encoder->base.dev;
+       struct intel_encoder *source_encoder;
        int index_mask = 0;
        int entry = 0;
  
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
-               if (type_mask & encoder->clone_mask)
+       list_for_each_entry(source_encoder,
+                           &dev->mode_config.encoder_list, base.head) {
+               if (encoder == source_encoder)
                        index_mask |= (1 << entry);
+               /* Intel hw has only one MUX where enocoders could be cloned. */
+               if (encoder->cloneable && source_encoder->cloneable)
+                       index_mask |= (1 << entry);
                entry++;
        }
  
@@@ -6748,10 -7534,10 +7534,10 @@@ static void intel_setup_outputs(struct 
                dpd_is_edp = intel_dpd_is_edp(dev);
  
                if (has_edp_a(dev))
-                       intel_dp_init(dev, DP_A);
+                       intel_dp_init(dev, DP_A, PORT_A);
  
                if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
-                       intel_dp_init(dev, PCH_DP_D);
+                       intel_dp_init(dev, PCH_DP_D, PORT_D);
        }
  
        intel_crt_init(dev);
                        /* PCH SDVOB multiplex with HDMIB */
                        found = intel_sdvo_init(dev, PCH_SDVOB, true);
                        if (!found)
-                               intel_hdmi_init(dev, HDMIB);
+                               intel_hdmi_init(dev, HDMIB, PORT_B);
                        if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
-                               intel_dp_init(dev, PCH_DP_B);
+                               intel_dp_init(dev, PCH_DP_B, PORT_B);
                }
  
                if (I915_READ(HDMIC) & PORT_DETECTED)
-                       intel_hdmi_init(dev, HDMIC);
+                       intel_hdmi_init(dev, HDMIC, PORT_C);
  
                if (!dpd_is_edp && I915_READ(HDMID) & PORT_DETECTED)
-                       intel_hdmi_init(dev, HDMID);
+                       intel_hdmi_init(dev, HDMID, PORT_D);
  
                if (I915_READ(PCH_DP_C) & DP_DETECTED)
-                       intel_dp_init(dev, PCH_DP_C);
+                       intel_dp_init(dev, PCH_DP_C, PORT_C);
  
                if (!dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
-                       intel_dp_init(dev, PCH_DP_D);
+                       intel_dp_init(dev, PCH_DP_D, PORT_D);
        } else if (IS_VALLEYVIEW(dev)) {
                int found;
  
                        /* SDVOB multiplex with HDMIB */
                        found = intel_sdvo_init(dev, SDVOB, true);
                        if (!found)
-                               intel_hdmi_init(dev, SDVOB);
+                               intel_hdmi_init(dev, SDVOB, PORT_B);
                        if (!found && (I915_READ(DP_B) & DP_DETECTED))
-                               intel_dp_init(dev, DP_B);
+                               intel_dp_init(dev, DP_B, PORT_B);
                }
  
                if (I915_READ(SDVOC) & PORT_DETECTED)
-                       intel_hdmi_init(dev, SDVOC);
+                       intel_hdmi_init(dev, SDVOC, PORT_C);
  
                /* Shares lanes with HDMI on SDVOC */
                if (I915_READ(DP_C) & DP_DETECTED)
-                       intel_dp_init(dev, DP_C);
+                       intel_dp_init(dev, DP_C, PORT_C);
        } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) {
                bool found = false;
  
                        found = intel_sdvo_init(dev, SDVOB, true);
                        if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) {
                                DRM_DEBUG_KMS("probing HDMI on SDVOB\n");
-                               intel_hdmi_init(dev, SDVOB);
+                               intel_hdmi_init(dev, SDVOB, PORT_B);
                        }
  
                        if (!found && SUPPORTS_INTEGRATED_DP(dev)) {
                                DRM_DEBUG_KMS("probing DP_B\n");
-                               intel_dp_init(dev, DP_B);
+                               intel_dp_init(dev, DP_B, PORT_B);
                        }
                }
  
  
                        if (SUPPORTS_INTEGRATED_HDMI(dev)) {
                                DRM_DEBUG_KMS("probing HDMI on SDVOC\n");
-                               intel_hdmi_init(dev, SDVOC);
+                               intel_hdmi_init(dev, SDVOC, PORT_C);
                        }
                        if (SUPPORTS_INTEGRATED_DP(dev)) {
                                DRM_DEBUG_KMS("probing DP_C\n");
-                               intel_dp_init(dev, DP_C);
+                               intel_dp_init(dev, DP_C, PORT_C);
                        }
                }
  
                if (SUPPORTS_INTEGRATED_DP(dev) &&
                    (I915_READ(DP_D) & DP_DETECTED)) {
                        DRM_DEBUG_KMS("probing DP_D\n");
-                       intel_dp_init(dev, DP_D);
+                       intel_dp_init(dev, DP_D, PORT_D);
                }
        } else if (IS_GEN2(dev))
                intel_dvo_init(dev);
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
                encoder->base.possible_crtcs = encoder->crtc_mask;
                encoder->base.possible_clones =
-                       intel_encoder_clones(dev, encoder->clone_mask);
+                       intel_encoder_clones(encoder);
        }
  
-       /* disable all the possible outputs/crtcs before entering KMS mode */
-       drm_helper_disable_unused_functions(dev);
        if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
                ironlake_init_pch_refclk(dev);
  }
@@@ -6973,13 -7756,15 +7756,15 @@@ static void intel_init_display(struct d
  
        /* We always want a DPMS function */
        if (HAS_PCH_SPLIT(dev)) {
-               dev_priv->display.dpms = ironlake_crtc_dpms;
                dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
+               dev_priv->display.crtc_enable = ironlake_crtc_enable;
+               dev_priv->display.crtc_disable = ironlake_crtc_disable;
                dev_priv->display.off = ironlake_crtc_off;
                dev_priv->display.update_plane = ironlake_update_plane;
        } else {
-               dev_priv->display.dpms = i9xx_crtc_dpms;
                dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
+               dev_priv->display.crtc_enable = i9xx_crtc_enable;
+               dev_priv->display.crtc_disable = i9xx_crtc_disable;
                dev_priv->display.off = i9xx_crtc_off;
                dev_priv->display.update_plane = i9xx_update_plane;
        }
                        dev_priv->display.write_eld = ironlake_write_eld;
                } else if (IS_HASWELL(dev)) {
                        dev_priv->display.fdi_link_train = hsw_fdi_link_train;
-                       dev_priv->display.write_eld = ironlake_write_eld;
+                       dev_priv->display.write_eld = haswell_write_eld;
                } else
                        dev_priv->display.update_wm = NULL;
        } else if (IS_G4X(dev)) {
@@@ -7101,21 -7886,16 +7886,16 @@@ static struct intel_quirk intel_quirks[
        /* HP Mini needs pipe A force quirk (LP: #322104) */
        { 0x27ae, 0x103c, 0x361a, quirk_pipea_force },
  
-       /* Thinkpad R31 needs pipe A force quirk */
-       { 0x3577, 0x1014, 0x0505, quirk_pipea_force },
        /* Toshiba Protege R-205, S-209 needs pipe A force quirk */
        { 0x2592, 0x1179, 0x0001, quirk_pipea_force },
  
-       /* ThinkPad X30 needs pipe A force quirk (LP: #304614) */
-       { 0x3577,  0x1014, 0x0513, quirk_pipea_force },
-       /* ThinkPad X40 needs pipe A force quirk */
        /* ThinkPad T60 needs pipe A force quirk (bug #16494) */
        { 0x2782, 0x17aa, 0x201a, quirk_pipea_force },
  
        /* 855 & before need to leave pipe A & dpll A up */
        { 0x3582, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
        { 0x2562, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
+       { 0x3577, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
  
        /* Lenovo U160 cannot use SSC on LVDS */
        { 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable },
@@@ -7231,10 -8011,251 +8011,251 @@@ void intel_modeset_init(struct drm_devi
        /* Just disable it once at startup */
        i915_disable_vga(dev);
        intel_setup_outputs(dev);
+ }
+ static void
+ intel_connector_break_all_links(struct intel_connector *connector)
+ {
+       connector->base.dpms = DRM_MODE_DPMS_OFF;
+       connector->base.encoder = NULL;
+       connector->encoder->connectors_active = false;
+       connector->encoder->base.crtc = NULL;
+ }
+ static void intel_enable_pipe_a(struct drm_device *dev)
+ {
+       struct intel_connector *connector;
+       struct drm_connector *crt = NULL;
+       struct intel_load_detect_pipe load_detect_temp;
+       /* We can't just switch on the pipe A, we need to set things up with a
+        * proper mode and output configuration. As a gross hack, enable pipe A
+        * by enabling the load detect pipe once. */
+       list_for_each_entry(connector,
+                           &dev->mode_config.connector_list,
+                           base.head) {
+               if (connector->encoder->type == INTEL_OUTPUT_ANALOG) {
+                       crt = &connector->base;
+                       break;
+               }
+       }
+       if (!crt)
+               return;
+       if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp))
+               intel_release_load_detect_pipe(crt, &load_detect_temp);
  
-       INIT_WORK(&dev_priv->idle_work, intel_idle_update);
-       setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
-                   (unsigned long)dev);
+ }
+ static void intel_sanitize_crtc(struct intel_crtc *crtc)
+ {
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg, val;
+       /* Clear any frame start delays used for debugging left by the BIOS */
+       reg = PIPECONF(crtc->pipe);
+       I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
+       /* We need to sanitize the plane -> pipe mapping first because this will
+        * disable the crtc (and hence change the state) if it is wrong. */
+       if (!HAS_PCH_SPLIT(dev)) {
+               struct intel_connector *connector;
+               bool plane;
+               reg = DSPCNTR(crtc->plane);
+               val = I915_READ(reg);
+               if ((val & DISPLAY_PLANE_ENABLE) == 0 &&
+                   (!!(val & DISPPLANE_SEL_PIPE_MASK) == crtc->pipe))
+                       goto ok;
+               DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n",
+                             crtc->base.base.id);
+               /* Pipe has the wrong plane attached and the plane is active.
+                * Temporarily change the plane mapping and disable everything
+                * ...  */
+               plane = crtc->plane;
+               crtc->plane = !plane;
+               dev_priv->display.crtc_disable(&crtc->base);
+               crtc->plane = plane;
+               /* ... and break all links. */
+               list_for_each_entry(connector, &dev->mode_config.connector_list,
+                                   base.head) {
+                       if (connector->encoder->base.crtc != &crtc->base)
+                               continue;
+                       intel_connector_break_all_links(connector);
+               }
+               WARN_ON(crtc->active);
+               crtc->base.enabled = false;
+       }
+ ok:
+       if (dev_priv->quirks & QUIRK_PIPEA_FORCE &&
+           crtc->pipe == PIPE_A && !crtc->active) {
+               /* BIOS forgot to enable pipe A, this mostly happens after
+                * resume. Force-enable the pipe to fix this, the update_dpms
+                * call below we restore the pipe to the right state, but leave
+                * the required bits on. */
+               intel_enable_pipe_a(dev);
+       }
+       /* Adjust the state of the output pipe according to whether we
+        * have active connectors/encoders. */
+       intel_crtc_update_dpms(&crtc->base);
+       if (crtc->active != crtc->base.enabled) {
+               struct intel_encoder *encoder;
+               /* This can happen either due to bugs in the get_hw_state
+                * functions or because the pipe is force-enabled due to the
+                * pipe A quirk. */
+               DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was %s, now %s\n",
+                             crtc->base.base.id,
+                             crtc->base.enabled ? "enabled" : "disabled",
+                             crtc->active ? "enabled" : "disabled");
+               crtc->base.enabled = crtc->active;
+               /* Because we only establish the connector -> encoder ->
+                * crtc links if something is active, this means the
+                * crtc is now deactivated. Break the links. connector
+                * -> encoder links are only establish when things are
+                *  actually up, hence no need to break them. */
+               WARN_ON(crtc->active);
+               for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
+                       WARN_ON(encoder->connectors_active);
+                       encoder->base.crtc = NULL;
+               }
+       }
+ }
+ static void intel_sanitize_encoder(struct intel_encoder *encoder)
+ {
+       struct intel_connector *connector;
+       struct drm_device *dev = encoder->base.dev;
+       /* We need to check both for a crtc link (meaning that the
+        * encoder is active and trying to read from a pipe) and the
+        * pipe itself being active. */
+       bool has_active_crtc = encoder->base.crtc &&
+               to_intel_crtc(encoder->base.crtc)->active;
+       if (encoder->connectors_active && !has_active_crtc) {
+               DRM_DEBUG_KMS("[ENCODER:%d:%s] has active connectors but no active pipe!\n",
+                             encoder->base.base.id,
+                             drm_get_encoder_name(&encoder->base));
+               /* Connector is active, but has no active pipe. This is
+                * fallout from our resume register restoring. Disable
+                * the encoder manually again. */
+               if (encoder->base.crtc) {
+                       DRM_DEBUG_KMS("[ENCODER:%d:%s] manually disabled\n",
+                                     encoder->base.base.id,
+                                     drm_get_encoder_name(&encoder->base));
+                       encoder->disable(encoder);
+               }
+               /* Inconsistent output/port/pipe state happens presumably due to
+                * a bug in one of the get_hw_state functions. Or someplace else
+                * in our code, like the register restore mess on resume. Clamp
+                * things to off as a safer default. */
+               list_for_each_entry(connector,
+                                   &dev->mode_config.connector_list,
+                                   base.head) {
+                       if (connector->encoder != encoder)
+                               continue;
+                       intel_connector_break_all_links(connector);
+               }
+       }
+       /* Enabled encoders without active connectors will be fixed in
+        * the crtc fixup. */
+ }
+ /* Scan out the current hw modeset state, sanitizes it and maps it into the drm
+  * and i915 state tracking structures. */
+ void intel_modeset_setup_hw_state(struct drm_device *dev)
+ {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe pipe;
+       u32 tmp;
+       struct intel_crtc *crtc;
+       struct intel_encoder *encoder;
+       struct intel_connector *connector;
+       for_each_pipe(pipe) {
+               crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+               tmp = I915_READ(PIPECONF(pipe));
+               if (tmp & PIPECONF_ENABLE)
+                       crtc->active = true;
+               else
+                       crtc->active = false;
+               crtc->base.enabled = crtc->active;
+               DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n",
+                             crtc->base.base.id,
+                             crtc->active ? "enabled" : "disabled");
+       }
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               pipe = 0;
+               if (encoder->get_hw_state(encoder, &pipe)) {
+                       encoder->base.crtc =
+                               dev_priv->pipe_to_crtc_mapping[pipe];
+               } else {
+                       encoder->base.crtc = NULL;
+               }
+               encoder->connectors_active = false;
+               DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe=%i\n",
+                             encoder->base.base.id,
+                             drm_get_encoder_name(&encoder->base),
+                             encoder->base.crtc ? "enabled" : "disabled",
+                             pipe);
+       }
+       list_for_each_entry(connector, &dev->mode_config.connector_list,
+                           base.head) {
+               if (connector->get_hw_state(connector)) {
+                       connector->base.dpms = DRM_MODE_DPMS_ON;
+                       connector->encoder->connectors_active = true;
+                       connector->base.encoder = &connector->encoder->base;
+               } else {
+                       connector->base.dpms = DRM_MODE_DPMS_OFF;
+                       connector->base.encoder = NULL;
+               }
+               DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hw state readout: %s\n",
+                             connector->base.base.id,
+                             drm_get_connector_name(&connector->base),
+                             connector->base.encoder ? "enabled" : "disabled");
+       }
+       /* HW state is read out, now we need to sanitize this mess. */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               intel_sanitize_encoder(encoder);
+       }
+       for_each_pipe(pipe) {
+               crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+               intel_sanitize_crtc(crtc);
+       }
+       intel_modeset_update_staged_output_state(dev);
+       intel_modeset_check_state(dev);
  }
  
  void intel_modeset_gem_init(struct drm_device *dev)
        intel_modeset_init_hw(dev);
  
        intel_setup_overlay(dev);
+       intel_modeset_setup_hw_state(dev);
  }
  
  void intel_modeset_cleanup(struct drm_device *dev)
         * enqueue unpin/hotplug work. */
        drm_irq_uninstall(dev);
        cancel_work_sync(&dev_priv->hotplug_work);
-       cancel_work_sync(&dev_priv->rps_work);
+       cancel_work_sync(&dev_priv->rps.work);
  
        /* flush any delayed tasks or pending work */
        flush_scheduled_work();
  
-       /* Shut off idle work before the crtcs get freed. */
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               intel_crtc = to_intel_crtc(crtc);
-               del_timer_sync(&intel_crtc->idle_timer);
-       }
-       del_timer_sync(&dev_priv->idle_timer);
-       cancel_work_sync(&dev_priv->idle_work);
        drm_mode_config_cleanup(dev);
  }
  
@@@ -7338,7 -8353,7 +8353,7 @@@ struct intel_display_error_state 
                u32 position;
                u32 base;
                u32 size;
-       } cursor[2];
+       } cursor[I915_MAX_PIPES];
  
        struct intel_pipe_error_state {
                u32 conf;
                u32 vtotal;
                u32 vblank;
                u32 vsync;
-       } pipe[2];
+       } pipe[I915_MAX_PIPES];
  
        struct intel_plane_error_state {
                u32 control;
                u32 addr;
                u32 surface;
                u32 tile_offset;
-       } plane[2];
+       } plane[I915_MAX_PIPES];
  };
  
  struct intel_display_error_state *
@@@ -7374,7 -8389,7 +8389,7 @@@ intel_display_capture_error_state(struc
        if (error == NULL)
                return NULL;
  
-       for (i = 0; i < 2; i++) {
+       for_each_pipe(i) {
                error->cursor[i].control = I915_READ(CURCNTR(i));
                error->cursor[i].position = I915_READ(CURPOS(i));
                error->cursor[i].base = I915_READ(CURBASE(i));
@@@ -7407,9 -8422,11 +8422,11 @@@ intel_display_print_error_state(struct 
                                struct drm_device *dev,
                                struct intel_display_error_state *error)
  {
+       drm_i915_private_t *dev_priv = dev->dev_private;
        int i;
  
-       for (i = 0; i < 2; i++) {
+       seq_printf(m, "Num Pipes: %d\n", dev_priv->num_pipe);
+       for_each_pipe(i) {
                seq_printf(m, "Pipe [%d]:\n", i);
                seq_printf(m, "  CONF: %08x\n", error->pipe[i].conf);
                seq_printf(m, "  SRC: %08x\n", error->pipe[i].source);
  #include <linux/i2c.h>
  #include <linux/slab.h>
  #include <linux/export.h>
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 -#include "drm_crtc_helper.h"
 -#include "drm_edid.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/drm_edid.h>
  #include "intel_drv.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
- #include <drm/drm_dp_helper.h>
  
- #define DP_RECEIVER_CAP_SIZE  0xf
  #define DP_LINK_STATUS_SIZE   6
  #define DP_LINK_CHECK_TIMEOUT (10 * 1000)
  
- #define DP_LINK_CONFIGURATION_SIZE    9
- struct intel_dp {
-       struct intel_encoder base;
-       uint32_t output_reg;
-       uint32_t DP;
-       uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
-       bool has_audio;
-       enum hdmi_force_audio force_audio;
-       uint32_t color_range;
-       int dpms_mode;
-       uint8_t link_bw;
-       uint8_t lane_count;
-       uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
-       struct i2c_adapter adapter;
-       struct i2c_algo_dp_aux_data algo;
-       bool is_pch_edp;
-       uint8_t train_set[4];
-       int panel_power_up_delay;
-       int panel_power_down_delay;
-       int panel_power_cycle_delay;
-       int backlight_on_delay;
-       int backlight_off_delay;
-       struct drm_display_mode *panel_fixed_mode;  /* for eDP */
-       struct delayed_work panel_vdd_work;
-       bool want_panel_vdd;
-       struct edid *edid; /* cached EDID for eDP */
-       int edid_mode_count;
- };
  /**
   * is_edp - is the given port attached to an eDP panel (either CPU or PCH)
   * @intel_dp: DP struct
@@@ -839,9 -808,6 +807,6 @@@ intel_dp_set_m_n(struct drm_crtc *crtc
        }
  }
  
- static void ironlake_edp_pll_on(struct drm_encoder *encoder);
- static void ironlake_edp_pll_off(struct drm_encoder *encoder);
  static void
  intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                  struct drm_display_mode *adjusted_mode)
        struct drm_crtc *crtc = intel_dp->base.base.crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
  
-       /* Turn on the eDP PLL if needed */
-       if (is_edp(intel_dp)) {
-               if (!is_pch_edp(intel_dp))
-                       ironlake_edp_pll_on(encoder);
-               else
-                       ironlake_edp_pll_off(encoder);
-       }
        /*
         * There are four kinds of DP registers:
         *
         * supposed to be read-only.
         */
        intel_dp->DP = I915_READ(intel_dp->output_reg) & DP_DETECTED;
-       intel_dp->DP |=  DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
  
        /* Handle DP bits in common between all three register formats */
        intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
  
        switch (intel_dp->lane_count) {
                intel_dp->DP |= intel_crtc->pipe << 29;
  
                /* don't miss out required setting for eDP */
-               intel_dp->DP |= DP_PLL_ENABLE;
                if (adjusted_mode->clock < 200000)
                        intel_dp->DP |= DP_PLL_FREQ_160MHZ;
                else
  
                if (is_cpu_edp(intel_dp)) {
                        /* don't miss out required setting for eDP */
-                       intel_dp->DP |= DP_PLL_ENABLE;
                        if (adjusted_mode->clock < 200000)
                                intel_dp->DP |= DP_PLL_FREQ_160MHZ;
                        else
@@@ -1224,27 -1178,49 +1177,49 @@@ static void ironlake_edp_backlight_off(
        msleep(intel_dp->backlight_off_delay);
  }
  
- static void ironlake_edp_pll_on(struct drm_encoder *encoder)
+ static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
  {
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
+       struct drm_crtc *crtc = intel_dp->base.base.crtc;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 dpa_ctl;
  
+       assert_pipe_disabled(dev_priv,
+                            to_intel_crtc(crtc)->pipe);
        DRM_DEBUG_KMS("\n");
        dpa_ctl = I915_READ(DP_A);
-       dpa_ctl |= DP_PLL_ENABLE;
-       I915_WRITE(DP_A, dpa_ctl);
+       WARN(dpa_ctl & DP_PLL_ENABLE, "dp pll on, should be off\n");
+       WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n");
+       /* We don't adjust intel_dp->DP while tearing down the link, to
+        * facilitate link retraining (e.g. after hotplug). Hence clear all
+        * enable bits here to ensure that we don't enable too much. */
+       intel_dp->DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE);
+       intel_dp->DP |= DP_PLL_ENABLE;
+       I915_WRITE(DP_A, intel_dp->DP);
        POSTING_READ(DP_A);
        udelay(200);
  }
  
- static void ironlake_edp_pll_off(struct drm_encoder *encoder)
+ static void ironlake_edp_pll_off(struct intel_dp *intel_dp)
  {
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
+       struct drm_crtc *crtc = intel_dp->base.base.crtc;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 dpa_ctl;
  
+       assert_pipe_disabled(dev_priv,
+                            to_intel_crtc(crtc)->pipe);
        dpa_ctl = I915_READ(DP_A);
+       WARN((dpa_ctl & DP_PLL_ENABLE) == 0,
+            "dp pll off, should be on\n");
+       WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n");
+       /* We can't rely on the value tracked for the DP register in
+        * intel_dp->DP because link_down must not change that (otherwise link
+        * re-training will fail. */
        dpa_ctl &= ~DP_PLL_ENABLE;
        I915_WRITE(DP_A, dpa_ctl);
        POSTING_READ(DP_A);
@@@ -1281,10 -1257,57 +1256,57 @@@ static void intel_dp_sink_dpms(struct i
        }
  }
  
- static void intel_dp_prepare(struct drm_encoder *encoder)
+ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
+                                 enum pipe *pipe)
  {
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 tmp = I915_READ(intel_dp->output_reg);
+       if (!(tmp & DP_PORT_EN))
+               return false;
+       if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) {
+               *pipe = PORT_TO_PIPE_CPT(tmp);
+       } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
+               *pipe = PORT_TO_PIPE(tmp);
+       } else {
+               u32 trans_sel;
+               u32 trans_dp;
+               int i;
+               switch (intel_dp->output_reg) {
+               case PCH_DP_B:
+                       trans_sel = TRANS_DP_PORT_SEL_B;
+                       break;
+               case PCH_DP_C:
+                       trans_sel = TRANS_DP_PORT_SEL_C;
+                       break;
+               case PCH_DP_D:
+                       trans_sel = TRANS_DP_PORT_SEL_D;
+                       break;
+               default:
+                       return true;
+               }
+               for_each_pipe(i) {
+                       trans_dp = I915_READ(TRANS_DP_CTL(i));
+                       if ((trans_dp & TRANS_DP_PORT_SEL_MASK) == trans_sel) {
+                               *pipe = i;
+                               return true;
+                       }
+               }
+       }
+       DRM_DEBUG_KMS("No pipe for dp port 0x%x found\n", intel_dp->output_reg);
+       return true;
+ }
  
+ static void intel_disable_dp(struct intel_encoder *encoder)
+ {
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
  
        /* Make sure the panel is off before trying to change the mode. But also
         * ensure that we have vdd while we switch off the panel. */
        ironlake_edp_backlight_off(intel_dp);
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
        ironlake_edp_panel_off(intel_dp);
-       intel_dp_link_down(intel_dp);
+       /* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */
+       if (!is_cpu_edp(intel_dp))
+               intel_dp_link_down(intel_dp);
  }
  
- static void intel_dp_commit(struct drm_encoder *encoder)
+ static void intel_post_disable_dp(struct intel_encoder *encoder)
  {
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-       struct drm_device *dev = encoder->dev;
-       struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       if (is_cpu_edp(intel_dp)) {
+               intel_dp_link_down(intel_dp);
+               ironlake_edp_pll_off(intel_dp);
+       }
+ }
+ static void intel_enable_dp(struct intel_encoder *encoder)
+ {
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t dp_reg = I915_READ(intel_dp->output_reg);
+       if (WARN_ON(dp_reg & DP_PORT_EN))
+               return;
  
        ironlake_edp_panel_vdd_on(intel_dp);
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
        ironlake_edp_panel_vdd_off(intel_dp, true);
        intel_dp_complete_link_train(intel_dp);
        ironlake_edp_backlight_on(intel_dp);
-       intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
-       if (HAS_PCH_CPT(dev))
-               intel_cpt_verify_modeset(dev, intel_crtc->pipe);
  }
  
- static void
- intel_dp_dpms(struct drm_encoder *encoder, int mode)
+ static void intel_pre_enable_dp(struct intel_encoder *encoder)
  {
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t dp_reg = I915_READ(intel_dp->output_reg);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
  
-       if (mode != DRM_MODE_DPMS_ON) {
-               /* Switching the panel off requires vdd. */
-               ironlake_edp_panel_vdd_on(intel_dp);
-               ironlake_edp_backlight_off(intel_dp);
-               intel_dp_sink_dpms(intel_dp, mode);
-               ironlake_edp_panel_off(intel_dp);
-               intel_dp_link_down(intel_dp);
-               if (is_cpu_edp(intel_dp))
-                       ironlake_edp_pll_off(encoder);
-       } else {
-               if (is_cpu_edp(intel_dp))
-                       ironlake_edp_pll_on(encoder);
-               ironlake_edp_panel_vdd_on(intel_dp);
-               intel_dp_sink_dpms(intel_dp, mode);
-               if (!(dp_reg & DP_PORT_EN)) {
-                       intel_dp_start_link_train(intel_dp);
-                       ironlake_edp_panel_on(intel_dp);
-                       ironlake_edp_panel_vdd_off(intel_dp, true);
-                       intel_dp_complete_link_train(intel_dp);
-               } else
-                       ironlake_edp_panel_vdd_off(intel_dp, false);
-               ironlake_edp_backlight_on(intel_dp);
-       }
-       intel_dp->dpms_mode = mode;
+       if (is_cpu_edp(intel_dp))
+               ironlake_edp_pll_on(intel_dp);
  }
  
  /*
@@@ -1667,6 -1674,45 +1673,45 @@@ intel_dp_set_link_train(struct intel_d
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
  
+       if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) {
+               dp_reg_value &= ~DP_LINK_TRAIN_MASK_CPT;
+               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+               case DP_TRAINING_PATTERN_DISABLE:
+                       dp_reg_value |= DP_LINK_TRAIN_OFF_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_1:
+                       dp_reg_value |= DP_LINK_TRAIN_PAT_1_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       dp_reg_value |= DP_LINK_TRAIN_PAT_2_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       DRM_ERROR("DP training pattern 3 not supported\n");
+                       dp_reg_value |= DP_LINK_TRAIN_PAT_2_CPT;
+                       break;
+               }
+       } else {
+               dp_reg_value &= ~DP_LINK_TRAIN_MASK;
+               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+               case DP_TRAINING_PATTERN_DISABLE:
+                       dp_reg_value |= DP_LINK_TRAIN_OFF;
+                       break;
+               case DP_TRAINING_PATTERN_1:
+                       dp_reg_value |= DP_LINK_TRAIN_PAT_1;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       dp_reg_value |= DP_LINK_TRAIN_PAT_2;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       DRM_ERROR("DP training pattern 3 not supported\n");
+                       dp_reg_value |= DP_LINK_TRAIN_PAT_2;
+                       break;
+               }
+       }
        I915_WRITE(intel_dp->output_reg, dp_reg_value);
        POSTING_READ(intel_dp->output_reg);
  
                                    DP_TRAINING_PATTERN_SET,
                                    dp_train_pat);
  
-       ret = intel_dp_aux_native_write(intel_dp,
-                                       DP_TRAINING_LANE0_SET,
-                                       intel_dp->train_set,
-                                       intel_dp->lane_count);
-       if (ret != intel_dp->lane_count)
-               return false;
+       if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) !=
+           DP_TRAINING_PATTERN_DISABLE) {
+               ret = intel_dp_aux_native_write(intel_dp,
+                                               DP_TRAINING_LANE0_SET,
+                                               intel_dp->train_set,
+                                               intel_dp->lane_count);
+               if (ret != intel_dp->lane_count)
+                       return false;
+       }
  
        return true;
  }
@@@ -1689,26 -1738,12 +1737,12 @@@ static voi
  intel_dp_start_link_train(struct intel_dp *intel_dp)
  {
        struct drm_device *dev = intel_dp->base.base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
        int i;
        uint8_t voltage;
        bool clock_recovery = false;
        int voltage_tries, loop_tries;
-       u32 reg;
        uint32_t DP = intel_dp->DP;
  
-       /*
-        * On CPT we have to enable the port in training pattern 1, which
-        * will happen below in intel_dp_set_link_train.  Otherwise, enable
-        * the port and wait for it to become active.
-        */
-       if (!HAS_PCH_CPT(dev)) {
-               I915_WRITE(intel_dp->output_reg, intel_dp->DP);
-               POSTING_READ(intel_dp->output_reg);
-               intel_wait_for_vblank(dev, intel_crtc->pipe);
-       }
        /* Write the link configuration data */
        intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
                                  intel_dp->link_configuration,
  
        DP |= DP_PORT_EN;
  
-       if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
-               DP &= ~DP_LINK_TRAIN_MASK_CPT;
-       else
-               DP &= ~DP_LINK_TRAIN_MASK;
        memset(intel_dp->train_set, 0, 4);
        voltage = 0xff;
        voltage_tries = 0;
                        DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
                }
  
-               if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
-                       reg = DP | DP_LINK_TRAIN_PAT_1_CPT;
-               else
-                       reg = DP | DP_LINK_TRAIN_PAT_1;
-               if (!intel_dp_set_link_train(intel_dp, reg,
+               if (!intel_dp_set_link_train(intel_dp, DP,
                                             DP_TRAINING_PATTERN_1 |
                                             DP_LINK_SCRAMBLING_DISABLE))
                        break;
@@@ -1803,10 -1829,8 +1828,8 @@@ static voi
  intel_dp_complete_link_train(struct intel_dp *intel_dp)
  {
        struct drm_device *dev = intel_dp->base.base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        bool channel_eq = false;
        int tries, cr_tries;
-       u32 reg;
        uint32_t DP = intel_dp->DP;
  
        /* channel equalization */
                        DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
                }
  
-               if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
-                       reg = DP | DP_LINK_TRAIN_PAT_2_CPT;
-               else
-                       reg = DP | DP_LINK_TRAIN_PAT_2;
                /* channel eq pattern */
-               if (!intel_dp_set_link_train(intel_dp, reg,
+               if (!intel_dp_set_link_train(intel_dp, DP,
                                             DP_TRAINING_PATTERN_2 |
                                             DP_LINK_SCRAMBLING_DISABLE))
                        break;
                ++tries;
        }
  
-       if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
-               reg = DP | DP_LINK_TRAIN_OFF_CPT;
-       else
-               reg = DP | DP_LINK_TRAIN_OFF;
-       I915_WRITE(intel_dp->output_reg, reg);
-       POSTING_READ(intel_dp->output_reg);
-       intel_dp_aux_native_write_1(intel_dp,
-                                   DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE);
+       intel_dp_set_link_train(intel_dp, DP, DP_TRAINING_PATTERN_DISABLE);
  }
  
  static void
@@@ -1894,18 -1905,11 +1904,11 @@@ intel_dp_link_down(struct intel_dp *int
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t DP = intel_dp->DP;
  
-       if ((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)
+       if (WARN_ON((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0))
                return;
  
        DRM_DEBUG_KMS("\n");
  
-       if (is_edp(intel_dp)) {
-               DP &= ~DP_PLL_ENABLE;
-               I915_WRITE(intel_dp->output_reg, DP);
-               POSTING_READ(intel_dp->output_reg);
-               udelay(100);
-       }
        if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) {
                DP &= ~DP_LINK_TRAIN_MASK_CPT;
                I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
  
        msleep(17);
  
-       if (is_edp(intel_dp)) {
-               if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
-                       DP |= DP_LINK_TRAIN_OFF_CPT;
-               else
-                       DP |= DP_LINK_TRAIN_OFF;
-       }
        if (HAS_PCH_IBX(dev) &&
            I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
                struct drm_crtc *crtc = intel_dp->base.base.crtc;
@@@ -2032,10 -2029,10 +2028,10 @@@ intel_dp_check_link_status(struct intel
        u8 sink_irq_vector;
        u8 link_status[DP_LINK_STATUS_SIZE];
  
-       if (intel_dp->dpms_mode != DRM_MODE_DPMS_ON)
+       if (!intel_dp->base.connectors_active)
                return;
  
-       if (!intel_dp->base.base.crtc)
+       if (WARN_ON(!intel_dp->base.base.crtc))
                return;
  
        /* Try to read receiver status if the link appears to be up */
@@@ -2159,7 -2156,6 +2155,6 @@@ intel_dp_get_edid_modes(struct drm_conn
                ret = drm_add_edid_modes(connector, intel_dp->edid);
                drm_edid_to_eld(connector,
                                intel_dp->edid);
-               connector->display_info.raw_edid = NULL;
                return intel_dp->edid_mode_count;
        }
  
@@@ -2205,7 -2201,6 +2200,6 @@@ intel_dp_detect(struct drm_connector *c
                edid = intel_dp_get_edid(connector, &intel_dp->adapter);
                if (edid) {
                        intel_dp->has_audio = drm_detect_monitor_audio(edid);
-                       connector->display_info.raw_edid = NULL;
                        kfree(edid);
                }
        }
@@@ -2270,8 -2265,6 +2264,6 @@@ intel_dp_detect_audio(struct drm_connec
        edid = intel_dp_get_edid(connector, &intel_dp->adapter);
        if (edid) {
                has_audio = drm_detect_monitor_audio(edid);
-               connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
  
@@@ -2325,9 -2318,8 +2317,8 @@@ intel_dp_set_property(struct drm_connec
  done:
        if (intel_dp->base.base.crtc) {
                struct drm_crtc *crtc = intel_dp->base.base.crtc;
-               drm_crtc_helper_set_mode(crtc, &crtc->mode,
-                                        crtc->x, crtc->y,
-                                        crtc->fb);
+               intel_set_mode(crtc, &crtc->mode,
+                              crtc->x, crtc->y, crtc->fb);
        }
  
        return 0;
@@@ -2361,15 -2353,13 +2352,13 @@@ static void intel_dp_encoder_destroy(st
  }
  
  static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
-       .dpms = intel_dp_dpms,
        .mode_fixup = intel_dp_mode_fixup,
-       .prepare = intel_dp_prepare,
        .mode_set = intel_dp_mode_set,
-       .commit = intel_dp_commit,
+       .disable = intel_encoder_noop,
  };
  
  static const struct drm_connector_funcs intel_dp_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = intel_connector_dpms,
        .detect = intel_dp_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_dp_set_property,
@@@ -2440,7 -2430,7 +2429,7 @@@ intel_dp_add_properties(struct intel_d
  }
  
  void
- intel_dp_init(struct drm_device *dev, int output_reg)
+ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_connector *connector;
                return;
  
        intel_dp->output_reg = output_reg;
-       intel_dp->dpms_mode = -1;
+       intel_dp->port = port;
+       /* Preserve the current hw state. */
+       intel_dp->DP = I915_READ(intel_dp->output_reg);
  
        intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
        if (!intel_connector) {
  
        connector->polled = DRM_CONNECTOR_POLL_HPD;
  
-       if (output_reg == DP_B || output_reg == PCH_DP_B)
-               intel_encoder->clone_mask = (1 << INTEL_DP_B_CLONE_BIT);
-       else if (output_reg == DP_C || output_reg == PCH_DP_C)
-               intel_encoder->clone_mask = (1 << INTEL_DP_C_CLONE_BIT);
-       else if (output_reg == DP_D || output_reg == PCH_DP_D)
-               intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
+       intel_encoder->cloneable = false;
  
-       if (is_edp(intel_dp)) {
-               intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
-               INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
-                                 ironlake_panel_vdd_work);
-       }
+       INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
+                         ironlake_panel_vdd_work);
  
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
  
        intel_connector_attach_encoder(intel_connector, intel_encoder);
        drm_sysfs_connector_add(connector);
  
+       intel_encoder->enable = intel_enable_dp;
+       intel_encoder->pre_enable = intel_pre_enable_dp;
+       intel_encoder->disable = intel_disable_dp;
+       intel_encoder->post_disable = intel_post_disable_dp;
+       intel_encoder->get_hw_state = intel_dp_get_hw_state;
+       intel_connector->get_hw_state = intel_connector_get_hw_state;
        /* Set up the DDC bus. */
-       switch (output_reg) {
-               case DP_A:
-                       name = "DPDDC-A";
-                       break;
-               case DP_B:
-               case PCH_DP_B:
-                       dev_priv->hotplug_supported_mask |=
-                               DPB_HOTPLUG_INT_STATUS;
-                       name = "DPDDC-B";
-                       break;
-               case DP_C:
-               case PCH_DP_C:
-                       dev_priv->hotplug_supported_mask |=
-                               DPC_HOTPLUG_INT_STATUS;
-                       name = "DPDDC-C";
-                       break;
-               case DP_D:
-               case PCH_DP_D:
-                       dev_priv->hotplug_supported_mask |=
-                               DPD_HOTPLUG_INT_STATUS;
-                       name = "DPDDC-D";
-                       break;
+       switch (port) {
+       case PORT_A:
+               name = "DPDDC-A";
+               break;
+       case PORT_B:
+               dev_priv->hotplug_supported_mask |= DPB_HOTPLUG_INT_STATUS;
+               name = "DPDDC-B";
+               break;
+       case PORT_C:
+               dev_priv->hotplug_supported_mask |= DPC_HOTPLUG_INT_STATUS;
+               name = "DPDDC-C";
+               break;
+       case PORT_D:
+               dev_priv->hotplug_supported_mask |= DPD_HOTPLUG_INT_STATUS;
+               name = "DPDDC-D";
+               break;
+       default:
+               WARN(1, "Invalid port %c\n", port_name(port));
+               break;
        }
  
        /* Cache some DPCD data in the eDP case */
  #define __INTEL_DRV_H__
  
  #include <linux/i2c.h>
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
 -#include "drm_crtc.h"
 -#include "drm_crtc_helper.h"
 -#include "drm_fb_helper.h"
 -#include "drm_dp_helper.h"
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/drm_fb_helper.h>
++#include <drm/drm_dp_helper.h>
  
  #define _wait_for(COND, MS, W) ({ \
        unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);       \
                        ret__ = -ETIMEDOUT;                             \
                        break;                                          \
                }                                                       \
-               if (W && drm_can_sleep()) msleep(W);    \
+               if (W && drm_can_sleep())  {                            \
+                       msleep(W);                                      \
+               } else {                                                \
+                       cpu_relax();                                    \
+               }                                                       \
        }                                                               \
        ret__;                                                          \
  })
  #define INTEL_OUTPUT_DISPLAYPORT 7
  #define INTEL_OUTPUT_EDP 8
  
- /* Intel Pipe Clone Bit */
- #define INTEL_HDMIB_CLONE_BIT 1
- #define INTEL_HDMIC_CLONE_BIT 2
- #define INTEL_HDMID_CLONE_BIT 3
- #define INTEL_HDMIE_CLONE_BIT 4
- #define INTEL_HDMIF_CLONE_BIT 5
- #define INTEL_SDVO_NON_TV_CLONE_BIT 6
- #define INTEL_SDVO_TV_CLONE_BIT 7
- #define INTEL_SDVO_LVDS_CLONE_BIT 8
- #define INTEL_ANALOG_CLONE_BIT 9
- #define INTEL_TV_CLONE_BIT 10
- #define INTEL_DP_B_CLONE_BIT 11
- #define INTEL_DP_C_CLONE_BIT 12
- #define INTEL_DP_D_CLONE_BIT 13
- #define INTEL_LVDS_CLONE_BIT 14
- #define INTEL_DVO_TMDS_CLONE_BIT 15
- #define INTEL_DVO_LVDS_CLONE_BIT 16
- #define INTEL_EDP_CLONE_BIT 17
  #define INTEL_DVO_CHIP_NONE 0
  #define INTEL_DVO_CHIP_LVDS 1
  #define INTEL_DVO_CHIP_TMDS 2
@@@ -151,16 -137,48 +137,48 @@@ struct intel_fbdev 
  
  struct intel_encoder {
        struct drm_encoder base;
+       /*
+        * The new crtc this encoder will be driven from. Only differs from
+        * base->crtc while a modeset is in progress.
+        */
+       struct intel_crtc *new_crtc;
        int type;
        bool needs_tv_clock;
+       /*
+        * Intel hw has only one MUX where encoders could be clone, hence a
+        * simple flag is enough to compute the possible_clones mask.
+        */
+       bool cloneable;
+       bool connectors_active;
        void (*hot_plug)(struct intel_encoder *);
+       void (*pre_enable)(struct intel_encoder *);
+       void (*enable)(struct intel_encoder *);
+       void (*disable)(struct intel_encoder *);
+       void (*post_disable)(struct intel_encoder *);
+       /* Read out the current hw state of this connector, returning true if
+        * the encoder is active. If the encoder is enabled it also set the pipe
+        * it is connected to in the pipe parameter. */
+       bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe);
        int crtc_mask;
-       int clone_mask;
  };
  
  struct intel_connector {
        struct drm_connector base;
+       /*
+        * The fixed encoder this connector is connected to.
+        */
        struct intel_encoder *encoder;
+       /*
+        * The new encoder this connector will be driven. Only differs from
+        * encoder while a modeset is in progress.
+        */
+       struct intel_encoder *new_encoder;
+       /* Reads out the current hw, returning true if the connector is enabled
+        * and active (i.e. dpms ON state). */
+       bool (*get_hw_state)(struct intel_connector *);
  };
  
  struct intel_crtc {
        enum pipe pipe;
        enum plane plane;
        u8 lut_r[256], lut_g[256], lut_b[256];
-       int dpms_mode;
-       bool active; /* is the crtc on? independent of the dpms mode */
+       /*
+        * Whether the crtc and the connected output pipeline is active. Implies
+        * that crtc->enabled is set, i.e. the current mode configuration has
+        * some outputs connected to this crtc.
+        */
+       bool active;
        bool primary_disabled; /* is the crtc obscured by a plane? */
-       bool busy; /* is scanout buffer being updated frequently? */
-       struct timer_list idle_timer;
        bool lowfreq_avail;
        struct intel_overlay *overlay;
        struct intel_unpin_work *unpin_work;
@@@ -311,6 -331,37 +331,37 @@@ struct intel_hdmi 
                               struct drm_display_mode *adjusted_mode);
  };
  
+ #define DP_RECEIVER_CAP_SIZE          0xf
+ #define DP_LINK_CONFIGURATION_SIZE    9
+ struct intel_dp {
+       struct intel_encoder base;
+       uint32_t output_reg;
+       uint32_t DP;
+       uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
+       bool has_audio;
+       enum hdmi_force_audio force_audio;
+       enum port port;
+       uint32_t color_range;
+       uint8_t link_bw;
+       uint8_t lane_count;
+       uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
+       struct i2c_adapter adapter;
+       struct i2c_algo_dp_aux_data algo;
+       bool is_pch_edp;
+       uint8_t train_set[4];
+       int panel_power_up_delay;
+       int panel_power_down_delay;
+       int panel_power_cycle_delay;
+       int backlight_on_delay;
+       int backlight_off_delay;
+       struct drm_display_mode *panel_fixed_mode;  /* for eDP */
+       struct delayed_work panel_vdd_work;
+       bool want_panel_vdd;
+       struct edid *edid; /* cached EDID for eDP */
+       int edid_mode_count;
+ };
  static inline struct drm_crtc *
  intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
  {
@@@ -350,17 -401,21 +401,21 @@@ extern void intel_attach_force_audio_pr
  extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
  
  extern void intel_crt_init(struct drm_device *dev);
- extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
+ extern void intel_hdmi_init(struct drm_device *dev,
+                           int sdvox_reg, enum port port);
  extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
  extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
  extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg,
                            bool is_sdvob);
  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_i915_gem_object *obj);
+ extern void intel_mark_busy(struct drm_device *dev);
+ extern void intel_mark_idle(struct drm_device *dev);
+ extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj);
+ extern void intel_mark_fb_idle(struct drm_i915_gem_object *obj);
  extern bool intel_lvds_init(struct drm_device *dev);
- extern void intel_dp_init(struct drm_device *dev, int dp_reg);
+ extern void intel_dp_init(struct drm_device *dev, int output_reg,
+                         enum port port);
  void
  intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
                 struct drm_display_mode *adjusted_mode);
@@@ -373,8 -428,6 +428,6 @@@ extern int intel_plane_init(struct drm_
  extern void intel_flush_display_plane(struct drm_i915_private *dev_priv,
                                      enum plane plane);
  
- void intel_sanitize_pm(struct drm_device *dev);
  /* intel_panel.c */
  extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
                                   struct drm_display_mode *adjusted_mode);
@@@ -391,10 -444,27 +444,27 @@@ extern void intel_panel_disable_backlig
  extern void intel_panel_destroy_backlight(struct drm_device *dev);
  extern enum drm_connector_status intel_panel_detect(struct drm_device *dev);
  
+ struct intel_set_config {
+       struct drm_encoder **save_connector_encoders;
+       struct drm_crtc **save_encoder_crtcs;
+       bool fb_changed;
+       bool mode_changed;
+ };
+ extern bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                          int x, int y, struct drm_framebuffer *old_fb);
+ extern void intel_modeset_disable(struct drm_device *dev);
  extern void intel_crtc_load_lut(struct drm_crtc *crtc);
- extern void intel_encoder_prepare(struct drm_encoder *encoder);
- extern void intel_encoder_commit(struct drm_encoder *encoder);
+ extern void intel_crtc_update_dpms(struct drm_crtc *crtc);
+ extern void intel_encoder_noop(struct drm_encoder *encoder);
  extern void intel_encoder_destroy(struct drm_encoder *encoder);
+ extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode);
+ extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder);
+ extern void intel_connector_dpms(struct drm_connector *, int mode);
+ extern bool intel_connector_get_hw_state(struct intel_connector *connector);
+ extern void intel_modeset_check_state(struct drm_device *dev);
  
  static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector)
  {
@@@ -417,12 -487,10 +487,10 @@@ struct intel_load_detect_pipe 
        bool load_detect_temp;
        int dpms_mode;
  };
- extern bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
-                                      struct drm_connector *connector,
+ extern bool intel_get_load_detect_pipe(struct drm_connector *connector,
                                       struct drm_display_mode *mode,
                                       struct intel_load_detect_pipe *old);
- extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
-                                          struct drm_connector *connector,
+ extern void intel_release_load_detect_pipe(struct drm_connector *connector,
                                           struct intel_load_detect_pipe *old);
  
  extern void intelfb_restore(void);
@@@ -503,7 -571,10 +571,10 @@@ extern void intel_disable_gt_powersave(
  extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv);
  extern void ironlake_teardown_rc6(struct drm_device *dev);
  
- extern void intel_ddi_dpms(struct drm_encoder *encoder, int mode);
+ extern void intel_enable_ddi(struct intel_encoder *encoder);
+ extern void intel_disable_ddi(struct intel_encoder *encoder);
+ extern bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
+                                  enum pipe *pipe);
  extern void intel_ddi_mode_set(struct drm_encoder *encoder,
                                struct drm_display_mode *mode,
                                struct drm_display_mode *adjusted_mode);
   */
  #include <linux/i2c.h>
  #include <linux/slab.h>
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
  #include "intel_drv.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "dvo.h"
  
  #define SIL164_ADDR   0x38
  #define CH7xxx_ADDR   0x76
  #define TFP410_ADDR   0x38
+ #define NS2501_ADDR     0x38
  
  static const struct intel_dvo_device intel_dvo_devices[] = {
        {
                .slave_addr = 0x75,
                .gpio = GMBUS_PORT_DPB,
                .dev_ops = &ch7017_ops,
-       }
+       },
+       {
+               .type = INTEL_DVO_CHIP_TMDS,
+               .name = "ns2501",
+               .dvo_reg = DVOC,
+               .slave_addr = NS2501_ADDR,
+               .dev_ops = &ns2501_ops,
+        }
  };
  
  struct intel_dvo {
@@@ -96,22 -105,91 +104,91 @@@ static struct intel_dvo *intel_attached
                            struct intel_dvo, base);
  }
  
- static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
+ static bool intel_dvo_connector_get_hw_state(struct intel_connector *connector)
  {
-       struct drm_i915_private *dev_priv = encoder->dev->dev_private;
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+       struct intel_dvo *intel_dvo = intel_attached_dvo(&connector->base);
+       return intel_dvo->dev.dev_ops->get_hw_state(&intel_dvo->dev);
+ }
+ static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
+                                  enum pipe *pipe)
+ {
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
+       u32 tmp;
+       tmp = I915_READ(intel_dvo->dev.dvo_reg);
+       if (!(tmp & DVO_ENABLE))
+               return false;
+       *pipe = PORT_TO_PIPE(tmp);
+       return true;
+ }
+ static void intel_disable_dvo(struct intel_encoder *encoder)
+ {
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
+       u32 dvo_reg = intel_dvo->dev.dvo_reg;
+       u32 temp = I915_READ(dvo_reg);
+       intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
+       I915_WRITE(dvo_reg, temp & ~DVO_ENABLE);
+       I915_READ(dvo_reg);
+ }
+ static void intel_enable_dvo(struct intel_encoder *encoder)
+ {
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
        u32 dvo_reg = intel_dvo->dev.dvo_reg;
        u32 temp = I915_READ(dvo_reg);
  
+       I915_WRITE(dvo_reg, temp | DVO_ENABLE);
+       I915_READ(dvo_reg);
+       intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
+ }
+ static void intel_dvo_dpms(struct drm_connector *connector, int mode)
+ {
+       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
+       struct drm_crtc *crtc;
+       /* dvo supports only 2 dpms states. */
+       if (mode != DRM_MODE_DPMS_ON)
+               mode = DRM_MODE_DPMS_OFF;
+       if (mode == connector->dpms)
+               return;
+       connector->dpms = mode;
+       /* Only need to change hw state when actually enabled */
+       crtc = intel_dvo->base.base.crtc;
+       if (!crtc) {
+               intel_dvo->base.connectors_active = false;
+               return;
+       }
        if (mode == DRM_MODE_DPMS_ON) {
-               I915_WRITE(dvo_reg, temp | DVO_ENABLE);
-               I915_READ(dvo_reg);
-               intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, mode);
+               intel_dvo->base.connectors_active = true;
+               intel_crtc_update_dpms(crtc);
+               intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
        } else {
-               intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, mode);
-               I915_WRITE(dvo_reg, temp & ~DVO_ENABLE);
-               I915_READ(dvo_reg);
+               intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
+               intel_dvo->base.connectors_active = false;
+               intel_crtc_update_dpms(crtc);
        }
+       intel_modeset_check_state(connector->dev);
  }
  
  static int intel_dvo_mode_valid(struct drm_connector *connector,
@@@ -266,15 -344,13 +343,13 @@@ static void intel_dvo_destroy(struct dr
  }
  
  static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = {
-       .dpms = intel_dvo_dpms,
        .mode_fixup = intel_dvo_mode_fixup,
-       .prepare = intel_encoder_prepare,
        .mode_set = intel_dvo_mode_set,
-       .commit = intel_encoder_commit,
+       .disable = intel_encoder_noop,
  };
  
  static const struct drm_connector_funcs intel_dvo_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = intel_dvo_dpms,
        .detect = intel_dvo_detect,
        .destroy = intel_dvo_destroy,
        .fill_modes = drm_helper_probe_single_connector_modes,
@@@ -363,6 -439,11 +438,11 @@@ void intel_dvo_init(struct drm_device *
        drm_encoder_init(dev, &intel_encoder->base,
                         &intel_dvo_enc_funcs, encoder_type);
  
+       intel_encoder->disable = intel_disable_dvo;
+       intel_encoder->enable = intel_enable_dvo;
+       intel_encoder->get_hw_state = intel_dvo_get_hw_state;
+       intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
        /* Now, try to find a controller */
        for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
                struct drm_connector *connector = &intel_connector->base;
                intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
                switch (dvo->type) {
                case INTEL_DVO_CHIP_TMDS:
-                       intel_encoder->clone_mask =
-                               (1 << INTEL_DVO_TMDS_CLONE_BIT) |
-                               (1 << INTEL_ANALOG_CLONE_BIT);
+                       intel_encoder->cloneable = true;
                        drm_connector_init(dev, connector,
                                           &intel_dvo_connector_funcs,
                                           DRM_MODE_CONNECTOR_DVII);
                        encoder_type = DRM_MODE_ENCODER_TMDS;
                        break;
                case INTEL_DVO_CHIP_LVDS:
-                       intel_encoder->clone_mask =
-                               (1 << INTEL_DVO_LVDS_CLONE_BIT);
+                       intel_encoder->cloneable = false;
                        drm_connector_init(dev, connector,
                                           &intel_dvo_connector_funcs,
                                           DRM_MODE_CONNECTOR_LVDS);
  #include <linux/i2c.h>
  #include <linux/slab.h>
  #include <linux/delay.h>
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 -#include "drm_edid.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_edid.h>
  #include "intel_drv.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  
  static void
@@@ -150,6 -151,9 +150,9 @@@ static void g4x_write_infoframe(struct 
                I915_WRITE(VIDEO_DIP_DATA, *data);
                data++;
        }
+       /* Write every possible data byte to force correct ECC calculation. */
+       for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
+               I915_WRITE(VIDEO_DIP_DATA, 0);
        mmiowb();
  
        val |= g4x_infoframe_enable(frame);
@@@ -185,6 -189,9 +188,9 @@@ static void ibx_write_infoframe(struct 
                I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
                data++;
        }
+       /* Write every possible data byte to force correct ECC calculation. */
+       for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
+               I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
        mmiowb();
  
        val |= g4x_infoframe_enable(frame);
@@@ -223,6 -230,9 +229,9 @@@ static void cpt_write_infoframe(struct 
                I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
                data++;
        }
+       /* Write every possible data byte to force correct ECC calculation. */
+       for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
+               I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
        mmiowb();
  
        val |= g4x_infoframe_enable(frame);
@@@ -258,6 -268,9 +267,9 @@@ static void vlv_write_infoframe(struct 
                I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
                data++;
        }
+       /* Write every possible data byte to force correct ECC calculation. */
+       for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
+               I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
        mmiowb();
  
        val |= g4x_infoframe_enable(frame);
@@@ -291,6 -304,9 +303,9 @@@ static void hsw_write_infoframe(struct 
                I915_WRITE(data_reg + i, *data);
                data++;
        }
+       /* Write every possible data byte to force correct ECC calculation. */
+       for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
+               I915_WRITE(data_reg + i, 0);
        mmiowb();
  
        val |= hsw_infoframe_enable(frame);
@@@ -376,6 -392,7 +391,7 @@@ static void g4x_set_infoframes(struct d
                port = VIDEO_DIP_PORT_C;
                break;
        default:
+               BUG();
                return;
        }
  
@@@ -434,6 -451,7 +450,7 @@@ static void ibx_set_infoframes(struct d
                port = VIDEO_DIP_PORT_D;
                break;
        default:
+               BUG();
                return;
        }
  
@@@ -600,15 -618,36 +617,36 @@@ static void intel_hdmi_mode_set(struct 
        intel_hdmi->set_infoframes(encoder, adjusted_mode);
  }
  
- static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
+ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
+                                   enum pipe *pipe)
  {
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       u32 tmp;
+       tmp = I915_READ(intel_hdmi->sdvox_reg);
+       if (!(tmp & SDVO_ENABLE))
+               return false;
+       if (HAS_PCH_CPT(dev))
+               *pipe = PORT_TO_PIPE_CPT(tmp);
+       else
+               *pipe = PORT_TO_PIPE(tmp);
+       return true;
+ }
+ static void intel_enable_hdmi(struct intel_encoder *encoder)
+ {
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
        u32 temp;
        u32 enable_bits = SDVO_ENABLE;
  
-       if (intel_hdmi->has_audio || mode != DRM_MODE_DPMS_ON)
+       if (intel_hdmi->has_audio)
                enable_bits |= SDVO_AUDIO_ENABLE;
  
        temp = I915_READ(intel_hdmi->sdvox_reg);
        /* HW workaround for IBX, we need to move the port to transcoder A
         * before disabling it. */
        if (HAS_PCH_IBX(dev)) {
-               struct drm_crtc *crtc = encoder->crtc;
+               struct drm_crtc *crtc = encoder->base.crtc;
                int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
  
-               if (mode != DRM_MODE_DPMS_ON) {
-                       if (temp & SDVO_PIPE_B_SELECT) {
-                               temp &= ~SDVO_PIPE_B_SELECT;
-                               I915_WRITE(intel_hdmi->sdvox_reg, temp);
-                               POSTING_READ(intel_hdmi->sdvox_reg);
-                               /* Again we need to write this twice. */
-                               I915_WRITE(intel_hdmi->sdvox_reg, temp);
-                               POSTING_READ(intel_hdmi->sdvox_reg);
-                               /* Transcoder selection bits only update
-                                * effectively on vblank. */
-                               if (crtc)
-                                       intel_wait_for_vblank(dev, pipe);
-                               else
-                                       msleep(50);
-                       }
-               } else {
-                       /* Restore the transcoder select bit. */
-                       if (pipe == PIPE_B)
-                               enable_bits |= SDVO_PIPE_B_SELECT;
-               }
+               /* Restore the transcoder select bit. */
+               if (pipe == PIPE_B)
+                       enable_bits |= SDVO_PIPE_B_SELECT;
        }
  
        /* HW workaround, need to toggle enable bit off and on for 12bpc, but
                POSTING_READ(intel_hdmi->sdvox_reg);
        }
  
-       if (mode != DRM_MODE_DPMS_ON) {
-               temp &= ~enable_bits;
-       } else {
-               temp |= enable_bits;
+       temp |= enable_bits;
+       I915_WRITE(intel_hdmi->sdvox_reg, temp);
+       POSTING_READ(intel_hdmi->sdvox_reg);
+       /* HW workaround, need to write this twice for issue that may result
+        * in first write getting masked.
+        */
+       if (HAS_PCH_SPLIT(dev)) {
+               I915_WRITE(intel_hdmi->sdvox_reg, temp);
+               POSTING_READ(intel_hdmi->sdvox_reg);
+       }
+ }
+ static void intel_disable_hdmi(struct intel_encoder *encoder)
+ {
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       u32 temp;
+       u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE;
+       temp = I915_READ(intel_hdmi->sdvox_reg);
+       /* HW workaround for IBX, we need to move the port to transcoder A
+        * before disabling it. */
+       if (HAS_PCH_IBX(dev)) {
+               struct drm_crtc *crtc = encoder->base.crtc;
+               int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
+               if (temp & SDVO_PIPE_B_SELECT) {
+                       temp &= ~SDVO_PIPE_B_SELECT;
+                       I915_WRITE(intel_hdmi->sdvox_reg, temp);
+                       POSTING_READ(intel_hdmi->sdvox_reg);
+                       /* Again we need to write this twice. */
+                       I915_WRITE(intel_hdmi->sdvox_reg, temp);
+                       POSTING_READ(intel_hdmi->sdvox_reg);
+                       /* Transcoder selection bits only update
+                        * effectively on vblank. */
+                       if (crtc)
+                               intel_wait_for_vblank(dev, pipe);
+                       else
+                               msleep(50);
+               }
+       }
+       /* HW workaround, need to toggle enable bit off and on for 12bpc, but
+        * we do this anyway which shows more stable in testing.
+        */
+       if (HAS_PCH_SPLIT(dev)) {
+               I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
+               POSTING_READ(intel_hdmi->sdvox_reg);
        }
  
+       temp &= ~enable_bits;
        I915_WRITE(intel_hdmi->sdvox_reg, temp);
        POSTING_READ(intel_hdmi->sdvox_reg);
  
@@@ -736,7 -808,6 +807,6 @@@ intel_hdmi_detect(struct drm_connector 
                                                drm_detect_hdmi_monitor(edid);
                        intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
                }
-               connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
  
@@@ -777,8 -848,6 +847,6 @@@ intel_hdmi_detect_audio(struct drm_conn
        if (edid) {
                if (edid->input & DRM_EDID_INPUT_DIGITAL)
                        has_audio = drm_detect_monitor_audio(edid);
-               connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
  
@@@ -832,9 -901,8 +900,8 @@@ intel_hdmi_set_property(struct drm_conn
  done:
        if (intel_hdmi->base.base.crtc) {
                struct drm_crtc *crtc = intel_hdmi->base.base.crtc;
-               drm_crtc_helper_set_mode(crtc, &crtc->mode,
-                                        crtc->x, crtc->y,
-                                        crtc->fb);
+               intel_set_mode(crtc, &crtc->mode,
+                              crtc->x, crtc->y, crtc->fb);
        }
  
        return 0;
@@@ -848,23 -916,19 +915,19 @@@ static void intel_hdmi_destroy(struct d
  }
  
  static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = {
-       .dpms = intel_ddi_dpms,
        .mode_fixup = intel_hdmi_mode_fixup,
-       .prepare = intel_encoder_prepare,
        .mode_set = intel_ddi_mode_set,
-       .commit = intel_encoder_commit,
+       .disable = intel_encoder_noop,
  };
  
  static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
-       .dpms = intel_hdmi_dpms,
        .mode_fixup = intel_hdmi_mode_fixup,
-       .prepare = intel_encoder_prepare,
        .mode_set = intel_hdmi_mode_set,
-       .commit = intel_encoder_commit,
+       .disable = intel_encoder_noop,
  };
  
  static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = intel_connector_dpms,
        .detect = intel_hdmi_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_hdmi_set_property,
@@@ -888,7 -952,7 +951,7 @@@ intel_hdmi_add_properties(struct intel_
        intel_attach_broadcast_rgb_property(connector);
  }
  
- void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
+ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_connector *connector;
        connector->doublescan_allowed = 0;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
  
-       /* Set up the DDC bus. */
-       if (sdvox_reg == SDVOB) {
-               intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
-               intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
-               dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
-       } else if (sdvox_reg == SDVOC) {
-               intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
-               intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
-               dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
-       } else if (sdvox_reg == HDMIB) {
-               intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
-               intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
-               dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
-       } else if (sdvox_reg == HDMIC) {
-               intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
-               intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
-               dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
-       } else if (sdvox_reg == HDMID) {
-               intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
-               intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
-               dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
-       } else if (sdvox_reg == DDI_BUF_CTL(PORT_B)) {
-               DRM_DEBUG_DRIVER("LPT: detected output on DDI B\n");
-               intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
+       intel_encoder->cloneable = false;
+       intel_hdmi->ddi_port = port;
+       switch (port) {
+       case PORT_B:
                intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
-               intel_hdmi->ddi_port = PORT_B;
                dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
-       } else if (sdvox_reg == DDI_BUF_CTL(PORT_C)) {
-               DRM_DEBUG_DRIVER("LPT: detected output on DDI C\n");
-               intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
+               break;
+       case PORT_C:
                intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
-               intel_hdmi->ddi_port = PORT_C;
                dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
-       } else if (sdvox_reg == DDI_BUF_CTL(PORT_D)) {
-               DRM_DEBUG_DRIVER("LPT: detected output on DDI D\n");
-               intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
+               break;
+       case PORT_D:
                intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
-               intel_hdmi->ddi_port = PORT_D;
                dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
-       } else {
-               /* If we got an unknown sdvox_reg, things are pretty much broken
-                * in a way that we should let the kernel know about it */
+               break;
+       case PORT_A:
+               /* Internal port only for eDP. */
+       default:
                BUG();
        }
  
                intel_hdmi->set_infoframes = cpt_set_infoframes;
        }
  
-       if (IS_HASWELL(dev))
-               drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw);
-       else
-               drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
+       if (IS_HASWELL(dev)) {
+               intel_encoder->enable = intel_enable_ddi;
+               intel_encoder->disable = intel_disable_ddi;
+               intel_encoder->get_hw_state = intel_ddi_get_hw_state;
+               drm_encoder_helper_add(&intel_encoder->base,
+                                      &intel_hdmi_helper_funcs_hsw);
+       } else {
+               intel_encoder->enable = intel_enable_hdmi;
+               intel_encoder->disable = intel_disable_hdmi;
+               intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
+               drm_encoder_helper_add(&intel_encoder->base,
+                                      &intel_hdmi_helper_funcs);
+       }
+       intel_connector->get_hw_state = intel_connector_get_hw_state;
  
        intel_hdmi_add_properties(intel_hdmi, connector);
  
  #include <linux/dmi.h>
  #include <linux/i2c.h>
  #include <linux/slab.h>
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 -#include "drm_edid.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_edid.h>
  #include "intel_drv.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include <linux/acpi.h>
  
@@@ -64,13 -65,40 +64,40 @@@ static struct intel_lvds *intel_attache
                            struct intel_lvds, base);
  }
  
+ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
+                                   enum pipe *pipe)
+ {
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 lvds_reg, tmp;
+       if (HAS_PCH_SPLIT(dev)) {
+               lvds_reg = PCH_LVDS;
+       } else {
+               lvds_reg = LVDS;
+       }
+       tmp = I915_READ(lvds_reg);
+       if (!(tmp & LVDS_PORT_EN))
+               return false;
+       if (HAS_PCH_CPT(dev))
+               *pipe = PORT_TO_PIPE_CPT(tmp);
+       else
+               *pipe = PORT_TO_PIPE(tmp);
+       return true;
+ }
  /**
   * Sets the power state for the panel.
   */
- static void intel_lvds_enable(struct intel_lvds *intel_lvds)
+ static void intel_enable_lvds(struct intel_encoder *encoder)
  {
-       struct drm_device *dev = intel_lvds->base.base.dev;
-       struct intel_crtc *intel_crtc = to_intel_crtc(intel_lvds->base.base.crtc);
+       struct drm_device *dev = encoder->base.dev;
+       struct intel_lvds *intel_lvds = to_intel_lvds(&encoder->base);
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 ctl_reg, lvds_reg, stat_reg;
  
        intel_panel_enable_backlight(dev, intel_crtc->pipe);
  }
  
- static void intel_lvds_disable(struct intel_lvds *intel_lvds)
+ static void intel_disable_lvds(struct intel_encoder *encoder)
  {
-       struct drm_device *dev = intel_lvds->base.base.dev;
+       struct drm_device *dev = encoder->base.dev;
+       struct intel_lvds *intel_lvds = to_intel_lvds(&encoder->base);
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 ctl_reg, lvds_reg, stat_reg;
  
        POSTING_READ(lvds_reg);
  }
  
- static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
- {
-       struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
-       if (mode == DRM_MODE_DPMS_ON)
-               intel_lvds_enable(intel_lvds);
-       else
-               intel_lvds_disable(intel_lvds);
-       /* XXX: We never power down the LVDS pairs. */
- }
  static int intel_lvds_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
  {
@@@ -233,9 -250,8 +249,8 @@@ static bool intel_lvds_mode_fixup(struc
  {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
        struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
-       struct intel_encoder *tmp_encoder;
+       struct intel_crtc *intel_crtc = intel_lvds->base.new_crtc;
        u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
        int pipe;
  
                return false;
        }
  
-       /* Should never happen!! */
-       for_each_encoder_on_crtc(dev, encoder->crtc, tmp_encoder) {
-               if (&tmp_encoder->base != encoder) {
-                       DRM_ERROR("Can't enable LVDS and another "
-                              "encoder on the same pipe\n");
-                       return false;
-               }
-       }
+       if (intel_encoder_check_is_cloned(&intel_lvds->base))
+               return false;
  
        /*
         * We have timings from the BIOS for the panel, put them in
@@@ -404,23 -414,6 +413,6 @@@ out
        return true;
  }
  
- static void intel_lvds_prepare(struct drm_encoder *encoder)
- {
-       struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
-       intel_lvds_disable(intel_lvds);
- }
- static void intel_lvds_commit(struct drm_encoder *encoder)
- {
-       struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
-       /* Always do a full power on as we do not know what state
-        * we were left in.
-        */
-       intel_lvds_enable(intel_lvds);
- }
  static void intel_lvds_mode_set(struct drm_encoder *encoder,
                                struct drm_display_mode *mode,
                                struct drm_display_mode *adjusted_mode)
@@@ -534,7 -527,7 +526,7 @@@ static int intel_lid_notify(struct noti
        dev_priv->modeset_on_lid = 0;
  
        mutex_lock(&dev->mode_config.mutex);
-       drm_helper_resume_force_mode(dev);
+       intel_modeset_check_state(dev);
        mutex_unlock(&dev->mode_config.mutex);
  
        return NOTIFY_OK;
@@@ -586,8 -579,8 +578,8 @@@ static int intel_lvds_set_property(stru
                         * If the CRTC is enabled, the display will be changed
                         * according to the new panel fitting mode.
                         */
-                       drm_crtc_helper_set_mode(crtc, &crtc->mode,
-                               crtc->x, crtc->y, crtc->fb);
+                       intel_set_mode(crtc, &crtc->mode,
+                                      crtc->x, crtc->y, crtc->fb);
                }
        }
  
  }
  
  static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
-       .dpms = intel_lvds_dpms,
        .mode_fixup = intel_lvds_mode_fixup,
-       .prepare = intel_lvds_prepare,
        .mode_set = intel_lvds_mode_set,
-       .commit = intel_lvds_commit,
+       .disable = intel_encoder_noop,
  };
  
  static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
  };
  
  static const struct drm_connector_funcs intel_lvds_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = intel_connector_dpms,
        .detect = intel_lvds_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_lvds_set_property,
@@@ -971,10 -962,15 +961,15 @@@ bool intel_lvds_init(struct drm_device 
        drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
                         DRM_MODE_ENCODER_LVDS);
  
+       intel_encoder->enable = intel_enable_lvds;
+       intel_encoder->disable = intel_disable_lvds;
+       intel_encoder->get_hw_state = intel_lvds_get_hw_state;
+       intel_connector->get_hw_state = intel_connector_get_hw_state;
        intel_connector_attach_encoder(intel_connector, intel_encoder);
        intel_encoder->type = INTEL_OUTPUT_LVDS;
  
-       intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
+       intel_encoder->cloneable = false;
        if (HAS_PCH_SPLIT(dev))
                intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
        else if (IS_GEN4(dev))
@@@ -27,8 -27,8 +27,8 @@@
  #include <linux/i2c.h>
  #include <linux/fb.h>
  #include <drm/drm_edid.h>
 -#include "drmP.h"
 -#include "drm_edid.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_edid.h>
  #include "intel_drv.h"
  #include "i915_drv.h"
  
@@@ -45,7 -45,6 +45,6 @@@ int intel_connector_update_modes(struc
        drm_mode_connector_update_edid_property(connector, edid);
        ret = drm_add_edid_modes(connector, edid);
        drm_edid_to_eld(connector, edid);
-       connector->display_info.raw_edid = NULL;
        kfree(edid);
  
        return ret;
@@@ -31,8 -31,8 +31,8 @@@
  #include <linux/acpi_io.h>
  #include <acpi/video.h>
  
 -#include "drmP.h"
 -#include "i915_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "intel_drv.h"
  
@@@ -427,6 -427,25 +427,25 @@@ blind_set
        goto end;
  }
  
+ static void intel_setup_cadls(struct drm_device *dev)
+ {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_opregion *opregion = &dev_priv->opregion;
+       int i = 0;
+       u32 disp_id;
+       /* Initialize the CADL field by duplicating the DIDL values.
+        * Technically, this is not always correct as display outputs may exist,
+        * but not active. This initialization is necessary for some Clevo
+        * laptops that check this field before processing the brightness and
+        * display switching hotkeys. Just like DIDL, CADL is NULL-terminated if
+        * there are less than eight devices. */
+       do {
+               disp_id = ioread32(&opregion->acpi->didl[i]);
+               iowrite32(disp_id, &opregion->acpi->cadl[i]);
+       } while (++i < 8 && disp_id != 0);
+ }
  void intel_opregion_init(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
                return;
  
        if (opregion->acpi) {
-               if (drm_core_check_feature(dev, DRIVER_MODESET))
+               if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                        intel_didl_outputs(dev);
+                       intel_setup_cadls(dev);
+               }
  
                /* Notify BIOS we are ready to handle ACPI video ext notifs.
                 * Right now, all the events are handled by the ACPI video module.
@@@ -25,8 -25,9 +25,8 @@@
   *
   * Derived from Xorg ddx, xf86-video-intel, src/i830_video.c
   */
 -#include "drmP.h"
 -#include "drm.h"
 -#include "i915_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "i915_reg.h"
  #include "intel_drv.h"
@@@ -234,54 -235,6 +234,6 @@@ static int intel_overlay_do_wait_reques
        return 0;
  }
  
- /* Workaround for i830 bug where pipe a must be enable to change control regs */
- static int
- i830_activate_pipe_a(struct drm_device *dev)
- {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       struct intel_crtc *crtc;
-       struct drm_crtc_helper_funcs *crtc_funcs;
-       struct drm_display_mode vesa_640x480 = {
-               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)
-       }, *mode;
-       crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]);
-       if (crtc->dpms_mode == DRM_MODE_DPMS_ON)
-               return 0;
-       /* most i8xx have pipe a forced on, so don't trust dpms mode */
-       if (I915_READ(_PIPEACONF) & PIPECONF_ENABLE)
-               return 0;
-       crtc_funcs = crtc->base.helper_private;
-       if (crtc_funcs->dpms == NULL)
-               return 0;
-       DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");
-       mode = drm_mode_duplicate(dev, &vesa_640x480);
-       if (!drm_crtc_helper_set_mode(&crtc->base, mode,
-                                      crtc->base.x, crtc->base.y,
-                                      crtc->base.fb))
-               return 0;
-       crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON);
-       return 1;
- }
- static void
- i830_deactivate_pipe_a(struct drm_device *dev)
- {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0];
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
- }
  /* overlay needs to be disable in OCMD reg */
  static int intel_overlay_on(struct intel_overlay *overlay)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
        struct drm_i915_gem_request *request;
-       int pipe_a_quirk = 0;
        int ret;
  
        BUG_ON(overlay->active);
        overlay->active = 1;
  
-       if (IS_I830(dev)) {
-               pipe_a_quirk = i830_activate_pipe_a(dev);
-               if (pipe_a_quirk < 0)
-                       return pipe_a_quirk;
-       }
+       WARN_ON(IS_I830(dev) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE));
  
        request = kzalloc(sizeof(*request), GFP_KERNEL);
        if (request == NULL) {
  
        ret = intel_overlay_do_wait_request(overlay, request, NULL);
  out:
-       if (pipe_a_quirk)
-               i830_deactivate_pipe_a(dev);
        return ret;
  }
  
@@@ -1438,7 -1383,7 +1382,7 @@@ void intel_setup_overlay(struct drm_dev
                }
                overlay->flip_addr = reg_bo->phys_obj->handle->busaddr;
        } else {
-               ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true);
+               ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true, false);
                if (ret) {
                        DRM_ERROR("failed to pin overlay register bo\n");
                        goto out_free_bo;
   *
   */
  
 -#include "drmP.h"
 -#include "drm.h"
 +#include <drm/drmP.h>
  #include "i915_drv.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_trace.h"
  #include "intel_drv.h"
  
@@@ -261,6 -262,83 +261,83 @@@ gen6_render_ring_flush(struct intel_rin
        return 0;
  }
  
+ static int
+ gen7_render_ring_cs_stall_wa(struct intel_ring_buffer *ring)
+ {
+       int ret;
+       ret = intel_ring_begin(ring, 4);
+       if (ret)
+               return ret;
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
+       intel_ring_emit(ring, PIPE_CONTROL_CS_STALL |
+                             PIPE_CONTROL_STALL_AT_SCOREBOARD);
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, 0);
+       intel_ring_advance(ring);
+       return 0;
+ }
+ static int
+ gen7_render_ring_flush(struct intel_ring_buffer *ring,
+                      u32 invalidate_domains, u32 flush_domains)
+ {
+       u32 flags = 0;
+       struct pipe_control *pc = ring->private;
+       u32 scratch_addr = pc->gtt_offset + 128;
+       int ret;
+       /*
+        * Ensure that any following seqno writes only happen when the render
+        * cache is indeed flushed.
+        *
+        * Workaround: 4th PIPE_CONTROL command (except the ones with only
+        * read-cache invalidate bits set) must have the CS_STALL bit set. We
+        * don't try to be clever and just set it unconditionally.
+        */
+       flags |= PIPE_CONTROL_CS_STALL;
+       /* Just flush everything.  Experiments have shown that reducing the
+        * number of bits based on the write domains has little performance
+        * impact.
+        */
+       if (flush_domains) {
+               flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
+               flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+       }
+       if (invalidate_domains) {
+               flags |= PIPE_CONTROL_TLB_INVALIDATE;
+               flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
+               /*
+                * TLB invalidate requires a post-sync write.
+                */
+               flags |= PIPE_CONTROL_QW_WRITE;
+               /* Workaround: we must issue a pipe_control with CS-stall bit
+                * set before a pipe_control command that has the state cache
+                * invalidate bit set. */
+               gen7_render_ring_cs_stall_wa(ring);
+       }
+       ret = intel_ring_begin(ring, 4);
+       if (ret)
+               return ret;
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
+       intel_ring_emit(ring, flags);
+       intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT);
+       intel_ring_emit(ring, 0);
+       intel_ring_advance(ring);
+       return 0;
+ }
  static void ring_write_tail(struct intel_ring_buffer *ring,
                            u32 value)
  {
@@@ -381,12 -459,12 +458,12 @@@ init_pipe_control(struct intel_ring_buf
  
        i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
  
-       ret = i915_gem_object_pin(obj, 4096, true);
+       ret = i915_gem_object_pin(obj, 4096, true, false);
        if (ret)
                goto err_unref;
  
        pc->gtt_offset = obj->gtt_offset;
-       pc->cpu_page =  kmap(obj->pages[0]);
+       pc->cpu_page =  kmap(sg_page(obj->pages->sgl));
        if (pc->cpu_page == NULL)
                goto err_unpin;
  
@@@ -413,7 -491,8 +490,8 @@@ cleanup_pipe_control(struct intel_ring_
                return;
  
        obj = pc->obj;
-       kunmap(obj->pages[0]);
+       kunmap(sg_page(obj->pages->sgl));
        i915_gem_object_unpin(obj);
        drm_gem_object_unreference(&obj->base);
  
@@@ -461,7 -540,7 +539,7 @@@ static int init_render_ring(struct inte
        if (INTEL_INFO(dev)->gen >= 6)
                I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
  
-       if (IS_IVYBRIDGE(dev))
+       if (HAS_L3_GPU_CACHE(dev))
                I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
  
        return ret;
@@@ -627,26 -706,24 +705,24 @@@ pc_render_add_request(struct intel_ring
  }
  
  static u32
- gen6_ring_get_seqno(struct intel_ring_buffer *ring)
+ gen6_ring_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency)
  {
-       struct drm_device *dev = ring->dev;
        /* Workaround to force correct ordering between irq and seqno writes on
         * ivb (and maybe also on snb) by reading from a CS register (like
         * ACTHD) before reading the status page. */
-       if (IS_GEN6(dev) || IS_GEN7(dev))
+       if (!lazy_coherency)
                intel_ring_get_active_head(ring);
        return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
  }
  
  static u32
- ring_get_seqno(struct intel_ring_buffer *ring)
+ ring_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency)
  {
        return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
  }
  
  static u32
- pc_render_get_seqno(struct intel_ring_buffer *ring)
+ pc_render_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency)
  {
        struct pipe_control *pc = ring->private;
        return pc->cpu_page[0];
@@@ -851,7 -928,7 +927,7 @@@ gen6_ring_get_irq(struct intel_ring_buf
  
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
        if (ring->irq_refcount++ == 0) {
-               if (IS_IVYBRIDGE(dev) && ring->id == RCS)
+               if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
                        I915_WRITE_IMR(ring, ~(ring->irq_enable_mask |
                                                GEN6_RENDER_L3_PARITY_ERROR));
                else
@@@ -874,7 -951,7 +950,7 @@@ gen6_ring_put_irq(struct intel_ring_buf
  
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
        if (--ring->irq_refcount == 0) {
-               if (IS_IVYBRIDGE(dev) && ring->id == RCS)
+               if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
                        I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
                else
                        I915_WRITE_IMR(ring, ~0);
@@@ -950,7 -1027,7 +1026,7 @@@ static void cleanup_status_page(struct 
        if (obj == NULL)
                return;
  
-       kunmap(obj->pages[0]);
+       kunmap(sg_page(obj->pages->sgl));
        i915_gem_object_unpin(obj);
        drm_gem_object_unreference(&obj->base);
        ring->status_page.obj = NULL;
@@@ -971,13 -1048,13 +1047,13 @@@ static int init_status_page(struct inte
  
        i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
  
-       ret = i915_gem_object_pin(obj, 4096, true);
+       ret = i915_gem_object_pin(obj, 4096, true, false);
        if (ret != 0) {
                goto err_unref;
        }
  
        ring->status_page.gfx_addr = obj->gtt_offset;
-       ring->status_page.page_addr = kmap(obj->pages[0]);
+       ring->status_page.page_addr = kmap(sg_page(obj->pages->sgl));
        if (ring->status_page.page_addr == NULL) {
                ret = -ENOMEM;
                goto err_unpin;
@@@ -1009,7 -1086,6 +1085,6 @@@ static int intel_init_ring_buffer(struc
        ring->dev = dev;
        INIT_LIST_HEAD(&ring->active_list);
        INIT_LIST_HEAD(&ring->request_list);
-       INIT_LIST_HEAD(&ring->gpu_write_list);
        ring->size = 32 * PAGE_SIZE;
  
        init_waitqueue_head(&ring->irq_queue);
  
        ring->obj = obj;
  
-       ret = i915_gem_object_pin(obj, PAGE_SIZE, true);
+       ret = i915_gem_object_pin(obj, PAGE_SIZE, true, false);
        if (ret)
                goto err_unref;
  
@@@ -1378,7 -1454,9 +1453,9 @@@ int intel_init_render_ring_buffer(struc
  
        if (INTEL_INFO(dev)->gen >= 6) {
                ring->add_request = gen6_add_request;
-               ring->flush = gen6_render_ring_flush;
+               ring->flush = gen7_render_ring_flush;
+               if (INTEL_INFO(dev)->gen == 6)
+                       ring->flush = gen6_render_ring_flush;
                ring->irq_get = gen6_ring_get_irq;
                ring->irq_put = gen6_ring_put_irq;
                ring->irq_enable_mask = GT_USER_INTERRUPT;
@@@ -1480,7 -1558,6 +1557,6 @@@ int intel_render_ring_init_dri(struct d
        ring->dev = dev;
        INIT_LIST_HEAD(&ring->active_list);
        INIT_LIST_HEAD(&ring->request_list);
-       INIT_LIST_HEAD(&ring->gpu_write_list);
  
        ring->size = size;
        ring->effective_size = ring->size;
@@@ -1573,3 -1650,41 +1649,41 @@@ int intel_init_blt_ring_buffer(struct d
  
        return intel_init_ring_buffer(dev, ring);
  }
+ int
+ intel_ring_flush_all_caches(struct intel_ring_buffer *ring)
+ {
+       int ret;
+       if (!ring->gpu_caches_dirty)
+               return 0;
+       ret = ring->flush(ring, 0, I915_GEM_GPU_DOMAINS);
+       if (ret)
+               return ret;
+       trace_i915_gem_ring_flush(ring, 0, I915_GEM_GPU_DOMAINS);
+       ring->gpu_caches_dirty = false;
+       return 0;
+ }
+ int
+ intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring)
+ {
+       uint32_t flush_domains;
+       int ret;
+       flush_domains = 0;
+       if (ring->gpu_caches_dirty)
+               flush_domains = I915_GEM_GPU_DOMAINS;
+       ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, flush_domains);
+       if (ret)
+               return ret;
+       trace_i915_gem_ring_flush(ring, I915_GEM_GPU_DOMAINS, flush_domains);
+       ring->gpu_caches_dirty = false;
+       return 0;
+ }
  #include <linux/slab.h>
  #include <linux/delay.h>
  #include <linux/export.h>
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 -#include "drm_edid.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_edid.h>
  #include "intel_drv.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "intel_sdvo_regs.h"
  
@@@ -96,7 -97,7 +96,7 @@@ struct intel_sdvo 
        /*
         * Hotplug activation bits for this device
         */
-       uint8_t hotplug_active[2];
+       uint16_t hotplug_active;
  
        /**
         * This is used to select the color range of RBG outputs in HDMI mode.
@@@ -627,6 -628,14 +627,14 @@@ static bool intel_sdvo_set_active_outpu
                                    &outputs, sizeof(outputs));
  }
  
+ static bool intel_sdvo_get_active_outputs(struct intel_sdvo *intel_sdvo,
+                                         u16 *outputs)
+ {
+       return intel_sdvo_get_value(intel_sdvo,
+                                   SDVO_CMD_GET_ACTIVE_OUTPUTS,
+                                   outputs, sizeof(*outputs));
+ }
  static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo,
                                               int mode)
  {
@@@ -1141,51 -1150,132 +1149,132 @@@ static void intel_sdvo_mode_set(struct 
        intel_sdvo_write_sdvox(intel_sdvo, sdvox);
  }
  
- static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
+ static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector)
  {
-       struct drm_device *dev = encoder->dev;
+       struct intel_sdvo_connector *intel_sdvo_connector =
+               to_intel_sdvo_connector(&connector->base);
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(&connector->base);
+       u16 active_outputs;
+       intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs);
+       if (active_outputs & intel_sdvo_connector->output_flag)
+               return true;
+       else
+               return false;
+ }
+ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
+                                   enum pipe *pipe)
+ {
+       struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
-       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+       u32 tmp;
+       tmp = I915_READ(intel_sdvo->sdvo_reg);
+       if (!(tmp & SDVO_ENABLE))
+               return false;
+       if (HAS_PCH_CPT(dev))
+               *pipe = PORT_TO_PIPE_CPT(tmp);
+       else
+               *pipe = PORT_TO_PIPE(tmp);
+       return true;
+ }
+ static void intel_disable_sdvo(struct intel_encoder *encoder)
+ {
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+       u32 temp;
+       intel_sdvo_set_active_outputs(intel_sdvo, 0);
+       if (0)
+               intel_sdvo_set_encoder_power_state(intel_sdvo,
+                                                  DRM_MODE_DPMS_OFF);
+       temp = I915_READ(intel_sdvo->sdvo_reg);
+       if ((temp & SDVO_ENABLE) != 0) {
+               intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE);
+       }
+ }
+ static void intel_enable_sdvo(struct intel_encoder *encoder)
+ {
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
        u32 temp;
+       bool input1, input2;
+       int i;
+       u8 status;
+       temp = I915_READ(intel_sdvo->sdvo_reg);
+       if ((temp & SDVO_ENABLE) == 0)
+               intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE);
+       for (i = 0; i < 2; i++)
+               intel_wait_for_vblank(dev, intel_crtc->pipe);
+       status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
+       /* Warn if the device reported failure to sync.
+        * A lot of SDVO devices fail to notify of sync, but it's
+        * a given it the status is a success, we succeeded.
+        */
+       if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
+               DRM_DEBUG_KMS("First %s output reported failure to "
+                               "sync\n", SDVO_NAME(intel_sdvo));
+       }
+       if (0)
+               intel_sdvo_set_encoder_power_state(intel_sdvo,
+                                                  DRM_MODE_DPMS_ON);
+       intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
+ }
+ static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
+ {
+       struct drm_crtc *crtc;
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+       /* dvo supports only 2 dpms states. */
+       if (mode != DRM_MODE_DPMS_ON)
+               mode = DRM_MODE_DPMS_OFF;
+       if (mode == connector->dpms)
+               return;
+       connector->dpms = mode;
+       /* Only need to change hw state when actually enabled */
+       crtc = intel_sdvo->base.base.crtc;
+       if (!crtc) {
+               intel_sdvo->base.connectors_active = false;
+               return;
+       }
  
        if (mode != DRM_MODE_DPMS_ON) {
                intel_sdvo_set_active_outputs(intel_sdvo, 0);
                if (0)
                        intel_sdvo_set_encoder_power_state(intel_sdvo, mode);
  
-               if (mode == DRM_MODE_DPMS_OFF) {
-                       temp = I915_READ(intel_sdvo->sdvo_reg);
-                       if ((temp & SDVO_ENABLE) != 0) {
-                               intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE);
-                       }
-               }
+               intel_sdvo->base.connectors_active = false;
+               intel_crtc_update_dpms(crtc);
        } else {
-               bool input1, input2;
-               int i;
-               u8 status;
-               temp = I915_READ(intel_sdvo->sdvo_reg);
-               if ((temp & SDVO_ENABLE) == 0)
-                       intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE);
-               for (i = 0; i < 2; i++)
-                       intel_wait_for_vblank(dev, intel_crtc->pipe);
-               status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
-               /* Warn if the device reported failure to sync.
-                * A lot of SDVO devices fail to notify of sync, but it's
-                * a given it the status is a success, we succeeded.
-                */
-               if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
-                       DRM_DEBUG_KMS("First %s output reported failure to "
-                                       "sync\n", SDVO_NAME(intel_sdvo));
-               }
+               intel_sdvo->base.connectors_active = true;
+               intel_crtc_update_dpms(crtc);
  
                if (0)
                        intel_sdvo_set_encoder_power_state(intel_sdvo, mode);
                intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
        }
-       return;
+       intel_modeset_check_state(connector->dev);
  }
  
  static int intel_sdvo_mode_valid(struct drm_connector *connector,
@@@ -1250,25 -1340,29 +1339,29 @@@ static bool intel_sdvo_get_capabilities
        return true;
  }
  
- static int intel_sdvo_supports_hotplug(struct intel_sdvo *intel_sdvo)
+ static uint16_t intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo)
  {
        struct drm_device *dev = intel_sdvo->base.base.dev;
-       u8 response[2];
+       uint16_t hotplug;
  
        /* HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise
         * on the line. */
        if (IS_I945G(dev) || IS_I945GM(dev))
-               return false;
+               return 0;
  
-       return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,
-                                   &response, 2) && response[0];
+       if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,
+                                       &hotplug, sizeof(hotplug)))
+               return 0;
+       return hotplug;
  }
  
  static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder)
  {
        struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
  
-       intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &intel_sdvo->hotplug_active, 2);
+       intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG,
+                       &intel_sdvo->hotplug_active, 2);
  }
  
  static bool
@@@ -1344,7 -1438,6 +1437,6 @@@ intel_sdvo_tmds_sink_detect(struct drm_
                        }
                } else
                        status = connector_status_disconnected;
-               connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
  
@@@ -1418,7 -1511,6 +1510,6 @@@ intel_sdvo_detect(struct drm_connector 
                        else
                                ret = connector_status_disconnected;
  
-                       connector->display_info.raw_edid = NULL;
                        kfree(edid);
                } else
                        ret = connector_status_connected;
@@@ -1464,7 -1556,6 +1555,6 @@@ static void intel_sdvo_get_ddc_modes(st
                        drm_add_edid_modes(connector, edid);
                }
  
-               connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
  }
@@@ -1836,8 -1927,8 +1926,8 @@@ set_value
  done:
        if (intel_sdvo->base.base.crtc) {
                struct drm_crtc *crtc = intel_sdvo->base.base.crtc;
-               drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
-                                        crtc->y, crtc->fb);
+               intel_set_mode(crtc, &crtc->mode,
+                              crtc->x, crtc->y, crtc->fb);
        }
  
        return 0;
  }
  
  static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
-       .dpms = intel_sdvo_dpms,
        .mode_fixup = intel_sdvo_mode_fixup,
-       .prepare = intel_encoder_prepare,
        .mode_set = intel_sdvo_mode_set,
-       .commit = intel_encoder_commit,
+       .disable = intel_encoder_noop,
  };
  
  static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = intel_sdvo_dpms,
        .detect = intel_sdvo_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_sdvo_set_property,
@@@ -2025,6 -2114,7 +2113,7 @@@ intel_sdvo_connector_init(struct intel_
        connector->base.base.interlace_allowed = 1;
        connector->base.base.doublescan_allowed = 0;
        connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
+       connector->base.get_hw_state = intel_sdvo_connector_get_hw_state;
  
        intel_connector_attach_encoder(&connector->base, &encoder->base);
        drm_sysfs_connector_add(&connector->base.base);
@@@ -2063,17 -2153,18 +2152,18 @@@ intel_sdvo_dvi_init(struct intel_sdvo *
  
        intel_connector = &intel_sdvo_connector->base;
        connector = &intel_connector->base;
-       if (intel_sdvo_supports_hotplug(intel_sdvo) & (1 << device)) {
+       if (intel_sdvo_get_hotplug_support(intel_sdvo) &
+               intel_sdvo_connector->output_flag) {
                connector->polled = DRM_CONNECTOR_POLL_HPD;
-               intel_sdvo->hotplug_active[0] |= 1 << device;
+               intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag;
                /* Some SDVO devices have one-shot hotplug interrupts.
                 * Ensure that they get re-enabled when an interrupt happens.
                 */
                intel_encoder->hot_plug = intel_sdvo_enable_hotplug;
                intel_sdvo_enable_hotplug(intel_encoder);
-       }
-       else
+       } else {
                connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
+       }
        encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
        connector->connector_type = DRM_MODE_CONNECTOR_DVID;
  
                connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
                intel_sdvo->is_hdmi = true;
        }
-       intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
-                                      (1 << INTEL_ANALOG_CLONE_BIT));
+       intel_sdvo->base.cloneable = true;
  
        intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
        if (intel_sdvo->is_hdmi)
@@@ -2113,7 -2203,7 +2202,7 @@@ intel_sdvo_tv_init(struct intel_sdvo *i
  
        intel_sdvo->is_tv = true;
        intel_sdvo->base.needs_tv_clock = true;
-       intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
+       intel_sdvo->base.cloneable = false;
  
        intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
  
@@@ -2156,8 -2246,7 +2245,7 @@@ intel_sdvo_analog_init(struct intel_sdv
                intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
        }
  
-       intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
-                                      (1 << INTEL_ANALOG_CLONE_BIT));
+       intel_sdvo->base.cloneable = true;
  
        intel_sdvo_connector_init(intel_sdvo_connector,
                                  intel_sdvo);
@@@ -2189,8 -2278,10 +2277,10 @@@ intel_sdvo_lvds_init(struct intel_sdvo 
                intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
        }
  
-       intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) |
-                                      (1 << INTEL_SDVO_LVDS_CLONE_BIT));
+       /* SDVO LVDS is cloneable because the SDVO encoder does the upscaling,
+        * as opposed to native LVDS, where we upscale with the panel-fitter
+        * (and hence only the native LVDS resolution could be cloned). */
+       intel_sdvo->base.cloneable = true;
  
        intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
        if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
@@@ -2575,6 -2666,10 +2665,10 @@@ bool intel_sdvo_init(struct drm_device 
  
        drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
  
+       intel_encoder->disable = intel_disable_sdvo;
+       intel_encoder->enable = intel_enable_sdvo;
+       intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
        /* In default case sdvo lvds is false */
        if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
                goto err;
        /* Only enable the hotplug irq if we need it, to work around noisy
         * hotplug lines.
         */
-       if (intel_sdvo->hotplug_active[0])
+       if (intel_sdvo->hotplug_active)
                dev_priv->hotplug_supported_mask |= hotplug_mask;
  
        intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
   * Integrated TV-out support for the 915GM and 945GM.
   */
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 -#include "drm_edid.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_edid.h>
  #include "intel_drv.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  
  enum tv_margin {
@@@ -835,22 -836,37 +835,37 @@@ static struct intel_tv *intel_attached_
                            base);
  }
  
+ static bool
+ intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
+ {
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 tmp = I915_READ(TV_CTL);
+       if (!(tmp & TV_ENC_ENABLE))
+               return false;
+       *pipe = PORT_TO_PIPE(tmp);
+       return true;
+ }
  static void
- intel_tv_dpms(struct drm_encoder *encoder, int mode)
+ intel_enable_tv(struct intel_encoder *encoder)
  {
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
  
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-       case DRM_MODE_DPMS_OFF:
-               I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
-               break;
-       }
+       I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
+ }
+ static void
+ intel_disable_tv(struct intel_encoder *encoder)
+ {
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
  }
  
  static const struct tv_mode *
@@@ -894,17 -910,14 +909,14 @@@ intel_tv_mode_fixup(struct drm_encoder 
                    const struct drm_display_mode *mode,
                    struct drm_display_mode *adjusted_mode)
  {
-       struct drm_device *dev = encoder->dev;
        struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
-       struct intel_encoder *other_encoder;
  
        if (!tv_mode)
                return false;
  
-       for_each_encoder_on_crtc(dev, encoder->crtc, other_encoder)
-               if (&other_encoder->base != encoder)
-                       return false;
+       if (intel_encoder_check_is_cloned(&intel_tv->base))
+               return false;
  
        adjusted_mode->clock = tv_mode->clock;
        return true;
@@@ -1302,12 -1315,9 +1314,9 @@@ intel_tv_detect(struct drm_connector *c
        if (force) {
                struct intel_load_detect_pipe tmp;
  
-               if (intel_get_load_detect_pipe(&intel_tv->base, connector,
-                                              &mode, &tmp)) {
+               if (intel_get_load_detect_pipe(connector, &mode, &tmp)) {
                        type = intel_tv_detect_type(intel_tv, connector);
-                       intel_release_load_detect_pipe(&intel_tv->base,
-                                                      connector,
-                                                      &tmp);
+                       intel_release_load_detect_pipe(connector, &tmp);
                } else
                        return connector_status_unknown;
        } else
@@@ -1473,22 -1483,20 +1482,20 @@@ intel_tv_set_property(struct drm_connec
        }
  
        if (changed && crtc)
-               drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
-                               crtc->y, crtc->fb);
+               intel_set_mode(crtc, &crtc->mode,
+                              crtc->x, crtc->y, crtc->fb);
  out:
        return ret;
  }
  
  static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
-       .dpms = intel_tv_dpms,
        .mode_fixup = intel_tv_mode_fixup,
-       .prepare = intel_encoder_prepare,
        .mode_set = intel_tv_mode_set,
-       .commit = intel_encoder_commit,
+       .disable = intel_encoder_noop,
  };
  
  static const struct drm_connector_funcs intel_tv_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = intel_connector_dpms,
        .detect = intel_tv_detect,
        .destroy = intel_tv_destroy,
        .set_property = intel_tv_set_property,
@@@ -1618,10 -1626,15 +1625,15 @@@ intel_tv_init(struct drm_device *dev
        drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
                         DRM_MODE_ENCODER_TVDAC);
  
+       intel_encoder->enable = intel_enable_tv;
+       intel_encoder->disable = intel_disable_tv;
+       intel_encoder->get_hw_state = intel_tv_get_hw_state;
+       intel_connector->get_hw_state = intel_connector_get_hw_state;
        intel_connector_attach_encoder(intel_connector, intel_encoder);
        intel_encoder->type = INTEL_OUTPUT_TVOUT;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
-       intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT);
+       intel_encoder->cloneable = false;
        intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
        intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
        intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
  
  #include <video/vga.h>
  
 -#include "drm/drm_fb_helper.h"
 -#include "ttm/ttm_bo_api.h"
 -#include "ttm/ttm_bo_driver.h"
 -#include "ttm/ttm_placement.h"
 -#include "ttm/ttm_memory.h"
 -#include "ttm/ttm_module.h"
 +#include <drm/drm_fb_helper.h>
 +#include <drm/ttm/ttm_bo_api.h>
 +#include <drm/ttm/ttm_bo_driver.h>
 +#include <drm/ttm/ttm_placement.h>
 +#include <drm/ttm/ttm_memory.h>
 +#include <drm/ttm/ttm_module.h>
  
  #include <linux/i2c.h>
  #include <linux/i2c-algo-bit.h>
@@@ -195,7 -195,6 +195,6 @@@ struct mga_device 
                struct drm_global_reference mem_global_ref;
                struct ttm_bo_global_ref bo_global_ref;
                struct ttm_bo_device bdev;
-               atomic_t validate_sequence;
        } ttm;
  
        u32 reg_1e24; /* SE model number */
@@@ -13,8 -13,9 +13,8 @@@
  
  #include <linux/delay.h>
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
  
  #include "mgag200_drv.h"
  
@@@ -1398,7 -1399,6 +1398,6 @@@ static int mga_vga_get_modes(struct drm
        if (edid) {
                drm_mode_connector_update_edid_property(connector, edid);
                ret = drm_add_edid_modes(connector, edid);
-               connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
        return ret;
index 0000000,abb135f..acf818c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,271 +1,271 @@@
 -                      flush_work_sync(&isr->work);
+ /*
+  * Copyright 2011 Red Hat Inc.
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+  * copy of this software and associated documentation files (the "Software"),
+  * to deal in the Software without restriction, including without limitation
+  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+  * and/or sell copies of the Software, and to permit persons to whom the
+  * Software is furnished to do so, subject to the following conditions:
+  *
+  * The above copyright notice and this permission notice shall be included in
+  * all copies or substantial portions of the Software.
+  *
+  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  * OTHER DEALINGS IN THE SOFTWARE.
+  *
+  * Authors: Ben Skeggs
+  */
+ #include <subdev/gpio.h>
+ #include <subdev/bios.h>
+ #include <subdev/bios/gpio.h>
+ static int
+ nouveau_gpio_drive(struct nouveau_gpio *gpio,
+                  int idx, int line, int dir, int out)
+ {
+       return gpio->drive ? gpio->drive(gpio, line, dir, out) : -ENODEV;
+ }
+ static int
+ nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line)
+ {
+       return gpio->sense ? gpio->sense(gpio, line) : -ENODEV;
+ }
+ static int
+ nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
+                 struct dcb_gpio_func *func)
+ {
+       if (line == 0xff && tag == 0xff)
+               return -EINVAL;
+       if (!dcb_gpio_parse(nouveau_bios(gpio), idx, tag, line, func))
+               return 0;
+       /* Apple iMac G4 NV18 */
+       if (nv_device_match(nv_object(gpio), 0x0189, 0x10de, 0x0010)) {
+               if (tag == DCB_GPIO_TVDAC0) {
+                       *func = (struct dcb_gpio_func) {
+                               .func = DCB_GPIO_TVDAC0,
+                               .line = 4,
+                               .log[0] = 0,
+                               .log[1] = 1,
+                       };
+                       return 0;
+               }
+       }
+       return -EINVAL;
+ }
+ static int
+ nouveau_gpio_set(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, int state)
+ {
+       struct dcb_gpio_func func;
+       int ret;
+       ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
+       if (ret == 0) {
+               int dir = !!(func.log[state] & 0x02);
+               int out = !!(func.log[state] & 0x01);
+               ret = nouveau_gpio_drive(gpio, idx, func.line, dir, out);
+       }
+       return ret;
+ }
+ static int
+ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line)
+ {
+       struct dcb_gpio_func func;
+       int ret;
+       ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
+       if (ret == 0) {
+               ret = nouveau_gpio_sense(gpio, idx, func.line);
+               if (ret >= 0)
+                       ret = (ret == (func.log[1] & 1));
+       }
+       return ret;
+ }
+ static int
+ nouveau_gpio_irq(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, bool on)
+ {
+       struct dcb_gpio_func func;
+       int ret;
+       ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
+       if (ret == 0) {
+               if (idx == 0 && gpio->irq_enable)
+                       gpio->irq_enable(gpio, func.line, on);
+               else
+                       ret = -ENODEV;
+       }
+       return ret;
+ }
+ struct gpio_isr {
+       struct nouveau_gpio *gpio;
+       struct list_head head;
+       struct work_struct work;
+       int idx;
+       struct dcb_gpio_func func;
+       void (*handler)(void *, int);
+       void *data;
+       bool inhibit;
+ };
+ static void
+ nouveau_gpio_isr_bh(struct work_struct *work)
+ {
+       struct gpio_isr *isr = container_of(work, struct gpio_isr, work);
+       struct nouveau_gpio *gpio = isr->gpio;
+       unsigned long flags;
+       int state;
+       state = nouveau_gpio_get(gpio, isr->idx, isr->func.func,
+                                                isr->func.line);
+       if (state >= 0)
+               isr->handler(isr->data, state);
+       spin_lock_irqsave(&gpio->lock, flags);
+       isr->inhibit = false;
+       spin_unlock_irqrestore(&gpio->lock, flags);
+ }
+ static void
+ nouveau_gpio_isr_run(struct nouveau_gpio *gpio, int idx, u32 line_mask)
+ {
+       struct gpio_isr *isr;
+       if (idx != 0)
+               return;
+       spin_lock(&gpio->lock);
+       list_for_each_entry(isr, &gpio->isr, head) {
+               if (line_mask & (1 << isr->func.line)) {
+                       if (isr->inhibit)
+                               continue;
+                       isr->inhibit = true;
+                       schedule_work(&isr->work);
+               }
+       }
+       spin_unlock(&gpio->lock);
+ }
+ static int
+ nouveau_gpio_isr_add(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
+                    void (*handler)(void *, int), void *data)
+ {
+       struct gpio_isr *isr;
+       unsigned long flags;
+       int ret;
+       isr = kzalloc(sizeof(*isr), GFP_KERNEL);
+       if (!isr)
+               return -ENOMEM;
+       ret = nouveau_gpio_find(gpio, idx, tag, line, &isr->func);
+       if (ret) {
+               kfree(isr);
+               return ret;
+       }
+       INIT_WORK(&isr->work, nouveau_gpio_isr_bh);
+       isr->gpio = gpio;
+       isr->handler = handler;
+       isr->data = data;
+       isr->idx = idx;
+       spin_lock_irqsave(&gpio->lock, flags);
+       list_add(&isr->head, &gpio->isr);
+       spin_unlock_irqrestore(&gpio->lock, flags);
+       return 0;
+ }
+ static void
+ nouveau_gpio_isr_del(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
+                    void (*handler)(void *, int), void *data)
+ {
+       struct gpio_isr *isr, *tmp;
+       struct dcb_gpio_func func;
+       unsigned long flags;
+       LIST_HEAD(tofree);
+       int ret;
+       ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
+       if (ret == 0) {
+               spin_lock_irqsave(&gpio->lock, flags);
+               list_for_each_entry_safe(isr, tmp, &gpio->isr, head) {
+                       if (memcmp(&isr->func, &func, sizeof(func)) ||
+                           isr->idx != idx ||
+                           isr->handler != handler || isr->data != data)
+                               continue;
+                       list_move_tail(&isr->head, &tofree);
+               }
+               spin_unlock_irqrestore(&gpio->lock, flags);
+               list_for_each_entry_safe(isr, tmp, &tofree, head) {
++                      flush_work(&isr->work);
+                       kfree(isr);
+               }
+       }
+ }
+ int
+ nouveau_gpio_create_(struct nouveau_object *parent,
+                    struct nouveau_object *engine,
+                    struct nouveau_oclass *oclass, int length, void **pobject)
+ {
+       struct nouveau_gpio *gpio;
+       int ret;
+       ret = nouveau_subdev_create_(parent, engine, oclass, 0, "GPIO", "gpio",
+                                    length, pobject);
+       gpio = *pobject;
+       if (ret)
+               return ret;
+       gpio->find = nouveau_gpio_find;
+       gpio->set  = nouveau_gpio_set;
+       gpio->get  = nouveau_gpio_get;
+       gpio->irq  = nouveau_gpio_irq;
+       gpio->isr_run = nouveau_gpio_isr_run;
+       gpio->isr_add = nouveau_gpio_isr_add;
+       gpio->isr_del = nouveau_gpio_isr_del;
+       INIT_LIST_HEAD(&gpio->isr);
+       spin_lock_init(&gpio->lock);
+       return 0;
+ }
+ static struct dmi_system_id gpio_reset_ids[] = {
+       {
+               .ident = "Apple Macbook 10,1",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
+               }
+       },
+       { }
+ };
+ int
+ nouveau_gpio_init(struct nouveau_gpio *gpio)
+ {
+       int ret = nouveau_subdev_init(&gpio->base);
+       if (ret == 0 && gpio->reset) {
+               if (dmi_check_system(gpio_reset_ids))
+                       gpio->reset(gpio);
+       }
+       return ret;
+ }
@@@ -7,15 -7,13 +7,13 @@@
  #include <acpi/acpi.h>
  #include <linux/mxm-wmi.h>
  
- #include <drm/drmP.h>
- #include <drm/drm_crtc_helper.h>
- #include "nouveau_drv.h"
- #include <drm/nouveau_drm.h>
- #include "nv50_display.h"
- #include "nouveau_connector.h"
  #include <linux/vga_switcheroo.h>
  
 -#include "drm_edid.h"
++#include <drm/drm_edid.h>
+ #include "nouveau_drm.h"
+ #include "nouveau_acpi.h"
  #define NOUVEAU_DSM_LED 0x02
  #define NOUVEAU_DSM_LED_STATE 0x00
  #define NOUVEAU_DSM_LED_OFF 0x10
@@@ -388,10 -386,9 +386,9 @@@ int nouveau_acpi_get_bios_chunk(uint8_
        return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len);
  }
  
- int
+ void *
  nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
  {
-       struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct acpi_device *acpidev;
        acpi_handle handle;
        int type, ret;
                type = ACPI_VIDEO_DISPLAY_LCD;
                break;
        default:
-               return -EINVAL;
+               return NULL;
        }
  
        handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
        if (!handle)
-               return -ENODEV;
+               return NULL;
  
        ret = acpi_bus_get_device(handle, &acpidev);
        if (ret)
-               return -ENODEV;
+               return NULL;
  
        ret = acpi_video_get_edid(acpidev, type, -1, &edid);
        if (ret < 0)
-               return ret;
+               return NULL;
  
-       nv_connector->edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
-       return 0;
+       return kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
  }
   * SOFTWARE.
   */
  
- #include <drm/drmP.h>
- #define NV_DEBUG_NOTRACE
- #include "nouveau_drv.h"
- #include "nouveau_hw.h"
- #include "nouveau_encoder.h"
- #include "nouveau_gpio.h"
- #include <linux/io-mapping.h>
- #include <linux/firmware.h>
- /* these defines are made up */
- #define NV_CIO_CRE_44_HEADA 0x0
- #define NV_CIO_CRE_44_HEADB 0x3
- #define FEATURE_MOBILE 0x10   /* also FEATURE_QUADRO for BMP */
- #define EDID1_LEN 128
- #define BIOSLOG(sip, fmt, arg...) NV_DEBUG(sip->dev, fmt, ##arg)
- #define LOG_OLD_VALUE(x)
- struct init_exec {
-       bool execute;
-       bool repeat;
- };
- static bool nv_cksum(const uint8_t *data, unsigned int length)
- {
-       /*
-        * There's a few checksums in the BIOS, so here's a generic checking
-        * function.
-        */
-       int i;
-       uint8_t sum = 0;
-       for (i = 0; i < length; i++)
-               sum += data[i];
-       if (sum)
-               return true;
-       return false;
- }
- static int
- score_vbios(struct nvbios *bios, const bool writeable)
- {
-       if (!bios->data || bios->data[0] != 0x55 || bios->data[1] != 0xAA) {
-               NV_TRACEWARN(bios->dev, "... BIOS signature not found\n");
-               return 0;
-       }
-       if (nv_cksum(bios->data, bios->data[2] * 512)) {
-               NV_TRACEWARN(bios->dev, "... BIOS checksum invalid\n");
-               /* if a ro image is somewhat bad, it's probably all rubbish */
-               return writeable ? 2 : 1;
-       }
-       NV_TRACE(bios->dev, "... appears to be valid\n");
-       return 3;
- }
- static void
- bios_shadow_prom(struct nvbios *bios)
- {
-       struct drm_device *dev = bios->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       u32 pcireg, access;
-       u16 pcir;
-       int i;
-       /* enable access to rom */
-       if (dev_priv->card_type >= NV_50)
-               pcireg = 0x088050;
-       else
-               pcireg = NV_PBUS_PCI_NV_20;
-       access = nv_mask(dev, pcireg, 0x00000001, 0x00000000);
-       /* bail if no rom signature, with a workaround for a PROM reading
-        * issue on some chipsets.  the first read after a period of
-        * inactivity returns the wrong result, so retry the first header
-        * byte a few times before giving up as a workaround
-        */
-       i = 16;
-       do {
-               if (nv_rd08(dev, NV_PROM_OFFSET + 0) == 0x55)
-                       break;
-       } while (i--);
-       if (!i || nv_rd08(dev, NV_PROM_OFFSET + 1) != 0xaa)
-               goto out;
-       /* additional check (see note below) - read PCI record header */
-       pcir = nv_rd08(dev, NV_PROM_OFFSET + 0x18) |
-              nv_rd08(dev, NV_PROM_OFFSET + 0x19) << 8;
-       if (nv_rd08(dev, NV_PROM_OFFSET + pcir + 0) != 'P' ||
-           nv_rd08(dev, NV_PROM_OFFSET + pcir + 1) != 'C' ||
-           nv_rd08(dev, NV_PROM_OFFSET + pcir + 2) != 'I' ||
-           nv_rd08(dev, NV_PROM_OFFSET + pcir + 3) != 'R')
-               goto out;
-       /* read entire bios image to system memory */
-       bios->length = nv_rd08(dev, NV_PROM_OFFSET + 2) * 512;
-       bios->data = kmalloc(bios->length, GFP_KERNEL);
-       if (bios->data) {
-               for (i = 0; i < bios->length; i++)
-                       bios->data[i] = nv_rd08(dev, NV_PROM_OFFSET + i);
-       }
- out:
-       /* disable access to rom */
-       nv_wr32(dev, pcireg, access);
- }
- static void
- bios_shadow_pramin(struct nvbios *bios)
- {
-       struct drm_device *dev = bios->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       u32 bar0 = 0;
-       int i;
-       if (dev_priv->card_type >= NV_50) {
-               u64 addr = (u64)(nv_rd32(dev, 0x619f04) & 0xffffff00) << 8;
-               if (!addr) {
-                       addr  = (u64)nv_rd32(dev, 0x001700) << 16;
-                       addr += 0xf0000;
-               }
-               bar0 = nv_mask(dev, 0x001700, 0xffffffff, addr >> 16);
-       }
-       /* bail if no rom signature */
-       if (nv_rd08(dev, NV_PRAMIN_OFFSET + 0) != 0x55 ||
-           nv_rd08(dev, NV_PRAMIN_OFFSET + 1) != 0xaa)
-               goto out;
-       bios->length = nv_rd08(dev, NV_PRAMIN_OFFSET + 2) * 512;
-       bios->data = kmalloc(bios->length, GFP_KERNEL);
-       if (bios->data) {
-               for (i = 0; i < bios->length; i++)
-                       bios->data[i] = nv_rd08(dev, NV_PRAMIN_OFFSET + i);
-       }
- out:
-       if (dev_priv->card_type >= NV_50)
-               nv_wr32(dev, 0x001700, bar0);
- }
- static void
- bios_shadow_pci(struct nvbios *bios)
- {
-       struct pci_dev *pdev = bios->dev->pdev;
-       size_t length;
-       if (!pci_enable_rom(pdev)) {
-               void __iomem *rom = pci_map_rom(pdev, &length);
-               if (rom && length) {
-                       bios->data = kmalloc(length, GFP_KERNEL);
-                       if (bios->data) {
-                               memcpy_fromio(bios->data, rom, length);
-                               bios->length = length;
-                       }
-               }
-               if (rom)
-                       pci_unmap_rom(pdev, rom);
-               pci_disable_rom(pdev);
-       }
- }
- static void
- bios_shadow_acpi(struct nvbios *bios)
- {
-       struct pci_dev *pdev = bios->dev->pdev;
-       int cnt = 65536 / ROM_BIOS_PAGE;
-       int ret;
-       if (!nouveau_acpi_rom_supported(pdev))
-               return;
-       bios->data = kmalloc(cnt * ROM_BIOS_PAGE, GFP_KERNEL);
-       if (!bios->data)
-               return;
-       bios->length = 0;
-       while (cnt--) {
-               ret = nouveau_acpi_get_bios_chunk(bios->data, bios->length,
-                                                 ROM_BIOS_PAGE);
-               if (ret != ROM_BIOS_PAGE)
-                       return;
-               bios->length += ROM_BIOS_PAGE;
-       }
- }
- struct methods {
-       const char desc[8];
-       void (*shadow)(struct nvbios *);
-       const bool rw;
-       int score;
-       u32 size;
-       u8 *data;
- };
- static bool
- bios_shadow(struct drm_device *dev)
- {
-       struct methods shadow_methods[] = {
-               { "PRAMIN", bios_shadow_pramin, true, 0, 0, NULL },
-               { "PROM", bios_shadow_prom, false, 0, 0, NULL },
-               { "ACPI", bios_shadow_acpi, true, 0, 0, NULL },
-               { "PCIROM", bios_shadow_pci, true, 0, 0, NULL },
-               {}
-       };
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
-       struct methods *mthd, *best;
-       const struct firmware *fw;
-       char fname[32];
-       int ret;
-       if (nouveau_vbios) {
-               /* try to match one of the built-in methods */
-               mthd = shadow_methods;
-               do {
-                       if (strcasecmp(nouveau_vbios, mthd->desc))
-                               continue;
-                       NV_INFO(dev, "VBIOS source: %s\n", mthd->desc);
-                       mthd->shadow(bios);
-                       mthd->score = score_vbios(bios, mthd->rw);
-                       if (mthd->score)
-                               return true;
-               } while ((++mthd)->shadow);
-               /* attempt to load firmware image */
-               snprintf(fname, sizeof(fname), "nouveau/%s", nouveau_vbios);
-               ret = request_firmware(&fw, fname, &dev->pdev->dev);
-               if (ret == 0) {
-                       bios->length = fw->size;
-                       bios->data   = kmemdup(fw->data, fw->size, GFP_KERNEL);
-                       release_firmware(fw);
-                       NV_INFO(dev, "VBIOS image: %s\n", nouveau_vbios);
-                       if (score_vbios(bios, 1))
-                               return true;
-                       kfree(bios->data);
-                       bios->data = NULL;
-               }
-               NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios);
-       }
-       mthd = shadow_methods;
-       do {
-               NV_TRACE(dev, "Checking %s for VBIOS\n", mthd->desc);
-               mthd->shadow(bios);
-               mthd->score = score_vbios(bios, mthd->rw);
-               mthd->size = bios->length;
-               mthd->data = bios->data;
-               bios->data = NULL;
-       } while (mthd->score != 3 && (++mthd)->shadow);
-       mthd = shadow_methods;
-       best = mthd;
-       do {
-               if (mthd->score > best->score) {
-                       kfree(best->data);
-                       best = mthd;
-               }
-       } while ((++mthd)->shadow);
-       if (best->score) {
-               NV_TRACE(dev, "Using VBIOS from %s\n", best->desc);
-               bios->length = best->size;
-               bios->data = best->data;
-               return true;
-       }
-       NV_ERROR(dev, "No valid VBIOS image found\n");
-       return false;
- }
- struct init_tbl_entry {
-       char *name;
-       uint8_t id;
-       /* Return:
-        *  > 0: success, length of opcode
-        *    0: success, but abort further parsing of table (INIT_DONE etc)
-        *  < 0: failure, table parsing will be aborted
-        */
-       int (*handler)(struct nvbios *, uint16_t, struct init_exec *);
- };
- static int parse_init_table(struct nvbios *, uint16_t, struct init_exec *);
- #define MACRO_INDEX_SIZE      2
- #define MACRO_SIZE            8
- #define CONDITION_SIZE                12
- #define IO_FLAG_CONDITION_SIZE        9
- #define IO_CONDITION_SIZE     5
- #define MEM_INIT_SIZE         66
- static void still_alive(void)
- {
- #if 0
-       sync();
-       mdelay(2);
- #endif
- }
- static uint32_t
- munge_reg(struct nvbios *bios, uint32_t reg)
- {
-       struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
-       struct dcb_entry *dcbent = bios->display.output;
-       if (dev_priv->card_type < NV_50)
-               return reg;
-       if (reg & 0x80000000) {
-               BUG_ON(bios->display.crtc < 0);
-               reg += bios->display.crtc * 0x800;
-       }
-       if (reg & 0x40000000) {
-               BUG_ON(!dcbent);
-               reg += (ffs(dcbent->or) - 1) * 0x800;
-               if ((reg & 0x20000000) && !(dcbent->sorconf.link & 1))
-                       reg += 0x00000080;
-       }
-       reg &= ~0xe0000000;
-       return reg;
- }
- static int
- valid_reg(struct nvbios *bios, uint32_t reg)
- {
-       struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
-       struct drm_device *dev = bios->dev;
-       /* C51 has misaligned regs on purpose. Marvellous */
-       if (reg & 0x2 ||
-           (reg & 0x1 && dev_priv->vbios.chip_version != 0x51))
-               NV_ERROR(dev, "======= misaligned reg 0x%08X =======\n", reg);
-       /* warn on C51 regs that haven't been verified accessible in tracing */
-       if (reg & 0x1 && dev_priv->vbios.chip_version == 0x51 &&
-           reg != 0x130d && reg != 0x1311 && reg != 0x60081d)
-               NV_WARN(dev, "=== C51 misaligned reg 0x%08X not verified ===\n",
-                       reg);
-       if (reg >= (8*1024*1024)) {
-               NV_ERROR(dev, "=== reg 0x%08x out of mapped bounds ===\n", reg);
-               return 0;
-       }
-       return 1;
- }
- static bool
- valid_idx_port(struct nvbios *bios, uint16_t port)
- {
-       struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
-       struct drm_device *dev = bios->dev;
-       /*
-        * If adding more ports here, the read/write functions below will need
-        * updating so that the correct mmio range (PRMCIO, PRMDIO, PRMVIO) is
-        * used for the port in question
-        */
-       if (dev_priv->card_type < NV_50) {
-               if (port == NV_CIO_CRX__COLOR)
-                       return true;
-               if (port == NV_VIO_SRX)
-                       return true;
-       } else {
-               if (port == NV_CIO_CRX__COLOR)
-                       return true;
-       }
-       NV_ERROR(dev, "========== unknown indexed io port 0x%04X ==========\n",
-                port);
-       return false;
- }
- static bool
- valid_port(struct nvbios *bios, uint16_t port)
- {
-       struct drm_device *dev = bios->dev;
-       /*
-        * If adding more ports here, the read/write functions below will need
-        * updating so that the correct mmio range (PRMCIO, PRMDIO, PRMVIO) is
-        * used for the port in question
-        */
-       if (port == NV_VIO_VSE2)
-               return true;
-       NV_ERROR(dev, "========== unknown io port 0x%04X ==========\n", port);
-       return false;
- }
- static uint32_t
- bios_rd32(struct nvbios *bios, uint32_t reg)
- {
-       uint32_t data;
-       reg = munge_reg(bios, reg);
-       if (!valid_reg(bios, reg))
-               return 0;
-       /*
-        * C51 sometimes uses regs with bit0 set in the address. For these
-        * cases there should exist a translation in a BIOS table to an IO
-        * port address which the BIOS uses for accessing the reg
-        *
-        * These only seem to appear for the power control regs to a flat panel,
-        * and the GPIO regs at 0x60081*.  In C51 mmio traces the normal regs
-        * for 0x1308 and 0x1310 are used - hence the mask below.  An S3
-        * suspend-resume mmio trace from a C51 will be required to see if this
-        * is true for the power microcode in 0x14.., or whether the direct IO
-        * port access method is needed
-        */
-       if (reg & 0x1)
-               reg &= ~0x1;
-       data = nv_rd32(bios->dev, reg);
-       BIOSLOG(bios, " Read:  Reg: 0x%08X, Data: 0x%08X\n", reg, data);
-       return data;
- }
- static void
- bios_wr32(struct nvbios *bios, uint32_t reg, uint32_t data)
- {
-       struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
-       reg = munge_reg(bios, reg);
-       if (!valid_reg(bios, reg))
-               return;
-       /* see note in bios_rd32 */
-       if (reg & 0x1)
-               reg &= 0xfffffffe;
-       LOG_OLD_VALUE(bios_rd32(bios, reg));
-       BIOSLOG(bios, " Write: Reg: 0x%08X, Data: 0x%08X\n", reg, data);
-       if (dev_priv->vbios.execute) {
-               still_alive();
-               nv_wr32(bios->dev, reg, data);
-       }
- }
- static uint8_t
- bios_idxprt_rd(struct nvbios *bios, uint16_t port, uint8_t index)
- {
-       struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
-       struct drm_device *dev = bios->dev;
-       uint8_t data;
-       if (!valid_idx_port(bios, port))
-               return 0;
-       if (dev_priv->card_type < NV_50) {
-               if (port == NV_VIO_SRX)
-                       data = NVReadVgaSeq(dev, bios->state.crtchead, index);
-               else    /* assume NV_CIO_CRX__COLOR */
-                       data = NVReadVgaCrtc(dev, bios->state.crtchead, index);
-       } else {
-               uint32_t data32;
-               data32 = bios_rd32(bios, NV50_PDISPLAY_VGACRTC(index & ~3));
-               data = (data32 >> ((index & 3) << 3)) & 0xff;
-       }
-       BIOSLOG(bios, " Indexed IO read:  Port: 0x%04X, Index: 0x%02X, "
-                     "Head: 0x%02X, Data: 0x%02X\n",
-               port, index, bios->state.crtchead, data);
-       return data;
- }
- static void
- bios_idxprt_wr(struct nvbios *bios, uint16_t port, uint8_t index, uint8_t data)
- {
-       struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
-       struct drm_device *dev = bios->dev;
-       if (!valid_idx_port(bios, port))
-               return;
-       /*
-        * The current head is maintained in the nvbios member  state.crtchead.
-        * We trap changes to CR44 and update the head variable and hence the
-        * register set written.
-        * As CR44 only exists on CRTC0, we update crtchead to head0 in advance
-        * of the write, and to head1 after the write
-        */
-       if (port == NV_CIO_CRX__COLOR && index == NV_CIO_CRE_44 &&
-           data != NV_CIO_CRE_44_HEADB)
-               bios->state.crtchead = 0;
-       LOG_OLD_VALUE(bios_idxprt_rd(bios, port, index));
-       BIOSLOG(bios, " Indexed IO write: Port: 0x%04X, Index: 0x%02X, "
-                     "Head: 0x%02X, Data: 0x%02X\n",
-               port, index, bios->state.crtchead, data);
-       if (bios->execute && dev_priv->card_type < NV_50) {
-               still_alive();
-               if (port == NV_VIO_SRX)
-                       NVWriteVgaSeq(dev, bios->state.crtchead, index, data);
-               else    /* assume NV_CIO_CRX__COLOR */
-                       NVWriteVgaCrtc(dev, bios->state.crtchead, index, data);
-       } else
-       if (bios->execute) {
-               uint32_t data32, shift = (index & 3) << 3;
-               still_alive();
-               data32  = bios_rd32(bios, NV50_PDISPLAY_VGACRTC(index & ~3));
-               data32 &= ~(0xff << shift);
-               data32 |= (data << shift);
-               bios_wr32(bios, NV50_PDISPLAY_VGACRTC(index & ~3), data32);
-       }
-       if (port == NV_CIO_CRX__COLOR &&
-           index == NV_CIO_CRE_44 && data == NV_CIO_CRE_44_HEADB)
-               bios->state.crtchead = 1;
- }
- static uint8_t
- bios_port_rd(struct nvbios *bios, uint16_t port)
- {
-       uint8_t data, head = bios->state.crtchead;
-       if (!valid_port(bios, port))
-               return 0;
-       data = NVReadPRMVIO(bios->dev, head, NV_PRMVIO0_OFFSET + port);
-       BIOSLOG(bios, " IO read:  Port: 0x%04X, Head: 0x%02X, Data: 0x%02X\n",
-               port, head, data);
-       return data;
- }
- static void
- bios_port_wr(struct nvbios *bios, uint16_t port, uint8_t data)
- {
-       int head = bios->state.crtchead;
-       if (!valid_port(bios, port))
-               return;
-       LOG_OLD_VALUE(bios_port_rd(bios, port));
-       BIOSLOG(bios, " IO write: Port: 0x%04X, Head: 0x%02X, Data: 0x%02X\n",
-               port, head, data);
-       if (!bios->execute)
-               return;
-       still_alive();
-       NVWritePRMVIO(bios->dev, head, NV_PRMVIO0_OFFSET + port, data);
- }
- static bool
- io_flag_condition_met(struct nvbios *bios, uint16_t offset, uint8_t cond)
- {
-       /*
-        * The IO flag condition entry has 2 bytes for the CRTC port; 1 byte
-        * for the CRTC index; 1 byte for the mask to apply to the value
-        * retrieved from the CRTC; 1 byte for the shift right to apply to the
-        * masked CRTC value; 2 bytes for the offset to the flag array, to
-        * which the shifted value is added; 1 byte for the mask applied to the
-        * value read from the flag array; and 1 byte for the value to compare
-        * against the masked byte from the flag table.
-        */
-       uint16_t condptr = bios->io_flag_condition_tbl_ptr + cond * IO_FLAG_CONDITION_SIZE;
-       uint16_t crtcport = ROM16(bios->data[condptr]);
-       uint8_t crtcindex = bios->data[condptr + 2];
-       uint8_t mask = bios->data[condptr + 3];
-       uint8_t shift = bios->data[condptr + 4];
-       uint16_t flagarray = ROM16(bios->data[condptr + 5]);
-       uint8_t flagarraymask = bios->data[condptr + 7];
-       uint8_t cmpval = bios->data[condptr + 8];
-       uint8_t data;
-       BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
-                     "Shift: 0x%02X, FlagArray: 0x%04X, FAMask: 0x%02X, "
-                     "Cmpval: 0x%02X\n",
-               offset, crtcport, crtcindex, mask, shift, flagarray, flagarraymask, cmpval);
-       data = bios_idxprt_rd(bios, crtcport, crtcindex);
-       data = bios->data[flagarray + ((data & mask) >> shift)];
-       data &= flagarraymask;
-       BIOSLOG(bios, "0x%04X: Checking if 0x%02X equals 0x%02X\n",
-               offset, data, cmpval);
-       return (data == cmpval);
- }
- static bool
- bios_condition_met(struct nvbios *bios, uint16_t offset, uint8_t cond)
- {
-       /*
-        * The condition table entry has 4 bytes for the address of the
-        * register to check, 4 bytes for a mask to apply to the register and
-        * 4 for a test comparison value
-        */
-       uint16_t condptr = bios->condition_tbl_ptr + cond * CONDITION_SIZE;
-       uint32_t reg = ROM32(bios->data[condptr]);
-       uint32_t mask = ROM32(bios->data[condptr + 4]);
-       uint32_t cmpval = ROM32(bios->data[condptr + 8]);
-       uint32_t data;
-       BIOSLOG(bios, "0x%04X: Cond: 0x%02X, Reg: 0x%08X, Mask: 0x%08X\n",
-               offset, cond, reg, mask);
-       data = bios_rd32(bios, reg) & mask;
-       BIOSLOG(bios, "0x%04X: Checking if 0x%08X equals 0x%08X\n",
-               offset, data, cmpval);
-       return (data == cmpval);
- }
- static bool
- io_condition_met(struct nvbios *bios, uint16_t offset, uint8_t cond)
- {
-       /*
-        * The IO condition entry has 2 bytes for the IO port address; 1 byte
-        * for the index to write to io_port; 1 byte for the mask to apply to
-        * the byte read from io_port+1; and 1 byte for the value to compare
-        * against the masked byte.
-        */
-       uint16_t condptr = bios->io_condition_tbl_ptr + cond * IO_CONDITION_SIZE;
-       uint16_t io_port = ROM16(bios->data[condptr]);
-       uint8_t port_index = bios->data[condptr + 2];
-       uint8_t mask = bios->data[condptr + 3];
-       uint8_t cmpval = bios->data[condptr + 4];
-       uint8_t data = bios_idxprt_rd(bios, io_port, port_index) & mask;
-       BIOSLOG(bios, "0x%04X: Checking if 0x%02X equals 0x%02X\n",
-               offset, data, cmpval);
-       return (data == cmpval);
- }
- static int
- nv50_pll_set(struct drm_device *dev, uint32_t reg, uint32_t clk)
- {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pll_vals pll;
-       struct pll_lims pll_limits;
-       u32 ctrl, mask, coef;
-       int ret;
-       ret = get_pll_limits(dev, reg, &pll_limits);
-       if (ret)
-               return ret;
-       clk = nouveau_calc_pll_mnp(dev, &pll_limits, clk, &pll);
-       if (!clk)
-               return -ERANGE;
-       coef = pll.N1 << 8 | pll.M1;
-       ctrl = pll.log2P << 16;
-       mask = 0x00070000;
-       if (reg == 0x004008) {
-               mask |= 0x01f80000;
-               ctrl |= (pll_limits.log2p_bias << 19);
-               ctrl |= (pll.log2P << 22);
-       }
-       if (!dev_priv->vbios.execute)
-               return 0;
-       nv_mask(dev, reg + 0, mask, ctrl);
-       nv_wr32(dev, reg + 4, coef);
-       return 0;
- }
- static int
- setPLL(struct nvbios *bios, uint32_t reg, uint32_t clk)
- {
-       struct drm_device *dev = bios->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       /* clk in kHz */
-       struct pll_lims pll_lim;
-       struct nouveau_pll_vals pllvals;
-       int ret;
-       if (dev_priv->card_type >= NV_50)
-               return nv50_pll_set(dev, reg, clk);
-       /* high regs (such as in the mac g5 table) are not -= 4 */
-       ret = get_pll_limits(dev, reg > 0x405c ? reg : reg - 4, &pll_lim);
-       if (ret)
-               return ret;
-       clk = nouveau_calc_pll_mnp(dev, &pll_lim, clk, &pllvals);
-       if (!clk)
-               return -ERANGE;
-       if (bios->execute) {
-               still_alive();
-               nouveau_hw_setpll(dev, reg, &pllvals);
-       }
-       return 0;
- }
- static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
- {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
-       /*
-        * For the results of this function to be correct, CR44 must have been
-        * set (using bios_idxprt_wr to set crtchead), CR58 set for CR57 = 0,
-        * and the DCB table parsed, before the script calling the function is
-        * run.  run_digital_op_script is example of how to do such setup
-        */
-       uint8_t dcb_entry = NVReadVgaCrtc5758(dev, bios->state.crtchead, 0);
-       if (dcb_entry > bios->dcb.entries) {
-               NV_ERROR(dev, "CR58 doesn't have a valid DCB entry currently "
-                               "(%02X)\n", dcb_entry);
-               dcb_entry = 0x7f;       /* unused / invalid marker */
-       }
-       return dcb_entry;
- }
- static struct nouveau_i2c_chan *
- init_i2c_device_find(struct drm_device *dev, int i2c_index)
- {
-       if (i2c_index == 0xff) {
-               struct drm_nouveau_private *dev_priv = dev->dev_private;
-               struct dcb_table *dcb = &dev_priv->vbios.dcb;
-               /* note: dcb_entry_idx_from_crtchead needs pre-script set-up */
-               int idx = dcb_entry_idx_from_crtchead(dev);
-               i2c_index = NV_I2C_DEFAULT(0);
-               if (idx != 0x7f && dcb->entry[idx].i2c_upper_default)
-                       i2c_index = NV_I2C_DEFAULT(1);
-       }
-       return nouveau_i2c_find(dev, i2c_index);
- }
- static uint32_t
- get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
- {
-       /*
-        * For mlv < 0x80, it is an index into a table of TMDS base addresses.
-        * For mlv == 0x80 use the "or" value of the dcb_entry indexed by
-        * CR58 for CR57 = 0 to index a table of offsets to the basic
-        * 0x6808b0 address.
-        * For mlv == 0x81 use the "or" value of the dcb_entry indexed by
-        * CR58 for CR57 = 0 to index a table of offsets to the basic
-        * 0x6808b0 address, and then flip the offset by 8.
-        */
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
-       const int pramdac_offset[13] = {
-               0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000 };
-       const uint32_t pramdac_table[4] = {
-               0x6808b0, 0x6808b8, 0x6828b0, 0x6828b8 };
-       if (mlv >= 0x80) {
-               int dcb_entry, dacoffset;
-               /* note: dcb_entry_idx_from_crtchead needs pre-script set-up */
-               dcb_entry = dcb_entry_idx_from_crtchead(dev);
-               if (dcb_entry == 0x7f)
-                       return 0;
-               dacoffset = pramdac_offset[bios->dcb.entry[dcb_entry].or];
-               if (mlv == 0x81)
-                       dacoffset ^= 8;
-               return 0x6808b0 + dacoffset;
-       } else {
-               if (mlv >= ARRAY_SIZE(pramdac_table)) {
-                       NV_ERROR(dev, "Magic Lookup Value too big (%02X)\n",
-                                                                       mlv);
-                       return 0;
-               }
-               return pramdac_table[mlv];
-       }
- }
- static int
- init_io_restrict_prog(struct nvbios *bios, uint16_t offset,
-                     struct init_exec *iexec)
- {
-       /*
-        * INIT_IO_RESTRICT_PROG   opcode: 0x32 ('2')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (16 bit): CRTC port
-        * offset + 3  (8  bit): CRTC index
-        * offset + 4  (8  bit): mask
-        * offset + 5  (8  bit): shift
-        * offset + 6  (8  bit): count
-        * offset + 7  (32 bit): register
-        * offset + 11 (32 bit): configuration 1
-        * ...
-        *
-        * Starting at offset + 11 there are "count" 32 bit values.
-        * To find out which value to use read index "CRTC index" on "CRTC
-        * port", AND this value with "mask" and then bit shift right "shift"
-        * bits.  Read the appropriate value using this index and write to
-        * "register"
-        */
-       uint16_t crtcport = ROM16(bios->data[offset + 1]);
-       uint8_t crtcindex = bios->data[offset + 3];
-       uint8_t mask = bios->data[offset + 4];
-       uint8_t shift = bios->data[offset + 5];
-       uint8_t count = bios->data[offset + 6];
-       uint32_t reg = ROM32(bios->data[offset + 7]);
-       uint8_t config;
-       uint32_t configval;
-       int len = 11 + count * 4;
-       if (!iexec->execute)
-               return len;
-       BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
-                     "Shift: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
-               offset, crtcport, crtcindex, mask, shift, count, reg);
-       config = (bios_idxprt_rd(bios, crtcport, crtcindex) & mask) >> shift;
-       if (config > count) {
-               NV_ERROR(bios->dev,
-                        "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
-                        offset, config, count);
-               return len;
-       }
-       configval = ROM32(bios->data[offset + 11 + config * 4]);
-       BIOSLOG(bios, "0x%04X: Writing config %02X\n", offset, config);
-       bios_wr32(bios, reg, configval);
-       return len;
- }
- static int
- init_repeat(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_REPEAT   opcode: 0x33 ('3')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): count
-        *
-        * Execute script following this opcode up to INIT_REPEAT_END
-        * "count" times
-        */
-       uint8_t count = bios->data[offset + 1];
-       uint8_t i;
-       /* no iexec->execute check by design */
-       BIOSLOG(bios, "0x%04X: Repeating following segment %d times\n",
-               offset, count);
-       iexec->repeat = true;
-       /*
-        * count - 1, as the script block will execute once when we leave this
-        * opcode -- this is compatible with bios behaviour as:
-        * a) the block is always executed at least once, even if count == 0
-        * b) the bios interpreter skips to the op following INIT_END_REPEAT,
-        * while we don't
-        */
-       for (i = 0; i < count - 1; i++)
-               parse_init_table(bios, offset + 2, iexec);
-       iexec->repeat = false;
-       return 2;
- }
- static int
- init_io_restrict_pll(struct nvbios *bios, uint16_t offset,
-                    struct init_exec *iexec)
- {
-       /*
-        * INIT_IO_RESTRICT_PLL   opcode: 0x34 ('4')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (16 bit): CRTC port
-        * offset + 3  (8  bit): CRTC index
-        * offset + 4  (8  bit): mask
-        * offset + 5  (8  bit): shift
-        * offset + 6  (8  bit): IO flag condition index
-        * offset + 7  (8  bit): count
-        * offset + 8  (32 bit): register
-        * offset + 12 (16 bit): frequency 1
-        * ...
-        *
-        * Starting at offset + 12 there are "count" 16 bit frequencies (10kHz).
-        * Set PLL register "register" to coefficients for frequency n,
-        * selected by reading index "CRTC index" of "CRTC port" ANDed with
-        * "mask" and shifted right by "shift".
-        *
-        * If "IO flag condition index" > 0, and condition met, double
-        * frequency before setting it.
-        */
-       uint16_t crtcport = ROM16(bios->data[offset + 1]);
-       uint8_t crtcindex = bios->data[offset + 3];
-       uint8_t mask = bios->data[offset + 4];
-       uint8_t shift = bios->data[offset + 5];
-       int8_t io_flag_condition_idx = bios->data[offset + 6];
-       uint8_t count = bios->data[offset + 7];
-       uint32_t reg = ROM32(bios->data[offset + 8]);
-       uint8_t config;
-       uint16_t freq;
-       int len = 12 + count * 2;
-       if (!iexec->execute)
-               return len;
-       BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
-                     "Shift: 0x%02X, IO Flag Condition: 0x%02X, "
-                     "Count: 0x%02X, Reg: 0x%08X\n",
-               offset, crtcport, crtcindex, mask, shift,
-               io_flag_condition_idx, count, reg);
-       config = (bios_idxprt_rd(bios, crtcport, crtcindex) & mask) >> shift;
-       if (config > count) {
-               NV_ERROR(bios->dev,
-                        "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
-                        offset, config, count);
-               return len;
-       }
-       freq = ROM16(bios->data[offset + 12 + config * 2]);
-       if (io_flag_condition_idx > 0) {
-               if (io_flag_condition_met(bios, offset, io_flag_condition_idx)) {
-                       BIOSLOG(bios, "0x%04X: Condition fulfilled -- "
-                                     "frequency doubled\n", offset);
-                       freq *= 2;
-               } else
-                       BIOSLOG(bios, "0x%04X: Condition not fulfilled -- "
-                                     "frequency unchanged\n", offset);
-       }
-       BIOSLOG(bios, "0x%04X: Reg: 0x%08X, Config: 0x%02X, Freq: %d0kHz\n",
-               offset, reg, config, freq);
-       setPLL(bios, reg, freq * 10);
-       return len;
- }
- static int
- init_end_repeat(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_END_REPEAT   opcode: 0x36 ('6')
-        *
-        * offset      (8 bit): opcode
-        *
-        * Marks the end of the block for INIT_REPEAT to repeat
-        */
-       /* no iexec->execute check by design */
-       /*
-        * iexec->repeat flag necessary to go past INIT_END_REPEAT opcode when
-        * we're not in repeat mode
-        */
-       if (iexec->repeat)
-               return 0;
-       return 1;
- }
- static int
- init_copy(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_COPY   opcode: 0x37 ('7')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): register
-        * offset + 5  (8  bit): shift
-        * offset + 6  (8  bit): srcmask
-        * offset + 7  (16 bit): CRTC port
-        * offset + 9  (8 bit): CRTC index
-        * offset + 10  (8 bit): mask
-        *
-        * Read index "CRTC index" on "CRTC port", AND with "mask", OR with
-        * (REGVAL("register") >> "shift" & "srcmask") and write-back to CRTC
-        * port
-        */
-       uint32_t reg = ROM32(bios->data[offset + 1]);
-       uint8_t shift = bios->data[offset + 5];
-       uint8_t srcmask = bios->data[offset + 6];
-       uint16_t crtcport = ROM16(bios->data[offset + 7]);
-       uint8_t crtcindex = bios->data[offset + 9];
-       uint8_t mask = bios->data[offset + 10];
-       uint32_t data;
-       uint8_t crtcdata;
-       if (!iexec->execute)
-               return 11;
-       BIOSLOG(bios, "0x%04X: Reg: 0x%08X, Shift: 0x%02X, SrcMask: 0x%02X, "
-                     "Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X\n",
-               offset, reg, shift, srcmask, crtcport, crtcindex, mask);
-       data = bios_rd32(bios, reg);
-       if (shift < 0x80)
-               data >>= shift;
-       else
-               data <<= (0x100 - shift);
-       data &= srcmask;
-       crtcdata  = bios_idxprt_rd(bios, crtcport, crtcindex) & mask;
-       crtcdata |= (uint8_t)data;
-       bios_idxprt_wr(bios, crtcport, crtcindex, crtcdata);
-       return 11;
- }
- static int
- init_not(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_NOT   opcode: 0x38 ('8')
-        *
-        * offset      (8  bit): opcode
-        *
-        * Invert the current execute / no-execute condition (i.e. "else")
-        */
-       if (iexec->execute)
-               BIOSLOG(bios, "0x%04X: ------ Skipping following commands  ------\n", offset);
-       else
-               BIOSLOG(bios, "0x%04X: ------ Executing following commands ------\n", offset);
-       iexec->execute = !iexec->execute;
-       return 1;
- }
- static int
- init_io_flag_condition(struct nvbios *bios, uint16_t offset,
-                      struct init_exec *iexec)
- {
-       /*
-        * INIT_IO_FLAG_CONDITION   opcode: 0x39 ('9')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): condition number
-        *
-        * Check condition "condition number" in the IO flag condition table.
-        * If condition not met skip subsequent opcodes until condition is
-        * inverted (INIT_NOT), or we hit INIT_RESUME
-        */
-       uint8_t cond = bios->data[offset + 1];
-       if (!iexec->execute)
-               return 2;
-       if (io_flag_condition_met(bios, offset, cond))
-               BIOSLOG(bios, "0x%04X: Condition fulfilled -- continuing to execute\n", offset);
-       else {
-               BIOSLOG(bios, "0x%04X: Condition not fulfilled -- skipping following commands\n", offset);
-               iexec->execute = false;
-       }
-       return 2;
- }
- static int
- init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_DP_CONDITION   opcode: 0x3A ('')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): "sub" opcode
-        * offset + 2  (8 bit): unknown
-        *
-        */
-       struct dcb_entry *dcb = bios->display.output;
-       struct drm_device *dev = bios->dev;
-       uint8_t cond = bios->data[offset + 1];
-       uint8_t *table, *entry;
-       BIOSLOG(bios, "0x%04X: subop 0x%02X\n", offset, cond);
-       if (!iexec->execute)
-               return 3;
-       table = nouveau_dp_bios_data(dev, dcb, &entry);
-       if (!table)
-               return 3;
-       switch (cond) {
-       case 0:
-               entry = dcb_conn(dev, dcb->connector);
-               if (!entry || entry[0] != DCB_CONNECTOR_eDP)
-                       iexec->execute = false;
-               break;
-       case 1:
-       case 2:
-               if ((table[0]  < 0x40 && !(entry[5] & cond)) ||
-                   (table[0] == 0x40 && !(entry[4] & cond)))
-                       iexec->execute = false;
-               break;
-       case 5:
-       {
-               struct nouveau_i2c_chan *auxch;
-               int ret;
-               auxch = nouveau_i2c_find(dev, bios->display.output->i2c_index);
-               if (!auxch) {
-                       NV_ERROR(dev, "0x%04X: couldn't get auxch\n", offset);
-                       return 3;
-               }
-               ret = nouveau_dp_auxch(auxch, 9, 0xd, &cond, 1);
-               if (ret) {
-                       NV_ERROR(dev, "0x%04X: auxch rd fail: %d\n", offset, ret);
-                       return 3;
-               }
-               if (!(cond & 1))
-                       iexec->execute = false;
-       }
-               break;
-       default:
-               NV_WARN(dev, "0x%04X: unknown INIT_3A op: %d\n", offset, cond);
-               break;
-       }
-       if (iexec->execute)
-               BIOSLOG(bios, "0x%04X: continuing to execute\n", offset);
-       else
-               BIOSLOG(bios, "0x%04X: skipping following commands\n", offset);
-       return 3;
- }
- static int
- init_op_3b(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_3B   opcode: 0x3B ('')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): crtc index
-        *
-        */
-       uint8_t or = ffs(bios->display.output->or) - 1;
-       uint8_t index = bios->data[offset + 1];
-       uint8_t data;
-       if (!iexec->execute)
-               return 2;
-       data = bios_idxprt_rd(bios, 0x3d4, index);
-       bios_idxprt_wr(bios, 0x3d4, index, data & ~(1 << or));
-       return 2;
- }
- static int
- init_op_3c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_3C   opcode: 0x3C ('')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): crtc index
-        *
-        */
-       uint8_t or = ffs(bios->display.output->or) - 1;
-       uint8_t index = bios->data[offset + 1];
-       uint8_t data;
-       if (!iexec->execute)
-               return 2;
-       data = bios_idxprt_rd(bios, 0x3d4, index);
-       bios_idxprt_wr(bios, 0x3d4, index, data | (1 << or));
-       return 2;
- }
- static int
- init_idx_addr_latched(struct nvbios *bios, uint16_t offset,
-                     struct init_exec *iexec)
- {
-       /*
-        * INIT_INDEX_ADDRESS_LATCHED   opcode: 0x49 ('I')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): control register
-        * offset + 5  (32 bit): data register
-        * offset + 9  (32 bit): mask
-        * offset + 13 (32 bit): data
-        * offset + 17 (8  bit): count
-        * offset + 18 (8  bit): address 1
-        * offset + 19 (8  bit): data 1
-        * ...
-        *
-        * For each of "count" address and data pairs, write "data n" to
-        * "data register", read the current value of "control register",
-        * and write it back once ANDed with "mask", ORed with "data",
-        * and ORed with "address n"
-        */
-       uint32_t controlreg = ROM32(bios->data[offset + 1]);
-       uint32_t datareg = ROM32(bios->data[offset + 5]);
-       uint32_t mask = ROM32(bios->data[offset + 9]);
-       uint32_t data = ROM32(bios->data[offset + 13]);
-       uint8_t count = bios->data[offset + 17];
-       int len = 18 + count * 2;
-       uint32_t value;
-       int i;
-       if (!iexec->execute)
-               return len;
-       BIOSLOG(bios, "0x%04X: ControlReg: 0x%08X, DataReg: 0x%08X, "
-                     "Mask: 0x%08X, Data: 0x%08X, Count: 0x%02X\n",
-               offset, controlreg, datareg, mask, data, count);
-       for (i = 0; i < count; i++) {
-               uint8_t instaddress = bios->data[offset + 18 + i * 2];
-               uint8_t instdata = bios->data[offset + 19 + i * 2];
-               BIOSLOG(bios, "0x%04X: Address: 0x%02X, Data: 0x%02X\n",
-                       offset, instaddress, instdata);
-               bios_wr32(bios, datareg, instdata);
-               value  = bios_rd32(bios, controlreg) & mask;
-               value |= data;
-               value |= instaddress;
-               bios_wr32(bios, controlreg, value);
-       }
-       return len;
- }
- static int
- init_io_restrict_pll2(struct nvbios *bios, uint16_t offset,
-                     struct init_exec *iexec)
- {
-       /*
-        * INIT_IO_RESTRICT_PLL2   opcode: 0x4A ('J')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (16 bit): CRTC port
-        * offset + 3  (8  bit): CRTC index
-        * offset + 4  (8  bit): mask
-        * offset + 5  (8  bit): shift
-        * offset + 6  (8  bit): count
-        * offset + 7  (32 bit): register
-        * offset + 11 (32 bit): frequency 1
-        * ...
-        *
-        * Starting at offset + 11 there are "count" 32 bit frequencies (kHz).
-        * Set PLL register "register" to coefficients for frequency n,
-        * selected by reading index "CRTC index" of "CRTC port" ANDed with
-        * "mask" and shifted right by "shift".
-        */
-       uint16_t crtcport = ROM16(bios->data[offset + 1]);
-       uint8_t crtcindex = bios->data[offset + 3];
-       uint8_t mask = bios->data[offset + 4];
-       uint8_t shift = bios->data[offset + 5];
-       uint8_t count = bios->data[offset + 6];
-       uint32_t reg = ROM32(bios->data[offset + 7]);
-       int len = 11 + count * 4;
-       uint8_t config;
-       uint32_t freq;
-       if (!iexec->execute)
-               return len;
-       BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
-                     "Shift: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
-               offset, crtcport, crtcindex, mask, shift, count, reg);
-       if (!reg)
-               return len;
-       config = (bios_idxprt_rd(bios, crtcport, crtcindex) & mask) >> shift;
-       if (config > count) {
-               NV_ERROR(bios->dev,
-                        "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
-                        offset, config, count);
-               return len;
-       }
-       freq = ROM32(bios->data[offset + 11 + config * 4]);
-       BIOSLOG(bios, "0x%04X: Reg: 0x%08X, Config: 0x%02X, Freq: %dkHz\n",
-               offset, reg, config, freq);
-       setPLL(bios, reg, freq);
-       return len;
- }
- static int
- init_pll2(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_PLL2   opcode: 0x4B ('K')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): register
-        * offset + 5  (32 bit): freq
-        *
-        * Set PLL register "register" to coefficients for frequency "freq"
-        */
-       uint32_t reg = ROM32(bios->data[offset + 1]);
-       uint32_t freq = ROM32(bios->data[offset + 5]);
-       if (!iexec->execute)
-               return 9;
-       BIOSLOG(bios, "0x%04X: Reg: 0x%04X, Freq: %dkHz\n",
-               offset, reg, freq);
-       setPLL(bios, reg, freq);
-       return 9;
- }
- static int
- init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_I2C_BYTE   opcode: 0x4C ('L')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): DCB I2C table entry index
-        * offset + 2  (8 bit): I2C slave address
-        * offset + 3  (8 bit): count
-        * offset + 4  (8 bit): I2C register 1
-        * offset + 5  (8 bit): mask 1
-        * offset + 6  (8 bit): data 1
-        * ...
-        *
-        * For each of "count" registers given by "I2C register n" on the device
-        * addressed by "I2C slave address" on the I2C bus given by
-        * "DCB I2C table entry index", read the register, AND the result with
-        * "mask n" and OR it with "data n" before writing it back to the device
-        */
-       struct drm_device *dev = bios->dev;
-       uint8_t i2c_index = bios->data[offset + 1];
-       uint8_t i2c_address = bios->data[offset + 2] >> 1;
-       uint8_t count = bios->data[offset + 3];
-       struct nouveau_i2c_chan *chan;
-       int len = 4 + count * 3;
-       int ret, i;
-       if (!iexec->execute)
-               return len;
-       BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X, "
-                     "Count: 0x%02X\n",
-               offset, i2c_index, i2c_address, count);
-       chan = init_i2c_device_find(dev, i2c_index);
-       if (!chan) {
-               NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset);
-               return len;
-       }
-       for (i = 0; i < count; i++) {
-               uint8_t reg = bios->data[offset + 4 + i * 3];
-               uint8_t mask = bios->data[offset + 5 + i * 3];
-               uint8_t data = bios->data[offset + 6 + i * 3];
-               union i2c_smbus_data val;
-               ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
-                                    I2C_SMBUS_READ, reg,
-                                    I2C_SMBUS_BYTE_DATA, &val);
-               if (ret < 0) {
-                       NV_ERROR(dev, "0x%04X: i2c rd fail: %d\n", offset, ret);
-                       return len;
-               }
-               BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, "
-                             "Mask: 0x%02X, Data: 0x%02X\n",
-                       offset, reg, val.byte, mask, data);
-               if (!bios->execute)
-                       continue;
-               val.byte &= mask;
-               val.byte |= data;
-               ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
-                                    I2C_SMBUS_WRITE, reg,
-                                    I2C_SMBUS_BYTE_DATA, &val);
-               if (ret < 0) {
-                       NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret);
-                       return len;
-               }
-       }
-       return len;
- }
- static int
- init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_ZM_I2C_BYTE   opcode: 0x4D ('M')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): DCB I2C table entry index
-        * offset + 2  (8 bit): I2C slave address
-        * offset + 3  (8 bit): count
-        * offset + 4  (8 bit): I2C register 1
-        * offset + 5  (8 bit): data 1
-        * ...
-        *
-        * For each of "count" registers given by "I2C register n" on the device
-        * addressed by "I2C slave address" on the I2C bus given by
-        * "DCB I2C table entry index", set the register to "data n"
-        */
-       struct drm_device *dev = bios->dev;
-       uint8_t i2c_index = bios->data[offset + 1];
-       uint8_t i2c_address = bios->data[offset + 2] >> 1;
-       uint8_t count = bios->data[offset + 3];
-       struct nouveau_i2c_chan *chan;
-       int len = 4 + count * 2;
-       int ret, i;
-       if (!iexec->execute)
-               return len;
-       BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X, "
-                     "Count: 0x%02X\n",
-               offset, i2c_index, i2c_address, count);
-       chan = init_i2c_device_find(dev, i2c_index);
-       if (!chan) {
-               NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset);
-               return len;
-       }
-       for (i = 0; i < count; i++) {
-               uint8_t reg = bios->data[offset + 4 + i * 2];
-               union i2c_smbus_data val;
-               val.byte = bios->data[offset + 5 + i * 2];
-               BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Data: 0x%02X\n",
-                       offset, reg, val.byte);
-               if (!bios->execute)
-                       continue;
-               ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
-                                    I2C_SMBUS_WRITE, reg,
-                                    I2C_SMBUS_BYTE_DATA, &val);
-               if (ret < 0) {
-                       NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret);
-                       return len;
-               }
-       }
-       return len;
- }
- static int
- init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_ZM_I2C   opcode: 0x4E ('N')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): DCB I2C table entry index
-        * offset + 2  (8 bit): I2C slave address
-        * offset + 3  (8 bit): count
-        * offset + 4  (8 bit): data 1
-        * ...
-        *
-        * Send "count" bytes ("data n") to the device addressed by "I2C slave
-        * address" on the I2C bus given by "DCB I2C table entry index"
-        */
-       struct drm_device *dev = bios->dev;
-       uint8_t i2c_index = bios->data[offset + 1];
-       uint8_t i2c_address = bios->data[offset + 2] >> 1;
-       uint8_t count = bios->data[offset + 3];
-       int len = 4 + count;
-       struct nouveau_i2c_chan *chan;
-       struct i2c_msg msg;
-       uint8_t data[256];
-       int ret, i;
-       if (!iexec->execute)
-               return len;
-       BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X, "
-                     "Count: 0x%02X\n",
-               offset, i2c_index, i2c_address, count);
-       chan = init_i2c_device_find(dev, i2c_index);
-       if (!chan) {
-               NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset);
-               return len;
-       }
-       for (i = 0; i < count; i++) {
-               data[i] = bios->data[offset + 4 + i];
-               BIOSLOG(bios, "0x%04X: Data: 0x%02X\n", offset, data[i]);
-       }
-       if (bios->execute) {
-               msg.addr = i2c_address;
-               msg.flags = 0;
-               msg.len = count;
-               msg.buf = data;
-               ret = i2c_transfer(&chan->adapter, &msg, 1);
-               if (ret != 1) {
-                       NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret);
-                       return len;
-               }
-       }
-       return len;
- }
- static int
- init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_TMDS   opcode: 0x4F ('O')       (non-canon name)
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): magic lookup value
-        * offset + 2  (8 bit): TMDS address
-        * offset + 3  (8 bit): mask
-        * offset + 4  (8 bit): data
-        *
-        * Read the data reg for TMDS address "TMDS address", AND it with mask
-        * and OR it with data, then write it back
-        * "magic lookup value" determines which TMDS base address register is
-        * used -- see get_tmds_index_reg()
-        */
-       struct drm_device *dev = bios->dev;
-       uint8_t mlv = bios->data[offset + 1];
-       uint32_t tmdsaddr = bios->data[offset + 2];
-       uint8_t mask = bios->data[offset + 3];
-       uint8_t data = bios->data[offset + 4];
-       uint32_t reg, value;
-       if (!iexec->execute)
-               return 5;
-       BIOSLOG(bios, "0x%04X: MagicLookupValue: 0x%02X, TMDSAddr: 0x%02X, "
-                     "Mask: 0x%02X, Data: 0x%02X\n",
-               offset, mlv, tmdsaddr, mask, data);
-       reg = get_tmds_index_reg(bios->dev, mlv);
-       if (!reg) {
-               NV_ERROR(dev, "0x%04X: no tmds_index_reg\n", offset);
-               return 5;
-       }
-       bios_wr32(bios, reg,
-                 tmdsaddr | NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE);
-       value = (bios_rd32(bios, reg + 4) & mask) | data;
-       bios_wr32(bios, reg + 4, value);
-       bios_wr32(bios, reg, tmdsaddr);
-       return 5;
- }
- static int
- init_zm_tmds_group(struct nvbios *bios, uint16_t offset,
-                  struct init_exec *iexec)
- {
-       /*
-        * INIT_ZM_TMDS_GROUP   opcode: 0x50 ('P')      (non-canon name)
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): magic lookup value
-        * offset + 2  (8 bit): count
-        * offset + 3  (8 bit): addr 1
-        * offset + 4  (8 bit): data 1
-        * ...
-        *
-        * For each of "count" TMDS address and data pairs write "data n" to
-        * "addr n".  "magic lookup value" determines which TMDS base address
-        * register is used -- see get_tmds_index_reg()
-        */
-       struct drm_device *dev = bios->dev;
-       uint8_t mlv = bios->data[offset + 1];
-       uint8_t count = bios->data[offset + 2];
-       int len = 3 + count * 2;
-       uint32_t reg;
-       int i;
-       if (!iexec->execute)
-               return len;
-       BIOSLOG(bios, "0x%04X: MagicLookupValue: 0x%02X, Count: 0x%02X\n",
-               offset, mlv, count);
-       reg = get_tmds_index_reg(bios->dev, mlv);
-       if (!reg) {
-               NV_ERROR(dev, "0x%04X: no tmds_index_reg\n", offset);
-               return len;
-       }
-       for (i = 0; i < count; i++) {
-               uint8_t tmdsaddr = bios->data[offset + 3 + i * 2];
-               uint8_t tmdsdata = bios->data[offset + 4 + i * 2];
-               bios_wr32(bios, reg + 4, tmdsdata);
-               bios_wr32(bios, reg, tmdsaddr);
-       }
-       return len;
- }
- static int
- init_cr_idx_adr_latch(struct nvbios *bios, uint16_t offset,
-                     struct init_exec *iexec)
- {
-       /*
-        * INIT_CR_INDEX_ADDRESS_LATCHED   opcode: 0x51 ('Q')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): CRTC index1
-        * offset + 2  (8 bit): CRTC index2
-        * offset + 3  (8 bit): baseaddr
-        * offset + 4  (8 bit): count
-        * offset + 5  (8 bit): data 1
-        * ...
-        *
-        * For each of "count" address and data pairs, write "baseaddr + n" to
-        * "CRTC index1" and "data n" to "CRTC index2"
-        * Once complete, restore initial value read from "CRTC index1"
-        */
-       uint8_t crtcindex1 = bios->data[offset + 1];
-       uint8_t crtcindex2 = bios->data[offset + 2];
-       uint8_t baseaddr = bios->data[offset + 3];
-       uint8_t count = bios->data[offset + 4];
-       int len = 5 + count;
-       uint8_t oldaddr, data;
-       int i;
-       if (!iexec->execute)
-               return len;
-       BIOSLOG(bios, "0x%04X: Index1: 0x%02X, Index2: 0x%02X, "
-                     "BaseAddr: 0x%02X, Count: 0x%02X\n",
-               offset, crtcindex1, crtcindex2, baseaddr, count);
-       oldaddr = bios_idxprt_rd(bios, NV_CIO_CRX__COLOR, crtcindex1);
-       for (i = 0; i < count; i++) {
-               bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, crtcindex1,
-                                    baseaddr + i);
-               data = bios->data[offset + 5 + i];
-               bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, crtcindex2, data);
-       }
-       bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, crtcindex1, oldaddr);
-       return len;
- }
- static int
- init_cr(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_CR   opcode: 0x52 ('R')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (8  bit): CRTC index
-        * offset + 2  (8  bit): mask
-        * offset + 3  (8  bit): data
-        *
-        * Assign the value of at "CRTC index" ANDed with mask and ORed with
-        * data back to "CRTC index"
-        */
-       uint8_t crtcindex = bios->data[offset + 1];
-       uint8_t mask = bios->data[offset + 2];
-       uint8_t data = bios->data[offset + 3];
-       uint8_t value;
-       if (!iexec->execute)
-               return 4;
-       BIOSLOG(bios, "0x%04X: Index: 0x%02X, Mask: 0x%02X, Data: 0x%02X\n",
-               offset, crtcindex, mask, data);
-       value  = bios_idxprt_rd(bios, NV_CIO_CRX__COLOR, crtcindex) & mask;
-       value |= data;
-       bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, crtcindex, value);
-       return 4;
- }
- static int
- init_zm_cr(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_ZM_CR   opcode: 0x53 ('S')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): CRTC index
-        * offset + 2  (8 bit): value
-        *
-        * Assign "value" to CRTC register with index "CRTC index".
-        */
-       uint8_t crtcindex = ROM32(bios->data[offset + 1]);
-       uint8_t data = bios->data[offset + 2];
-       if (!iexec->execute)
-               return 3;
-       bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, crtcindex, data);
-       return 3;
- }
- static int
- init_zm_cr_group(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_ZM_CR_GROUP   opcode: 0x54 ('T')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): count
-        * offset + 2  (8 bit): CRTC index 1
-        * offset + 3  (8 bit): value 1
-        * ...
-        *
-        * For "count", assign "value n" to CRTC register with index
-        * "CRTC index n".
-        */
-       uint8_t count = bios->data[offset + 1];
-       int len = 2 + count * 2;
-       int i;
-       if (!iexec->execute)
-               return len;
-       for (i = 0; i < count; i++)
-               init_zm_cr(bios, offset + 2 + 2 * i - 1, iexec);
-       return len;
- }
- static int
- init_condition_time(struct nvbios *bios, uint16_t offset,
-                   struct init_exec *iexec)
- {
-       /*
-        * INIT_CONDITION_TIME   opcode: 0x56 ('V')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): condition number
-        * offset + 2  (8 bit): retries / 50
-        *
-        * Check condition "condition number" in the condition table.
-        * Bios code then sleeps for 2ms if the condition is not met, and
-        * repeats up to "retries" times, but on one C51 this has proved
-        * insufficient.  In mmiotraces the driver sleeps for 20ms, so we do
-        * this, and bail after "retries" times, or 2s, whichever is less.
-        * If still not met after retries, clear execution flag for this table.
-        */
-       uint8_t cond = bios->data[offset + 1];
-       uint16_t retries = bios->data[offset + 2] * 50;
-       unsigned cnt;
-       if (!iexec->execute)
-               return 3;
-       if (retries > 100)
-               retries = 100;
-       BIOSLOG(bios, "0x%04X: Condition: 0x%02X, Retries: 0x%02X\n",
-               offset, cond, retries);
-       if (!bios->execute) /* avoid 2s delays when "faking" execution */
-               retries = 1;
-       for (cnt = 0; cnt < retries; cnt++) {
-               if (bios_condition_met(bios, offset, cond)) {
-                       BIOSLOG(bios, "0x%04X: Condition met, continuing\n",
-                                                               offset);
-                       break;
-               } else {
-                       BIOSLOG(bios, "0x%04X: "
-                               "Condition not met, sleeping for 20ms\n",
-                                                               offset);
-                       mdelay(20);
-               }
-       }
-       if (!bios_condition_met(bios, offset, cond)) {
-               NV_WARN(bios->dev,
-                       "0x%04X: Condition still not met after %dms, "
-                       "skipping following opcodes\n", offset, 20 * retries);
-               iexec->execute = false;
-       }
-       return 3;
- }
- static int
- init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_LTIME   opcode: 0x57 ('V')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (16 bit): time
-        *
-        * Sleep for "time" milliseconds.
-        */
-       unsigned time = ROM16(bios->data[offset + 1]);
-       if (!iexec->execute)
-               return 3;
-       BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X milliseconds\n",
-               offset, time);
-       mdelay(time);
-       return 3;
- }
- static int
- init_zm_reg_sequence(struct nvbios *bios, uint16_t offset,
-                    struct init_exec *iexec)
- {
-       /*
-        * INIT_ZM_REG_SEQUENCE   opcode: 0x58 ('X')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): base register
-        * offset + 5  (8  bit): count
-        * offset + 6  (32 bit): value 1
-        * ...
-        *
-        * Starting at offset + 6 there are "count" 32 bit values.
-        * For "count" iterations set "base register" + 4 * current_iteration
-        * to "value current_iteration"
-        */
-       uint32_t basereg = ROM32(bios->data[offset + 1]);
-       uint32_t count = bios->data[offset + 5];
-       int len = 6 + count * 4;
-       int i;
-       if (!iexec->execute)
-               return len;
-       BIOSLOG(bios, "0x%04X: BaseReg: 0x%08X, Count: 0x%02X\n",
-               offset, basereg, count);
-       for (i = 0; i < count; i++) {
-               uint32_t reg = basereg + i * 4;
-               uint32_t data = ROM32(bios->data[offset + 6 + i * 4]);
-               bios_wr32(bios, reg, data);
-       }
-       return len;
- }
- static int
- init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_SUB_DIRECT   opcode: 0x5B ('[')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (16 bit): subroutine offset (in bios)
-        *
-        * Calls a subroutine that will execute commands until INIT_DONE
-        * is found.
-        */
-       uint16_t sub_offset = ROM16(bios->data[offset + 1]);
-       if (!iexec->execute)
-               return 3;
-       BIOSLOG(bios, "0x%04X: Executing subroutine at 0x%04X\n",
-               offset, sub_offset);
-       parse_init_table(bios, sub_offset, iexec);
-       BIOSLOG(bios, "0x%04X: End of 0x%04X subroutine\n", offset, sub_offset);
-       return 3;
- }
- static int
- init_jump(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_JUMP   opcode: 0x5C ('\')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (16 bit): offset (in bios)
-        *
-        * Continue execution of init table from 'offset'
-        */
-       uint16_t jmp_offset = ROM16(bios->data[offset + 1]);
-       if (!iexec->execute)
-               return 3;
-       BIOSLOG(bios, "0x%04X: Jump to 0x%04X\n", offset, jmp_offset);
-       return jmp_offset - offset;
- }
- static int
- init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_I2C_IF   opcode: 0x5E ('^')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): DCB I2C table entry index
-        * offset + 2  (8 bit): I2C slave address
-        * offset + 3  (8 bit): I2C register
-        * offset + 4  (8 bit): mask
-        * offset + 5  (8 bit): data
-        *
-        * Read the register given by "I2C register" on the device addressed
-        * by "I2C slave address" on the I2C bus given by "DCB I2C table
-        * entry index". Compare the result AND "mask" to "data".
-        * If they're not equal, skip subsequent opcodes until condition is
-        * inverted (INIT_NOT), or we hit INIT_RESUME
-        */
-       uint8_t i2c_index = bios->data[offset + 1];
-       uint8_t i2c_address = bios->data[offset + 2] >> 1;
-       uint8_t reg = bios->data[offset + 3];
-       uint8_t mask = bios->data[offset + 4];
-       uint8_t data = bios->data[offset + 5];
-       struct nouveau_i2c_chan *chan;
-       union i2c_smbus_data val;
-       int ret;
-       /* no execute check by design */
-       BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n",
-               offset, i2c_index, i2c_address);
-       chan = init_i2c_device_find(bios->dev, i2c_index);
-       if (!chan)
-               return -ENODEV;
-       ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
-                            I2C_SMBUS_READ, reg,
-                            I2C_SMBUS_BYTE_DATA, &val);
-       if (ret < 0) {
-               BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: [no device], "
-                             "Mask: 0x%02X, Data: 0x%02X\n",
-                       offset, reg, mask, data);
-               iexec->execute = 0;
-               return 6;
-       }
-       BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, "
-                     "Mask: 0x%02X, Data: 0x%02X\n",
-               offset, reg, val.byte, mask, data);
-       iexec->execute = ((val.byte & mask) == data);
-       return 6;
- }
- static int
- init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_COPY_NV_REG   opcode: 0x5F ('_')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): src reg
-        * offset + 5  (8  bit): shift
-        * offset + 6  (32 bit): src mask
-        * offset + 10 (32 bit): xor
-        * offset + 14 (32 bit): dst reg
-        * offset + 18 (32 bit): dst mask
-        *
-        * Shift REGVAL("src reg") right by (signed) "shift", AND result with
-        * "src mask", then XOR with "xor". Write this OR'd with
-        * (REGVAL("dst reg") AND'd with "dst mask") to "dst reg"
-        */
-       uint32_t srcreg = *((uint32_t *)(&bios->data[offset + 1]));
-       uint8_t shift = bios->data[offset + 5];
-       uint32_t srcmask = *((uint32_t *)(&bios->data[offset + 6]));
-       uint32_t xor = *((uint32_t *)(&bios->data[offset + 10]));
-       uint32_t dstreg = *((uint32_t *)(&bios->data[offset + 14]));
-       uint32_t dstmask = *((uint32_t *)(&bios->data[offset + 18]));
-       uint32_t srcvalue, dstvalue;
-       if (!iexec->execute)
-               return 22;
-       BIOSLOG(bios, "0x%04X: SrcReg: 0x%08X, Shift: 0x%02X, SrcMask: 0x%08X, "
-                     "Xor: 0x%08X, DstReg: 0x%08X, DstMask: 0x%08X\n",
-               offset, srcreg, shift, srcmask, xor, dstreg, dstmask);
-       srcvalue = bios_rd32(bios, srcreg);
-       if (shift < 0x80)
-               srcvalue >>= shift;
-       else
-               srcvalue <<= (0x100 - shift);
-       srcvalue = (srcvalue & srcmask) ^ xor;
-       dstvalue = bios_rd32(bios, dstreg) & dstmask;
-       bios_wr32(bios, dstreg, dstvalue | srcvalue);
-       return 22;
- }
- static int
- init_zm_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_ZM_INDEX_IO   opcode: 0x62 ('b')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (16 bit): CRTC port
-        * offset + 3  (8  bit): CRTC index
-        * offset + 4  (8  bit): data
-        *
-        * Write "data" to index "CRTC index" of "CRTC port"
-        */
-       uint16_t crtcport = ROM16(bios->data[offset + 1]);
-       uint8_t crtcindex = bios->data[offset + 3];
-       uint8_t data = bios->data[offset + 4];
-       if (!iexec->execute)
-               return 5;
-       bios_idxprt_wr(bios, crtcport, crtcindex, data);
-       return 5;
- }
- static inline void
- bios_md32(struct nvbios *bios, uint32_t reg,
-         uint32_t mask, uint32_t val)
- {
-       bios_wr32(bios, reg, (bios_rd32(bios, reg) & ~mask) | val);
- }
- static uint32_t
- peek_fb(struct drm_device *dev, struct io_mapping *fb,
-       uint32_t off)
- {
-       uint32_t val = 0;
-       if (off < pci_resource_len(dev->pdev, 1)) {
-               uint8_t __iomem *p =
-                       io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
-               val = ioread32(p + (off & ~PAGE_MASK));
-               io_mapping_unmap_atomic(p);
-       }
-       return val;
- }
- static void
- poke_fb(struct drm_device *dev, struct io_mapping *fb,
-       uint32_t off, uint32_t val)
- {
-       if (off < pci_resource_len(dev->pdev, 1)) {
-               uint8_t __iomem *p =
-                       io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
-               iowrite32(val, p + (off & ~PAGE_MASK));
-               wmb();
-               io_mapping_unmap_atomic(p);
-       }
- }
- static inline bool
- read_back_fb(struct drm_device *dev, struct io_mapping *fb,
-            uint32_t off, uint32_t val)
- {
-       poke_fb(dev, fb, off, val);
-       return val == peek_fb(dev, fb, off);
- }
- static int
- nv04_init_compute_mem(struct nvbios *bios)
- {
-       struct drm_device *dev = bios->dev;
-       uint32_t patt = 0xdeadbeef;
-       struct io_mapping *fb;
-       int i;
-       /* Map the framebuffer aperture */
-       fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1),
-                                 pci_resource_len(dev->pdev, 1));
-       if (!fb)
-               return -ENOMEM;
-       /* Sequencer and refresh off */
-       NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) | 0x20);
-       bios_md32(bios, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF);
-       bios_md32(bios, NV04_PFB_BOOT_0, ~0,
-                 NV04_PFB_BOOT_0_RAM_AMOUNT_16MB |
-                 NV04_PFB_BOOT_0_RAM_WIDTH_128 |
-                 NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT);
-       for (i = 0; i < 4; i++)
-               poke_fb(dev, fb, 4 * i, patt);
-       poke_fb(dev, fb, 0x400000, patt + 1);
-       if (peek_fb(dev, fb, 0) == patt + 1) {
-               bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE,
-                         NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT);
-               bios_md32(bios, NV04_PFB_DEBUG_0,
-                         NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
-               for (i = 0; i < 4; i++)
-                       poke_fb(dev, fb, 4 * i, patt);
-               if ((peek_fb(dev, fb, 0xc) & 0xffff) != (patt & 0xffff))
-                       bios_md32(bios, NV04_PFB_BOOT_0,
-                                 NV04_PFB_BOOT_0_RAM_WIDTH_128 |
-                                 NV04_PFB_BOOT_0_RAM_AMOUNT,
-                                 NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
-       } else if ((peek_fb(dev, fb, 0xc) & 0xffff0000) !=
-                  (patt & 0xffff0000)) {
-               bios_md32(bios, NV04_PFB_BOOT_0,
-                         NV04_PFB_BOOT_0_RAM_WIDTH_128 |
-                         NV04_PFB_BOOT_0_RAM_AMOUNT,
-                         NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
-       } else if (peek_fb(dev, fb, 0) != patt) {
-               if (read_back_fb(dev, fb, 0x800000, patt))
-                       bios_md32(bios, NV04_PFB_BOOT_0,
-                                 NV04_PFB_BOOT_0_RAM_AMOUNT,
-                                 NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
-               else
-                       bios_md32(bios, NV04_PFB_BOOT_0,
-                                 NV04_PFB_BOOT_0_RAM_AMOUNT,
-                                 NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
-               bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE,
-                         NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT);
-       } else if (!read_back_fb(dev, fb, 0x800000, patt)) {
-               bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
-                         NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
-       }
-       /* Refresh on, sequencer on */
-       bios_md32(bios, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
-       NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) & ~0x20);
-       io_mapping_free(fb);
-       return 0;
- }
- static const uint8_t *
- nv05_memory_config(struct nvbios *bios)
- {
-       /* Defaults for BIOSes lacking a memory config table */
-       static const uint8_t default_config_tab[][2] = {
-               { 0x24, 0x00 },
-               { 0x28, 0x00 },
-               { 0x24, 0x01 },
-               { 0x1f, 0x00 },
-               { 0x0f, 0x00 },
-               { 0x17, 0x00 },
-               { 0x06, 0x00 },
-               { 0x00, 0x00 }
-       };
-       int i = (bios_rd32(bios, NV_PEXTDEV_BOOT_0) &
-                NV_PEXTDEV_BOOT_0_RAMCFG) >> 2;
-       if (bios->legacy.mem_init_tbl_ptr)
-               return &bios->data[bios->legacy.mem_init_tbl_ptr + 2 * i];
-       else
-               return default_config_tab[i];
- }
- static int
- nv05_init_compute_mem(struct nvbios *bios)
- {
-       struct drm_device *dev = bios->dev;
-       const uint8_t *ramcfg = nv05_memory_config(bios);
-       uint32_t patt = 0xdeadbeef;
-       struct io_mapping *fb;
-       int i, v;
-       /* Map the framebuffer aperture */
-       fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1),
-                                 pci_resource_len(dev->pdev, 1));
-       if (!fb)
-               return -ENOMEM;
-       /* Sequencer off */
-       NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) | 0x20);
-       if (bios_rd32(bios, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE)
-               goto out;
-       bios_md32(bios, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
-       /* If present load the hardcoded scrambling table */
-       if (bios->legacy.mem_init_tbl_ptr) {
-               uint32_t *scramble_tab = (uint32_t *)&bios->data[
-                       bios->legacy.mem_init_tbl_ptr + 0x10];
-               for (i = 0; i < 8; i++)
-                       bios_wr32(bios, NV04_PFB_SCRAMBLE(i),
-                                 ROM32(scramble_tab[i]));
-       }
-       /* Set memory type/width/length defaults depending on the straps */
-       bios_md32(bios, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]);
-       if (ramcfg[1] & 0x80)
-               bios_md32(bios, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE);
-       bios_md32(bios, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20);
-       bios_md32(bios, NV04_PFB_CFG1, 0, 1);
-       /* Probe memory bus width */
-       for (i = 0; i < 4; i++)
-               poke_fb(dev, fb, 4 * i, patt);
-       if (peek_fb(dev, fb, 0xc) != patt)
-               bios_md32(bios, NV04_PFB_BOOT_0,
-                         NV04_PFB_BOOT_0_RAM_WIDTH_128, 0);
-       /* Probe memory length */
-       v = bios_rd32(bios, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT;
-       if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_32MB &&
-           (!read_back_fb(dev, fb, 0x1000000, ++patt) ||
-            !read_back_fb(dev, fb, 0, ++patt)))
-               bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
-                         NV04_PFB_BOOT_0_RAM_AMOUNT_16MB);
-       if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_16MB &&
-           !read_back_fb(dev, fb, 0x800000, ++patt))
-               bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
-                         NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
-       if (!read_back_fb(dev, fb, 0x400000, ++patt))
-               bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
-                         NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
- out:
-       /* Sequencer on */
-       NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) & ~0x20);
-       io_mapping_free(fb);
-       return 0;
- }
- static int
- nv10_init_compute_mem(struct nvbios *bios)
- {
-       struct drm_device *dev = bios->dev;
-       struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
-       const int mem_width[] = { 0x10, 0x00, 0x20 };
-       const int mem_width_count = (dev_priv->chipset >= 0x17 ? 3 : 2);
-       uint32_t patt = 0xdeadbeef;
-       struct io_mapping *fb;
-       int i, j, k;
-       /* Map the framebuffer aperture */
-       fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1),
-                                 pci_resource_len(dev->pdev, 1));
-       if (!fb)
-               return -ENOMEM;
-       bios_wr32(bios, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1);
-       /* Probe memory bus width */
-       for (i = 0; i < mem_width_count; i++) {
-               bios_md32(bios, NV04_PFB_CFG0, 0x30, mem_width[i]);
-               for (j = 0; j < 4; j++) {
-                       for (k = 0; k < 4; k++)
-                               poke_fb(dev, fb, 0x1c, 0);
-                       poke_fb(dev, fb, 0x1c, patt);
-                       poke_fb(dev, fb, 0x3c, 0);
-                       if (peek_fb(dev, fb, 0x1c) == patt)
-                               goto mem_width_found;
-               }
-       }
- mem_width_found:
-       patt <<= 1;
-       /* Probe amount of installed memory */
-       for (i = 0; i < 4; i++) {
-               int off = bios_rd32(bios, NV04_PFB_FIFO_DATA) - 0x100000;
-               poke_fb(dev, fb, off, patt);
-               poke_fb(dev, fb, 0, 0);
-               peek_fb(dev, fb, 0);
-               peek_fb(dev, fb, 0);
-               peek_fb(dev, fb, 0);
-               peek_fb(dev, fb, 0);
-               if (peek_fb(dev, fb, off) == patt)
-                       goto amount_found;
-       }
-       /* IC missing - disable the upper half memory space. */
-       bios_md32(bios, NV04_PFB_CFG0, 0x1000, 0);
- amount_found:
-       io_mapping_free(fb);
-       return 0;
- }
- static int
- nv20_init_compute_mem(struct nvbios *bios)
- {
-       struct drm_device *dev = bios->dev;
-       struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
-       uint32_t mask = (dev_priv->chipset >= 0x25 ? 0x300 : 0x900);
-       uint32_t amount, off;
-       struct io_mapping *fb;
-       /* Map the framebuffer aperture */
-       fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1),
-                                 pci_resource_len(dev->pdev, 1));
-       if (!fb)
-               return -ENOMEM;
-       bios_wr32(bios, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1);
-       /* Allow full addressing */
-       bios_md32(bios, NV04_PFB_CFG0, 0, mask);
-       amount = bios_rd32(bios, NV04_PFB_FIFO_DATA);
-       for (off = amount; off > 0x2000000; off -= 0x2000000)
-               poke_fb(dev, fb, off - 4, off);
-       amount = bios_rd32(bios, NV04_PFB_FIFO_DATA);
-       if (amount != peek_fb(dev, fb, amount - 4))
-               /* IC missing - disable the upper half memory space. */
-               bios_md32(bios, NV04_PFB_CFG0, mask, 0);
-       io_mapping_free(fb);
-       return 0;
- }
- static int
- init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_COMPUTE_MEM   opcode: 0x63 ('c')
-        *
-        * offset      (8 bit): opcode
-        *
-        * This opcode is meant to set the PFB memory config registers
-        * appropriately so that we can correctly calculate how much VRAM it
-        * has (on nv10 and better chipsets the amount of installed VRAM is
-        * subsequently reported in NV_PFB_CSTATUS (0x10020C)).
-        *
-        * The implementation of this opcode in general consists of several
-        * parts:
-        *
-        * 1) Determination of memory type and density. Only necessary for
-        *    really old chipsets, the memory type reported by the strap bits
-        *    (0x101000) is assumed to be accurate on nv05 and newer.
-        *
-        * 2) Determination of the memory bus width. Usually done by a cunning
-        *    combination of writes to offsets 0x1c and 0x3c in the fb, and
-        *    seeing whether the written values are read back correctly.
-        *
-        *    Only necessary on nv0x-nv1x and nv34, on the other cards we can
-        *    trust the straps.
-        *
-        * 3) Determination of how many of the card's RAM pads have ICs
-        *    attached, usually done by a cunning combination of writes to an
-        *    offset slightly less than the maximum memory reported by
-        *    NV_PFB_CSTATUS, then seeing if the test pattern can be read back.
-        *
-        * This appears to be a NOP on IGPs and NV4x or newer chipsets, both io
-        * logs of the VBIOS and kmmio traces of the binary driver POSTing the
-        * card show nothing being done for this opcode. Why is it still listed
-        * in the table?!
-        */
-       /* no iexec->execute check by design */
-       struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
-       int ret;
-       if (dev_priv->chipset >= 0x40 ||
-           dev_priv->chipset == 0x1a ||
-           dev_priv->chipset == 0x1f)
-               ret = 0;
-       else if (dev_priv->chipset >= 0x20 &&
-                dev_priv->chipset != 0x34)
-               ret = nv20_init_compute_mem(bios);
-       else if (dev_priv->chipset >= 0x10)
-               ret = nv10_init_compute_mem(bios);
-       else if (dev_priv->chipset >= 0x5)
-               ret = nv05_init_compute_mem(bios);
-       else
-               ret = nv04_init_compute_mem(bios);
-       if (ret)
-               return ret;
-       return 1;
- }
- static int
- init_reset(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_RESET   opcode: 0x65 ('e')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): register
-        * offset + 5  (32 bit): value1
-        * offset + 9  (32 bit): value2
-        *
-        * Assign "value1" to "register", then assign "value2" to "register"
-        */
-       uint32_t reg = ROM32(bios->data[offset + 1]);
-       uint32_t value1 = ROM32(bios->data[offset + 5]);
-       uint32_t value2 = ROM32(bios->data[offset + 9]);
-       uint32_t pci_nv_19, pci_nv_20;
-       /* no iexec->execute check by design */
-       pci_nv_19 = bios_rd32(bios, NV_PBUS_PCI_NV_19);
-       bios_wr32(bios, NV_PBUS_PCI_NV_19, pci_nv_19 & ~0xf00);
-       bios_wr32(bios, reg, value1);
-       udelay(10);
-       bios_wr32(bios, reg, value2);
-       bios_wr32(bios, NV_PBUS_PCI_NV_19, pci_nv_19);
-       pci_nv_20 = bios_rd32(bios, NV_PBUS_PCI_NV_20);
-       pci_nv_20 &= ~NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED;     /* 0xfffffffe */
-       bios_wr32(bios, NV_PBUS_PCI_NV_20, pci_nv_20);
-       return 13;
- }
- static int
- init_configure_mem(struct nvbios *bios, uint16_t offset,
-                  struct init_exec *iexec)
- {
-       /*
-        * INIT_CONFIGURE_MEM   opcode: 0x66 ('f')
-        *
-        * offset      (8 bit): opcode
-        *
-        * Equivalent to INIT_DONE on bios version 3 or greater.
-        * For early bios versions, sets up the memory registers, using values
-        * taken from the memory init table
-        */
-       /* no iexec->execute check by design */
-       uint16_t meminitoffs = bios->legacy.mem_init_tbl_ptr + MEM_INIT_SIZE * (bios_idxprt_rd(bios, NV_CIO_CRX__COLOR, NV_CIO_CRE_SCRATCH4__INDEX) >> 4);
-       uint16_t seqtbloffs = bios->legacy.sdr_seq_tbl_ptr, meminitdata = meminitoffs + 6;
-       uint32_t reg, data;
-       if (bios->major_version > 2)
-               return 0;
-       bios_idxprt_wr(bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX, bios_idxprt_rd(
-                      bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX) | 0x20);
-       if (bios->data[meminitoffs] & 1)
-               seqtbloffs = bios->legacy.ddr_seq_tbl_ptr;
-       for (reg = ROM32(bios->data[seqtbloffs]);
-            reg != 0xffffffff;
-            reg = ROM32(bios->data[seqtbloffs += 4])) {
-               switch (reg) {
-               case NV04_PFB_PRE:
-                       data = NV04_PFB_PRE_CMD_PRECHARGE;
-                       break;
-               case NV04_PFB_PAD:
-                       data = NV04_PFB_PAD_CKE_NORMAL;
-                       break;
-               case NV04_PFB_REF:
-                       data = NV04_PFB_REF_CMD_REFRESH;
-                       break;
-               default:
-                       data = ROM32(bios->data[meminitdata]);
-                       meminitdata += 4;
-                       if (data == 0xffffffff)
-                               continue;
-               }
-               bios_wr32(bios, reg, data);
-       }
-       return 1;
- }
- static int
- init_configure_clk(struct nvbios *bios, uint16_t offset,
-                  struct init_exec *iexec)
- {
-       /*
-        * INIT_CONFIGURE_CLK   opcode: 0x67 ('g')
-        *
-        * offset      (8 bit): opcode
-        *
-        * Equivalent to INIT_DONE on bios version 3 or greater.
-        * For early bios versions, sets up the NVClk and MClk PLLs, using
-        * values taken from the memory init table
-        */
-       /* no iexec->execute check by design */
-       uint16_t meminitoffs = bios->legacy.mem_init_tbl_ptr + MEM_INIT_SIZE * (bios_idxprt_rd(bios, NV_CIO_CRX__COLOR, NV_CIO_CRE_SCRATCH4__INDEX) >> 4);
-       int clock;
-       if (bios->major_version > 2)
-               return 0;
-       clock = ROM16(bios->data[meminitoffs + 4]) * 10;
-       setPLL(bios, NV_PRAMDAC_NVPLL_COEFF, clock);
-       clock = ROM16(bios->data[meminitoffs + 2]) * 10;
-       if (bios->data[meminitoffs] & 1) /* DDR */
-               clock *= 2;
-       setPLL(bios, NV_PRAMDAC_MPLL_COEFF, clock);
-       return 1;
- }
- static int
- init_configure_preinit(struct nvbios *bios, uint16_t offset,
-                      struct init_exec *iexec)
- {
-       /*
-        * INIT_CONFIGURE_PREINIT   opcode: 0x68 ('h')
-        *
-        * offset      (8 bit): opcode
-        *
-        * Equivalent to INIT_DONE on bios version 3 or greater.
-        * For early bios versions, does early init, loading ram and crystal
-        * configuration from straps into CR3C
-        */
-       /* no iexec->execute check by design */
-       uint32_t straps = bios_rd32(bios, NV_PEXTDEV_BOOT_0);
-       uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & 0x40) >> 6;
-       if (bios->major_version > 2)
-               return 0;
-       bios_idxprt_wr(bios, NV_CIO_CRX__COLOR,
-                            NV_CIO_CRE_SCRATCH4__INDEX, cr3c);
-       return 1;
- }
- static int
- init_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_IO   opcode: 0x69 ('i')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (16 bit): CRTC port
-        * offset + 3  (8  bit): mask
-        * offset + 4  (8  bit): data
-        *
-        * Assign ((IOVAL("crtc port") & "mask") | "data") to "crtc port"
-        */
-       struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
-       uint16_t crtcport = ROM16(bios->data[offset + 1]);
-       uint8_t mask = bios->data[offset + 3];
-       uint8_t data = bios->data[offset + 4];
-       if (!iexec->execute)
-               return 5;
-       BIOSLOG(bios, "0x%04X: Port: 0x%04X, Mask: 0x%02X, Data: 0x%02X\n",
-               offset, crtcport, mask, data);
-       /*
-        * I have no idea what this does, but NVIDIA do this magic sequence
-        * in the places where this INIT_IO happens..
-        */
-       if (dev_priv->card_type >= NV_50 && crtcport == 0x3c3 && data == 1) {
-               int i;
-               bios_wr32(bios, 0x614100, (bios_rd32(
-                         bios, 0x614100) & 0x0fffffff) | 0x00800000);
-               bios_wr32(bios, 0x00e18c, bios_rd32(
-                         bios, 0x00e18c) | 0x00020000);
-               bios_wr32(bios, 0x614900, (bios_rd32(
-                         bios, 0x614900) & 0x0fffffff) | 0x00800000);
-               bios_wr32(bios, 0x000200, bios_rd32(
-                         bios, 0x000200) & ~0x40000000);
-               mdelay(10);
-               bios_wr32(bios, 0x00e18c, bios_rd32(
-                         bios, 0x00e18c) & ~0x00020000);
-               bios_wr32(bios, 0x000200, bios_rd32(
-                         bios, 0x000200) | 0x40000000);
-               bios_wr32(bios, 0x614100, 0x00800018);
-               bios_wr32(bios, 0x614900, 0x00800018);
-               mdelay(10);
-               bios_wr32(bios, 0x614100, 0x10000018);
-               bios_wr32(bios, 0x614900, 0x10000018);
-               for (i = 0; i < 3; i++)
-                       bios_wr32(bios, 0x614280 + (i*0x800), bios_rd32(
-                                 bios, 0x614280 + (i*0x800)) & 0xf0f0f0f0);
-               for (i = 0; i < 2; i++)
-                       bios_wr32(bios, 0x614300 + (i*0x800), bios_rd32(
-                                 bios, 0x614300 + (i*0x800)) & 0xfffff0f0);
-               for (i = 0; i < 3; i++)
-                       bios_wr32(bios, 0x614380 + (i*0x800), bios_rd32(
-                                 bios, 0x614380 + (i*0x800)) & 0xfffff0f0);
-               for (i = 0; i < 2; i++)
-                       bios_wr32(bios, 0x614200 + (i*0x800), bios_rd32(
-                                 bios, 0x614200 + (i*0x800)) & 0xfffffff0);
-               for (i = 0; i < 2; i++)
-                       bios_wr32(bios, 0x614108 + (i*0x800), bios_rd32(
-                                 bios, 0x614108 + (i*0x800)) & 0x0fffffff);
-               return 5;
-       }
-       bios_port_wr(bios, crtcport, (bios_port_rd(bios, crtcport) & mask) |
-                                                                       data);
-       return 5;
- }
- static int
- init_sub(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_SUB   opcode: 0x6B ('k')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): script number
-        *
-        * Execute script number "script number", as a subroutine
-        */
-       uint8_t sub = bios->data[offset + 1];
-       if (!iexec->execute)
-               return 2;
-       BIOSLOG(bios, "0x%04X: Calling script %d\n", offset, sub);
-       parse_init_table(bios,
-                        ROM16(bios->data[bios->init_script_tbls_ptr + sub * 2]),
-                        iexec);
-       BIOSLOG(bios, "0x%04X: End of script %d\n", offset, sub);
-       return 2;
- }
- static int
- init_ram_condition(struct nvbios *bios, uint16_t offset,
-                  struct init_exec *iexec)
- {
-       /*
-        * INIT_RAM_CONDITION   opcode: 0x6D ('m')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): mask
-        * offset + 2  (8 bit): cmpval
-        *
-        * Test if (NV04_PFB_BOOT_0 & "mask") equals "cmpval".
-        * If condition not met skip subsequent opcodes until condition is
-        * inverted (INIT_NOT), or we hit INIT_RESUME
-        */
-       uint8_t mask = bios->data[offset + 1];
-       uint8_t cmpval = bios->data[offset + 2];
-       uint8_t data;
-       if (!iexec->execute)
-               return 3;
-       data = bios_rd32(bios, NV04_PFB_BOOT_0) & mask;
-       BIOSLOG(bios, "0x%04X: Checking if 0x%08X equals 0x%08X\n",
-               offset, data, cmpval);
-       if (data == cmpval)
-               BIOSLOG(bios, "0x%04X: Condition fulfilled -- continuing to execute\n", offset);
-       else {
-               BIOSLOG(bios, "0x%04X: Condition not fulfilled -- skipping following commands\n", offset);
-               iexec->execute = false;
-       }
-       return 3;
- }
- static int
- init_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_NV_REG   opcode: 0x6E ('n')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): register
-        * offset + 5  (32 bit): mask
-        * offset + 9  (32 bit): data
-        *
-        * Assign ((REGVAL("register") & "mask") | "data") to "register"
-        */
-       uint32_t reg = ROM32(bios->data[offset + 1]);
-       uint32_t mask = ROM32(bios->data[offset + 5]);
-       uint32_t data = ROM32(bios->data[offset + 9]);
-       if (!iexec->execute)
-               return 13;
-       BIOSLOG(bios, "0x%04X: Reg: 0x%08X, Mask: 0x%08X, Data: 0x%08X\n",
-               offset, reg, mask, data);
-       bios_wr32(bios, reg, (bios_rd32(bios, reg) & mask) | data);
-       return 13;
- }
- static int
- init_macro(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_MACRO   opcode: 0x6F ('o')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): macro number
-        *
-        * Look up macro index "macro number" in the macro index table.
-        * The macro index table entry has 1 byte for the index in the macro
-        * table, and 1 byte for the number of times to repeat the macro.
-        * The macro table entry has 4 bytes for the register address and
-        * 4 bytes for the value to write to that register
-        */
-       uint8_t macro_index_tbl_idx = bios->data[offset + 1];
-       uint16_t tmp = bios->macro_index_tbl_ptr + (macro_index_tbl_idx * MACRO_INDEX_SIZE);
-       uint8_t macro_tbl_idx = bios->data[tmp];
-       uint8_t count = bios->data[tmp + 1];
-       uint32_t reg, data;
-       int i;
-       if (!iexec->execute)
-               return 2;
-       BIOSLOG(bios, "0x%04X: Macro: 0x%02X, MacroTableIndex: 0x%02X, "
-                     "Count: 0x%02X\n",
-               offset, macro_index_tbl_idx, macro_tbl_idx, count);
-       for (i = 0; i < count; i++) {
-               uint16_t macroentryptr = bios->macro_tbl_ptr + (macro_tbl_idx + i) * MACRO_SIZE;
-               reg = ROM32(bios->data[macroentryptr]);
-               data = ROM32(bios->data[macroentryptr + 4]);
-               bios_wr32(bios, reg, data);
-       }
-       return 2;
- }
- static int
- init_done(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_DONE   opcode: 0x71 ('q')
-        *
-        * offset      (8  bit): opcode
-        *
-        * End the current script
-        */
-       /* mild retval abuse to stop parsing this table */
-       return 0;
- }
- static int
- init_resume(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_RESUME   opcode: 0x72 ('r')
-        *
-        * offset      (8  bit): opcode
-        *
-        * End the current execute / no-execute condition
-        */
-       if (iexec->execute)
-               return 1;
-       iexec->execute = true;
-       BIOSLOG(bios, "0x%04X: ---- Executing following commands ----\n", offset);
-       return 1;
- }
- static int
- init_time(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_TIME   opcode: 0x74 ('t')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (16 bit): time
-        *
-        * Sleep for "time" microseconds.
-        */
-       unsigned time = ROM16(bios->data[offset + 1]);
-       if (!iexec->execute)
-               return 3;
-       BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X microseconds\n",
-               offset, time);
-       if (time < 1000)
-               udelay(time);
-       else
-               mdelay((time + 900) / 1000);
-       return 3;
- }
- static int
- init_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_CONDITION   opcode: 0x75 ('u')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): condition number
-        *
-        * Check condition "condition number" in the condition table.
-        * If condition not met skip subsequent opcodes until condition is
-        * inverted (INIT_NOT), or we hit INIT_RESUME
-        */
-       uint8_t cond = bios->data[offset + 1];
-       if (!iexec->execute)
-               return 2;
-       BIOSLOG(bios, "0x%04X: Condition: 0x%02X\n", offset, cond);
-       if (bios_condition_met(bios, offset, cond))
-               BIOSLOG(bios, "0x%04X: Condition fulfilled -- continuing to execute\n", offset);
-       else {
-               BIOSLOG(bios, "0x%04X: Condition not fulfilled -- skipping following commands\n", offset);
-               iexec->execute = false;
-       }
-       return 2;
- }
- static int
- init_io_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_IO_CONDITION  opcode: 0x76
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): condition number
-        *
-        * Check condition "condition number" in the io condition table.
-        * If condition not met skip subsequent opcodes until condition is
-        * inverted (INIT_NOT), or we hit INIT_RESUME
-        */
-       uint8_t cond = bios->data[offset + 1];
-       if (!iexec->execute)
-               return 2;
-       BIOSLOG(bios, "0x%04X: IO condition: 0x%02X\n", offset, cond);
-       if (io_condition_met(bios, offset, cond))
-               BIOSLOG(bios, "0x%04X: Condition fulfilled -- continuing to execute\n", offset);
-       else {
-               BIOSLOG(bios, "0x%04X: Condition not fulfilled -- skipping following commands\n", offset);
-               iexec->execute = false;
-       }
-       return 2;
- }
- static int
- init_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_INDEX_IO   opcode: 0x78 ('x')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (16 bit): CRTC port
-        * offset + 3  (8  bit): CRTC index
-        * offset + 4  (8  bit): mask
-        * offset + 5  (8  bit): data
-        *
-        * Read value at index "CRTC index" on "CRTC port", AND with "mask",
-        * OR with "data", write-back
-        */
-       uint16_t crtcport = ROM16(bios->data[offset + 1]);
-       uint8_t crtcindex = bios->data[offset + 3];
-       uint8_t mask = bios->data[offset + 4];
-       uint8_t data = bios->data[offset + 5];
-       uint8_t value;
-       if (!iexec->execute)
-               return 6;
-       BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
-                     "Data: 0x%02X\n",
-               offset, crtcport, crtcindex, mask, data);
-       value = (bios_idxprt_rd(bios, crtcport, crtcindex) & mask) | data;
-       bios_idxprt_wr(bios, crtcport, crtcindex, value);
-       return 6;
- }
- static int
- init_pll(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_PLL   opcode: 0x79 ('y')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): register
-        * offset + 5  (16 bit): freq
-        *
-        * Set PLL register "register" to coefficients for frequency (10kHz)
-        * "freq"
-        */
-       uint32_t reg = ROM32(bios->data[offset + 1]);
-       uint16_t freq = ROM16(bios->data[offset + 5]);
-       if (!iexec->execute)
-               return 7;
-       BIOSLOG(bios, "0x%04X: Reg: 0x%08X, Freq: %d0kHz\n", offset, reg, freq);
-       setPLL(bios, reg, freq * 10);
-       return 7;
- }
- static int
- init_zm_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_ZM_REG   opcode: 0x7A ('z')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): register
-        * offset + 5  (32 bit): value
-        *
-        * Assign "value" to "register"
-        */
-       uint32_t reg = ROM32(bios->data[offset + 1]);
-       uint32_t value = ROM32(bios->data[offset + 5]);
-       if (!iexec->execute)
-               return 9;
-       if (reg == 0x000200)
-               value |= 1;
-       bios_wr32(bios, reg, value);
-       return 9;
- }
- static int
- init_ram_restrict_pll(struct nvbios *bios, uint16_t offset,
-                     struct init_exec *iexec)
- {
-       /*
-        * INIT_RAM_RESTRICT_PLL   opcode: 0x87 ('')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): PLL type
-        * offset + 2 (32 bit): frequency 0
-        *
-        * Uses the RAMCFG strap of PEXTDEV_BOOT as an index into the table at
-        * ram_restrict_table_ptr.  The value read from there is used to select
-        * a frequency from the table starting at 'frequency 0' to be
-        * programmed into the PLL corresponding to 'type'.
-        *
-        * The PLL limits table on cards using this opcode has a mapping of
-        * 'type' to the relevant registers.
-        */
-       struct drm_device *dev = bios->dev;
-       uint32_t strap = (bios_rd32(bios, NV_PEXTDEV_BOOT_0) & 0x0000003c) >> 2;
-       uint8_t index = bios->data[bios->ram_restrict_tbl_ptr + strap];
-       uint8_t type = bios->data[offset + 1];
-       uint32_t freq = ROM32(bios->data[offset + 2 + (index * 4)]);
-       uint8_t *pll_limits = &bios->data[bios->pll_limit_tbl_ptr], *entry;
-       int len = 2 + bios->ram_restrict_group_count * 4;
-       int i;
-       if (!iexec->execute)
-               return len;
-       if (!bios->pll_limit_tbl_ptr || (pll_limits[0] & 0xf0) != 0x30) {
-               NV_ERROR(dev, "PLL limits table not version 3.x\n");
-               return len; /* deliberate, allow default clocks to remain */
-       }
-       entry = pll_limits + pll_limits[1];
-       for (i = 0; i < pll_limits[3]; i++, entry += pll_limits[2]) {
-               if (entry[0] == type) {
-                       uint32_t reg = ROM32(entry[3]);
-                       BIOSLOG(bios, "0x%04X: "
-                                     "Type %02x Reg 0x%08x Freq %dKHz\n",
-                               offset, type, reg, freq);
-                       setPLL(bios, reg, freq);
-                       return len;
-               }
-       }
-       NV_ERROR(dev, "PLL type 0x%02x not found in PLL limits table", type);
-       return len;
- }
- static int
- init_8c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_8C   opcode: 0x8C ('')
-        *
-        * NOP so far....
-        *
-        */
-       return 1;
- }
- static int
- init_8d(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_8D   opcode: 0x8D ('')
-        *
-        * NOP so far....
-        *
-        */
-       return 1;
- }
- static int
- init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_GPIO   opcode: 0x8E ('')
-        *
-        * offset      (8 bit): opcode
-        *
-        * Loop over all entries in the DCB GPIO table, and initialise
-        * each GPIO according to various values listed in each entry
-        */
-       if (iexec->execute && bios->execute)
-               nouveau_gpio_reset(bios->dev);
-       return 1;
- }
- static int
- init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset,
-                              struct init_exec *iexec)
- {
-       /*
-        * INIT_RAM_RESTRICT_ZM_REG_GROUP   opcode: 0x8F ('')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): reg
-        * offset + 5  (8  bit): regincrement
-        * offset + 6  (8  bit): count
-        * offset + 7  (32 bit): value 1,1
-        * ...
-        *
-        * Use the RAMCFG strap of PEXTDEV_BOOT as an index into the table at
-        * ram_restrict_table_ptr. The value read from here is 'n', and
-        * "value 1,n" gets written to "reg". This repeats "count" times and on
-        * each iteration 'm', "reg" increases by "regincrement" and
-        * "value m,n" is used. The extent of n is limited by a number read
-        * from the 'M' BIT table, herein called "blocklen"
-        */
-       uint32_t reg = ROM32(bios->data[offset + 1]);
-       uint8_t regincrement = bios->data[offset + 5];
-       uint8_t count = bios->data[offset + 6];
-       uint32_t strap_ramcfg, data;
-       /* previously set by 'M' BIT table */
-       uint16_t blocklen = bios->ram_restrict_group_count * 4;
-       int len = 7 + count * blocklen;
-       uint8_t index;
-       int i;
-       /* critical! to know the length of the opcode */;
-       if (!blocklen) {
-               NV_ERROR(bios->dev,
-                        "0x%04X: Zero block length - has the M table "
-                        "been parsed?\n", offset);
-               return -EINVAL;
-       }
-       if (!iexec->execute)
-               return len;
-       strap_ramcfg = (bios_rd32(bios, NV_PEXTDEV_BOOT_0) >> 2) & 0xf;
-       index = bios->data[bios->ram_restrict_tbl_ptr + strap_ramcfg];
-       BIOSLOG(bios, "0x%04X: Reg: 0x%08X, RegIncrement: 0x%02X, "
-                     "Count: 0x%02X, StrapRamCfg: 0x%02X, Index: 0x%02X\n",
-               offset, reg, regincrement, count, strap_ramcfg, index);
-       for (i = 0; i < count; i++) {
-               data = ROM32(bios->data[offset + 7 + index * 4 + blocklen * i]);
-               bios_wr32(bios, reg, data);
-               reg += regincrement;
-       }
-       return len;
- }
- static int
- init_copy_zm_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_COPY_ZM_REG   opcode: 0x90 ('')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): src reg
-        * offset + 5  (32 bit): dst reg
-        *
-        * Put contents of "src reg" into "dst reg"
-        */
-       uint32_t srcreg = ROM32(bios->data[offset + 1]);
-       uint32_t dstreg = ROM32(bios->data[offset + 5]);
-       if (!iexec->execute)
-               return 9;
-       bios_wr32(bios, dstreg, bios_rd32(bios, srcreg));
-       return 9;
- }
- static int
- init_zm_reg_group_addr_latched(struct nvbios *bios, uint16_t offset,
-                              struct init_exec *iexec)
- {
-       /*
-        * INIT_ZM_REG_GROUP_ADDRESS_LATCHED   opcode: 0x91 ('')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): dst reg
-        * offset + 5  (8  bit): count
-        * offset + 6  (32 bit): data 1
-        * ...
-        *
-        * For each of "count" values write "data n" to "dst reg"
-        */
-       uint32_t reg = ROM32(bios->data[offset + 1]);
-       uint8_t count = bios->data[offset + 5];
-       int len = 6 + count * 4;
-       int i;
-       if (!iexec->execute)
-               return len;
-       for (i = 0; i < count; i++) {
-               uint32_t data = ROM32(bios->data[offset + 6 + 4 * i]);
-               bios_wr32(bios, reg, data);
-       }
-       return len;
- }
- static int
- init_reserved(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_RESERVED   opcode: 0x92 ('')
-        *
-        * offset      (8 bit): opcode
-        *
-        * Seemingly does nothing
-        */
-       return 1;
- }
- static int
- init_96(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_96   opcode: 0x96 ('')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): sreg
-        * offset + 5  (8  bit): sshift
-        * offset + 6  (8  bit): smask
-        * offset + 7  (8  bit): index
-        * offset + 8  (32 bit): reg
-        * offset + 12 (32 bit): mask
-        * offset + 16 (8  bit): shift
-        *
-        */
-       uint16_t xlatptr = bios->init96_tbl_ptr + (bios->data[offset + 7] * 2);
-       uint32_t reg = ROM32(bios->data[offset + 8]);
-       uint32_t mask = ROM32(bios->data[offset + 12]);
-       uint32_t val;
-       val = bios_rd32(bios, ROM32(bios->data[offset + 1]));
-       if (bios->data[offset + 5] < 0x80)
-               val >>= bios->data[offset + 5];
-       else
-               val <<= (0x100 - bios->data[offset + 5]);
-       val &= bios->data[offset + 6];
-       val   = bios->data[ROM16(bios->data[xlatptr]) + val];
-       val <<= bios->data[offset + 16];
-       if (!iexec->execute)
-               return 17;
-       bios_wr32(bios, reg, (bios_rd32(bios, reg) & mask) | val);
-       return 17;
- }
- static int
- init_97(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_97   opcode: 0x97 ('')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): register
-        * offset + 5  (32 bit): mask
-        * offset + 9  (32 bit): value
-        *
-        * Adds "value" to "register" preserving the fields specified
-        * by "mask"
-        */
-       uint32_t reg = ROM32(bios->data[offset + 1]);
-       uint32_t mask = ROM32(bios->data[offset + 5]);
-       uint32_t add = ROM32(bios->data[offset + 9]);
-       uint32_t val;
-       val = bios_rd32(bios, reg);
-       val = (val & mask) | ((val + add) & ~mask);
-       if (!iexec->execute)
-               return 13;
-       bios_wr32(bios, reg, val);
-       return 13;
- }
+ #include <subdev/bios.h>
  
- static int
- init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_AUXCH   opcode: 0x98 ('')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): address
-        * offset + 5  (8  bit): count
-        * offset + 6  (8  bit): mask 0
-        * offset + 7  (8  bit): data 0
-        *  ...
-        *
-        */
-       struct drm_device *dev = bios->dev;
-       struct nouveau_i2c_chan *auxch;
-       uint32_t addr = ROM32(bios->data[offset + 1]);
-       uint8_t count = bios->data[offset + 5];
-       int len = 6 + count * 2;
-       int ret, i;
-       if (!bios->display.output) {
-               NV_ERROR(dev, "INIT_AUXCH: no active output\n");
-               return len;
-       }
-       auxch = init_i2c_device_find(dev, bios->display.output->i2c_index);
-       if (!auxch) {
-               NV_ERROR(dev, "INIT_AUXCH: couldn't get auxch %d\n",
-                        bios->display.output->i2c_index);
-               return len;
-       }
-       if (!iexec->execute)
-               return len;
-       offset += 6;
-       for (i = 0; i < count; i++, offset += 2) {
-               uint8_t data;
-               ret = nouveau_dp_auxch(auxch, 9, addr, &data, 1);
-               if (ret) {
-                       NV_ERROR(dev, "INIT_AUXCH: rd auxch fail %d\n", ret);
-                       return len;
-               }
-               data &= bios->data[offset + 0];
-               data |= bios->data[offset + 1];
-               ret = nouveau_dp_auxch(auxch, 8, addr, &data, 1);
-               if (ret) {
-                       NV_ERROR(dev, "INIT_AUXCH: wr auxch fail %d\n", ret);
-                       return len;
-               }
-       }
-       return len;
- }
- static int
- init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_ZM_AUXCH   opcode: 0x99 ('')
-        *
-        * offset      (8  bit): opcode
-        * offset + 1  (32 bit): address
-        * offset + 5  (8  bit): count
-        * offset + 6  (8  bit): data 0
-        *  ...
-        *
-        */
-       struct drm_device *dev = bios->dev;
-       struct nouveau_i2c_chan *auxch;
-       uint32_t addr = ROM32(bios->data[offset + 1]);
-       uint8_t count = bios->data[offset + 5];
-       int len = 6 + count;
-       int ret, i;
-       if (!bios->display.output) {
-               NV_ERROR(dev, "INIT_ZM_AUXCH: no active output\n");
-               return len;
-       }
-       auxch = init_i2c_device_find(dev, bios->display.output->i2c_index);
-       if (!auxch) {
-               NV_ERROR(dev, "INIT_ZM_AUXCH: couldn't get auxch %d\n",
-                        bios->display.output->i2c_index);
-               return len;
-       }
-       if (!iexec->execute)
-               return len;
-       offset += 6;
-       for (i = 0; i < count; i++, offset++) {
-               ret = nouveau_dp_auxch(auxch, 8, addr, &bios->data[offset], 1);
-               if (ret) {
-                       NV_ERROR(dev, "INIT_ZM_AUXCH: wr auxch fail %d\n", ret);
-                       return len;
-               }
-       }
-       return len;
- }
- static int
- init_i2c_long_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
- {
-       /*
-        * INIT_I2C_LONG_IF   opcode: 0x9A ('')
-        *
-        * offset      (8 bit): opcode
-        * offset + 1  (8 bit): DCB I2C table entry index
-        * offset + 2  (8 bit): I2C slave address
-        * offset + 3  (16 bit): I2C register
-        * offset + 5  (8 bit): mask
-        * offset + 6  (8 bit): data
-        *
-        * Read the register given by "I2C register" on the device addressed
-        * by "I2C slave address" on the I2C bus given by "DCB I2C table
-        * entry index". Compare the result AND "mask" to "data".
-        * If they're not equal, skip subsequent opcodes until condition is
-        * inverted (INIT_NOT), or we hit INIT_RESUME
-        */
-       uint8_t i2c_index = bios->data[offset + 1];
-       uint8_t i2c_address = bios->data[offset + 2] >> 1;
-       uint8_t reglo = bios->data[offset + 3];
-       uint8_t reghi = bios->data[offset + 4];
-       uint8_t mask = bios->data[offset + 5];
-       uint8_t data = bios->data[offset + 6];
-       struct nouveau_i2c_chan *chan;
-       uint8_t buf0[2] = { reghi, reglo };
-       uint8_t buf1[1];
-       struct i2c_msg msg[2] = {
-               { i2c_address, 0, 1, buf0 },
-               { i2c_address, I2C_M_RD, 1, buf1 },
-       };
-       int ret;
-       /* no execute check by design */
-       BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n",
-               offset, i2c_index, i2c_address);
-       chan = init_i2c_device_find(bios->dev, i2c_index);
-       if (!chan)
-               return -ENODEV;
 -#include "drmP.h"
++#include <drm/drmP.h>
 +
+ #include "nouveau_drm.h"
+ #include "nouveau_reg.h"
+ #include "nouveau_hw.h"
+ #include "nouveau_encoder.h"
  
-       ret = i2c_transfer(&chan->adapter, msg, 2);
-       if (ret < 0) {
-               BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: [no device], "
-                             "Mask: 0x%02X, Data: 0x%02X\n",
-                       offset, reghi, reglo, mask, data);
-               iexec->execute = 0;
-               return 7;
-       }
+ #include <linux/io-mapping.h>
+ #include <linux/firmware.h>
  
-       BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: 0x%02X, "
-                     "Mask: 0x%02X, Data: 0x%02X\n",
-               offset, reghi, reglo, buf1[0], mask, data);
+ /* these defines are made up */
+ #define NV_CIO_CRE_44_HEADA 0x0
+ #define NV_CIO_CRE_44_HEADB 0x3
+ #define FEATURE_MOBILE 0x10   /* also FEATURE_QUADRO for BMP */
  
-       iexec->execute = ((buf1[0] & mask) == data);
+ #define EDID1_LEN 128
  
-       return 7;
- }
+ #define BIOSLOG(sip, fmt, arg...) NV_DEBUG(sip->dev, fmt, ##arg)
+ #define LOG_OLD_VALUE(x)
  
- static struct init_tbl_entry itbl_entry[] = {
-       /* command name                       , id  , length  , offset  , mult    , command handler                 */
-       /* INIT_PROG (0x31, 15, 10, 4) removed due to no example of use */
-       { "INIT_IO_RESTRICT_PROG"             , 0x32, init_io_restrict_prog           },
-       { "INIT_REPEAT"                       , 0x33, init_repeat                     },
-       { "INIT_IO_RESTRICT_PLL"              , 0x34, init_io_restrict_pll            },
-       { "INIT_END_REPEAT"                   , 0x36, init_end_repeat                 },
-       { "INIT_COPY"                         , 0x37, init_copy                       },
-       { "INIT_NOT"                          , 0x38, init_not                        },
-       { "INIT_IO_FLAG_CONDITION"            , 0x39, init_io_flag_condition          },
-       { "INIT_DP_CONDITION"                 , 0x3A, init_dp_condition               },
-       { "INIT_OP_3B"                        , 0x3B, init_op_3b                      },
-       { "INIT_OP_3C"                        , 0x3C, init_op_3c                      },
-       { "INIT_INDEX_ADDRESS_LATCHED"        , 0x49, init_idx_addr_latched           },
-       { "INIT_IO_RESTRICT_PLL2"             , 0x4A, init_io_restrict_pll2           },
-       { "INIT_PLL2"                         , 0x4B, init_pll2                       },
-       { "INIT_I2C_BYTE"                     , 0x4C, init_i2c_byte                   },
-       { "INIT_ZM_I2C_BYTE"                  , 0x4D, init_zm_i2c_byte                },
-       { "INIT_ZM_I2C"                       , 0x4E, init_zm_i2c                     },
-       { "INIT_TMDS"                         , 0x4F, init_tmds                       },
-       { "INIT_ZM_TMDS_GROUP"                , 0x50, init_zm_tmds_group              },
-       { "INIT_CR_INDEX_ADDRESS_LATCHED"     , 0x51, init_cr_idx_adr_latch           },
-       { "INIT_CR"                           , 0x52, init_cr                         },
-       { "INIT_ZM_CR"                        , 0x53, init_zm_cr                      },
-       { "INIT_ZM_CR_GROUP"                  , 0x54, init_zm_cr_group                },
-       { "INIT_CONDITION_TIME"               , 0x56, init_condition_time             },
-       { "INIT_LTIME"                        , 0x57, init_ltime                      },
-       { "INIT_ZM_REG_SEQUENCE"              , 0x58, init_zm_reg_sequence            },
-       /* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */
-       { "INIT_SUB_DIRECT"                   , 0x5B, init_sub_direct                 },
-       { "INIT_JUMP"                         , 0x5C, init_jump                       },
-       { "INIT_I2C_IF"                       , 0x5E, init_i2c_if                     },
-       { "INIT_COPY_NV_REG"                  , 0x5F, init_copy_nv_reg                },
-       { "INIT_ZM_INDEX_IO"                  , 0x62, init_zm_index_io                },
-       { "INIT_COMPUTE_MEM"                  , 0x63, init_compute_mem                },
-       { "INIT_RESET"                        , 0x65, init_reset                      },
-       { "INIT_CONFIGURE_MEM"                , 0x66, init_configure_mem              },
-       { "INIT_CONFIGURE_CLK"                , 0x67, init_configure_clk              },
-       { "INIT_CONFIGURE_PREINIT"            , 0x68, init_configure_preinit          },
-       { "INIT_IO"                           , 0x69, init_io                         },
-       { "INIT_SUB"                          , 0x6B, init_sub                        },
-       { "INIT_RAM_CONDITION"                , 0x6D, init_ram_condition              },
-       { "INIT_NV_REG"                       , 0x6E, init_nv_reg                     },
-       { "INIT_MACRO"                        , 0x6F, init_macro                      },
-       { "INIT_DONE"                         , 0x71, init_done                       },
-       { "INIT_RESUME"                       , 0x72, init_resume                     },
-       /* INIT_RAM_CONDITION2 (0x73, 9, 0, 0) removed due to no example of use */
-       { "INIT_TIME"                         , 0x74, init_time                       },
-       { "INIT_CONDITION"                    , 0x75, init_condition                  },
-       { "INIT_IO_CONDITION"                 , 0x76, init_io_condition               },
-       { "INIT_INDEX_IO"                     , 0x78, init_index_io                   },
-       { "INIT_PLL"                          , 0x79, init_pll                        },
-       { "INIT_ZM_REG"                       , 0x7A, init_zm_reg                     },
-       { "INIT_RAM_RESTRICT_PLL"             , 0x87, init_ram_restrict_pll           },
-       { "INIT_8C"                           , 0x8C, init_8c                         },
-       { "INIT_8D"                           , 0x8D, init_8d                         },
-       { "INIT_GPIO"                         , 0x8E, init_gpio                       },
-       { "INIT_RAM_RESTRICT_ZM_REG_GROUP"    , 0x8F, init_ram_restrict_zm_reg_group  },
-       { "INIT_COPY_ZM_REG"                  , 0x90, init_copy_zm_reg                },
-       { "INIT_ZM_REG_GROUP_ADDRESS_LATCHED" , 0x91, init_zm_reg_group_addr_latched  },
-       { "INIT_RESERVED"                     , 0x92, init_reserved                   },
-       { "INIT_96"                           , 0x96, init_96                         },
-       { "INIT_97"                           , 0x97, init_97                         },
-       { "INIT_AUXCH"                        , 0x98, init_auxch                      },
-       { "INIT_ZM_AUXCH"                     , 0x99, init_zm_auxch                   },
-       { "INIT_I2C_LONG_IF"                  , 0x9A, init_i2c_long_if                },
-       { NULL                                , 0   , NULL                            }
+ struct init_exec {
+       bool execute;
+       bool repeat;
  };
  
- #define MAX_TABLE_OPS 1000
- static int
- parse_init_table(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+ static bool nv_cksum(const uint8_t *data, unsigned int length)
  {
        /*
-        * Parses all commands in an init table.
-        *
-        * We start out executing all commands found in the init table. Some
-        * opcodes may change the status of iexec->execute to SKIP, which will
-        * cause the following opcodes to perform no operation until the value
-        * is changed back to EXECUTE.
-        */
-       int count = 0, i, ret;
-       uint8_t id;
-       /* catch NULL script pointers */
-       if (offset == 0)
-               return 0;
-       /*
-        * Loop until INIT_DONE causes us to break out of the loop
-        * (or until offset > bios length just in case... )
-        * (and no more than MAX_TABLE_OPS iterations, just in case... )
+        * There's a few checksums in the BIOS, so here's a generic checking
+        * function.
         */
-       while ((offset < bios->length) && (count++ < MAX_TABLE_OPS)) {
-               id = bios->data[offset];
-               /* Find matching id in itbl_entry */
-               for (i = 0; itbl_entry[i].name && (itbl_entry[i].id != id); i++)
-                       ;
-               if (!itbl_entry[i].name) {
-                       NV_ERROR(bios->dev,
-                                "0x%04X: Init table command not found: "
-                                "0x%02X\n", offset, id);
-                       return -ENOENT;
-               }
-               BIOSLOG(bios, "0x%04X: [ (0x%02X) - %s ]\n", offset,
-                       itbl_entry[i].id, itbl_entry[i].name);
-               /* execute eventual command handler */
-               ret = (*itbl_entry[i].handler)(bios, offset, iexec);
-               if (ret < 0) {
-                       NV_ERROR(bios->dev, "0x%04X: Failed parsing init "
-                                "table opcode: %s %d\n", offset,
-                                itbl_entry[i].name, ret);
-               }
-               if (ret <= 0)
-                       break;
-               /*
-                * Add the offset of the current command including all data
-                * of that command. The offset will then be pointing on the
-                * next op code.
-                */
-               offset += ret;
-       }
-       if (offset >= bios->length)
-               NV_WARN(bios->dev,
-                       "Offset 0x%04X greater than known bios image length.  "
-                       "Corrupt image?\n", offset);
-       if (count >= MAX_TABLE_OPS)
-               NV_WARN(bios->dev,
-                       "More than %d opcodes to a table is unlikely, "
-                       "is the bios image corrupt?\n", MAX_TABLE_OPS);
-       return 0;
- }
- static void
- parse_init_tables(struct nvbios *bios)
- {
-       /* Loops and calls parse_init_table() for each present table. */
-       int i = 0;
-       uint16_t table;
-       struct init_exec iexec = {true, false};
-       if (bios->old_style_init) {
-               if (bios->init_script_tbls_ptr)
-                       parse_init_table(bios, bios->init_script_tbls_ptr, &iexec);
-               if (bios->extra_init_script_tbl_ptr)
-                       parse_init_table(bios, bios->extra_init_script_tbl_ptr, &iexec);
+       int i;
+       uint8_t sum = 0;
  
-               return;
-       }
+       for (i = 0; i < length; i++)
+               sum += data[i];
  
-       while ((table = ROM16(bios->data[bios->init_script_tbls_ptr + i]))) {
-               NV_INFO(bios->dev,
-                       "Parsing VBIOS init table %d at offset 0x%04X\n",
-                       i / 2, table);
-               BIOSLOG(bios, "0x%04X: ------ Executing following commands ------\n", table);
+       if (sum)
+               return true;
  
-               parse_init_table(bios, table, &iexec);
-               i += 2;
-       }
+       return false;
  }
  
  static uint16_t clkcmptable(struct nvbios *bios, uint16_t clktable, int pxclk)
  
  static void
  run_digital_op_script(struct drm_device *dev, uint16_t scriptptr,
-                     struct dcb_entry *dcbent, int head, bool dl)
+                     struct dcb_output *dcbent, int head, bool dl)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
-       struct init_exec iexec = {true, false};
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
-       NV_TRACE(dev, "0x%04X: Parsing digital output script table\n",
+       NV_INFO(drm, "0x%04X: Parsing digital output script table\n",
                 scriptptr);
-       bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, NV_CIO_CRE_44,
-                      head ? NV_CIO_CRE_44_HEADB : NV_CIO_CRE_44_HEADA);
-       /* note: if dcb entries have been merged, index may be misleading */
-       NVWriteVgaCrtc5758(dev, head, 0, dcbent->index);
-       parse_init_table(bios, scriptptr, &iexec);
+       NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_44, head ? NV_CIO_CRE_44_HEADB :
+                                                NV_CIO_CRE_44_HEADA);
+       nouveau_bios_run_init_table(dev, scriptptr, dcbent, head);
  
        nv04_dfp_bind_head(dev, dcbent, head, dl);
  }
  
- static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entry *dcbent, int head, enum LVDS_script script)
+ static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_output *dcbent, int head, enum LVDS_script script)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
-       uint8_t sub = bios->data[bios->fp.xlated_entry + script] + (bios->fp.link_c_increment && dcbent->or & OUTPUT_C ? 1 : 0);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
+       uint8_t sub = bios->data[bios->fp.xlated_entry + script] + (bios->fp.link_c_increment && dcbent->or & DCB_OUTPUT_C ? 1 : 0);
        uint16_t scriptofs = ROM16(bios->data[bios->init_script_tbls_ptr + sub * 2]);
  
        if (!bios->fp.xlated_entry || !sub || !scriptofs)
        return 0;
  }
  
- static int run_lvds_table(struct drm_device *dev, struct dcb_entry *dcbent, int head, enum LVDS_script script, int pxclk)
+ static int run_lvds_table(struct drm_device *dev, struct dcb_output *dcbent, int head, enum LVDS_script script, int pxclk)
  {
        /*
         * The BIT LVDS table's header has the information to setup the
         * conf byte. These tables are similar to the TMDS tables, consisting
         * of a list of pxclks and script pointers.
         */
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
        unsigned int outputset = (dcbent->or == 4) ? 1 : 0;
        uint16_t scriptptr = 0, clktable;
  
  
                clktable = ROM16(bios->data[clktable]);
                if (!clktable) {
-                       NV_ERROR(dev, "Pixel clock comparison table not found\n");
+                       NV_ERROR(drm, "Pixel clock comparison table not found\n");
                        return -ENOENT;
                }
                scriptptr = clkcmptable(bios, clktable, pxclk);
        }
  
        if (!scriptptr) {
-               NV_ERROR(dev, "LVDS output init script not found\n");
+               NV_ERROR(drm, "LVDS output init script not found\n");
                return -ENOENT;
        }
        run_digital_op_script(dev, scriptptr, dcbent, head, bios->fp.dual_link);
        return 0;
  }
  
- int call_lvds_script(struct drm_device *dev, struct dcb_entry *dcbent, int head, enum LVDS_script script, int pxclk)
+ int call_lvds_script(struct drm_device *dev, struct dcb_output *dcbent, int head, enum LVDS_script script, int pxclk)
  {
        /*
         * LVDS operations are multiplexed in an effort to present a single API
         * This acts as the demux
         */
  
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nv_device(drm->device);
+       struct nvbios *bios = &drm->vbios;
        uint8_t lvds_ver = bios->data[bios->fp.lvdsmanufacturerpointer];
        uint32_t sel_clk_binding, sel_clk;
        int ret;
        if (script == LVDS_RESET && bios->fp.power_off_for_reset)
                call_lvds_script(dev, dcbent, head, LVDS_PANEL_OFF, pxclk);
  
-       NV_TRACE(dev, "Calling LVDS script %d:\n", script);
+       NV_INFO(drm, "Calling LVDS script %d:\n", script);
  
        /* don't let script change pll->head binding */
-       sel_clk_binding = bios_rd32(bios, NV_PRAMDAC_SEL_CLK) & 0x50000;
+       sel_clk_binding = nv_rd32(device, NV_PRAMDAC_SEL_CLK) & 0x50000;
  
        if (lvds_ver < 0x30)
                ret = call_lvds_manufacturer_script(dev, dcbent, head, script);
        sel_clk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK) & ~0x50000;
        NVWriteRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK, sel_clk | sel_clk_binding);
        /* some scripts set a value in NV_PBUS_POWERCTRL_2 and break video overlay */
-       nvWriteMC(dev, NV_PBUS_POWERCTRL_2, 0);
+       nv_wr32(device, NV_PBUS_POWERCTRL_2, 0);
  
        return ret;
  }
@@@ -3942,12 -269,13 +270,13 @@@ static int parse_lvds_manufacturer_tabl
         * the maximum number of records that can be held in the table.
         */
  
+       struct nouveau_drm *drm = nouveau_drm(dev);
        uint8_t lvds_ver, headerlen, recordlen;
  
        memset(lth, 0, sizeof(struct lvdstableheader));
  
        if (bios->fp.lvdsmanufacturerpointer == 0x0) {
-               NV_ERROR(dev, "Pointer to LVDS manufacturer table invalid\n");
+               NV_ERROR(drm, "Pointer to LVDS manufacturer table invalid\n");
                return -EINVAL;
        }
  
        case 0x30:      /* NV4x */
                headerlen = bios->data[bios->fp.lvdsmanufacturerpointer + 1];
                if (headerlen < 0x1f) {
-                       NV_ERROR(dev, "LVDS table header not understood\n");
+                       NV_ERROR(drm, "LVDS table header not understood\n");
                        return -EINVAL;
                }
                recordlen = bios->data[bios->fp.lvdsmanufacturerpointer + 2];
        case 0x40:      /* G80/G90 */
                headerlen = bios->data[bios->fp.lvdsmanufacturerpointer + 1];
                if (headerlen < 0x7) {
-                       NV_ERROR(dev, "LVDS table header not understood\n");
+                       NV_ERROR(drm, "LVDS table header not understood\n");
                        return -EINVAL;
                }
                recordlen = bios->data[bios->fp.lvdsmanufacturerpointer + 2];
                break;
        default:
-               NV_ERROR(dev,
+               NV_ERROR(drm,
                         "LVDS table revision %d.%d not currently supported\n",
                         lvds_ver >> 4, lvds_ver & 0xf);
                return -ENOSYS;
  static int
  get_fp_strap(struct drm_device *dev, struct nvbios *bios)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
  
        /*
         * The fp strap is normally dictated by the "User Strap" in
        if (bios->major_version < 5 && bios->data[0x48] & 0x4)
                return NVReadVgaCrtc5758(dev, 0, 0xf) & 0xf;
  
-       if (dev_priv->card_type >= NV_50)
-               return (bios_rd32(bios, NV_PEXTDEV_BOOT_0) >> 24) & 0xf;
+       if (device->card_type >= NV_50)
+               return (nv_rd32(device, NV_PEXTDEV_BOOT_0) >> 24) & 0xf;
        else
-               return (bios_rd32(bios, NV_PEXTDEV_BOOT_0) >> 16) & 0xf;
+               return (nv_rd32(device, NV_PEXTDEV_BOOT_0) >> 16) & 0xf;
  }
  
  static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        uint8_t *fptable;
        uint8_t fptable_ver, headerlen = 0, recordlen, fpentries = 0xf, fpindex;
        int ret, ofs, fpstrapping;
                /* Apple cards don't have the fp table; the laptops use DDC */
                /* The table is also missing on some x86 IGPs */
  #ifndef __powerpc__
-               NV_ERROR(dev, "Pointer to flat panel table invalid\n");
+               NV_ERROR(drm, "Pointer to flat panel table invalid\n");
  #endif
                bios->digital_min_front_porch = 0x4b;
                return 0;
                ofs = -7;
                break;
        default:
-               NV_ERROR(dev,
+               NV_ERROR(drm,
                         "FP table revision %d.%d not currently supported\n",
                         fptable_ver >> 4, fptable_ver & 0xf);
                return -ENOSYS;
                bios->fp.xlatwidth = lth.recordlen;
        }
        if (bios->fp.fpxlatetableptr == 0x0) {
-               NV_ERROR(dev, "Pointer to flat panel xlat table invalid\n");
+               NV_ERROR(drm, "Pointer to flat panel xlat table invalid\n");
                return -EINVAL;
        }
  
                                        fpstrapping * bios->fp.xlatwidth];
  
        if (fpindex > fpentries) {
-               NV_ERROR(dev, "Bad flat panel table index\n");
+               NV_ERROR(drm, "Bad flat panel table index\n");
                return -ENOENT;
        }
  
        bios->fp.mode_ptr = bios->fp.fptablepointer + headerlen +
                            recordlen * fpindex + ofs;
  
-       NV_TRACE(dev, "BIOS FP mode: %dx%d (%dkHz pixel clock)\n",
+       NV_INFO(drm, "BIOS FP mode: %dx%d (%dkHz pixel clock)\n",
                 ROM16(bios->data[bios->fp.mode_ptr + 11]) + 1,
                 ROM16(bios->data[bios->fp.mode_ptr + 25]) + 1,
                 ROM16(bios->data[bios->fp.mode_ptr + 7]) * 10);
  
  bool nouveau_bios_fp_mode(struct drm_device *dev, struct drm_display_mode *mode)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
        uint8_t *mode_entry = &bios->data[bios->fp.mode_ptr];
  
        if (!mode)      /* just checking whether we can produce a mode */
@@@ -4190,8 -519,8 +520,8 @@@ int nouveau_bios_parse_lvds_table(struc
         * requiring tests against the native-mode pixel clock, cannot be done
         * until later, when this function should be called with non-zero pxclk
         */
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
        int fpstrapping = get_fp_strap(dev, bios), lvdsmanufacturerindex = 0;
        struct lvdstableheader lth;
        uint16_t lvdsofs;
                lvdsmanufacturerindex = fpstrapping;
                break;
        default:
-               NV_ERROR(dev, "LVDS table revision not currently supported\n");
+               NV_ERROR(drm, "LVDS table revision not currently supported\n");
                return -ENOSYS;
        }
  
   * This function returns true if a particular DCB entry matches.
   */
  bool
- bios_encoder_match(struct dcb_entry *dcb, u32 hash)
+ bios_encoder_match(struct dcb_output *dcb, u32 hash)
  {
        if ((hash & 0x000000f0) != (dcb->location << 4))
                return false;
                return false;
  
        switch (dcb->type) {
-       case OUTPUT_TMDS:
-       case OUTPUT_LVDS:
-       case OUTPUT_DP:
+       case DCB_OUTPUT_TMDS:
+       case DCB_OUTPUT_LVDS:
+       case DCB_OUTPUT_DP:
                if (hash & 0x00c00000) {
                        if (!(hash & (dcb->sorconf.link << 22)))
                                return false;
  
  int
  nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk,
-                              struct dcb_entry *dcbent, int crtc)
+                              struct dcb_output *dcbent, int crtc)
  {
        /*
         * The display script table is located by the BIT 'U' table.
         * offset + 5   (16 bits): pointer to first output script table
         */
  
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
        uint8_t *table = &bios->data[bios->display.script_table_ptr];
        uint8_t *otable = NULL;
        uint16_t script;
        int i;
  
        if (!bios->display.script_table_ptr) {
-               NV_ERROR(dev, "No pointer to output script table\n");
+               NV_ERROR(drm, "No pointer to output script table\n");
                return 1;
        }
  
                return 1;
  
        if (table[0] != 0x20 && table[0] != 0x21) {
-               NV_ERROR(dev, "Output script table version 0x%02x unknown\n",
+               NV_ERROR(drm, "Output script table version 0x%02x unknown\n",
                         table[0]);
                return 1;
        }
         * script tables is a pointer to the script to execute.
         */
  
-       NV_DEBUG_KMS(dev, "Searching for output entry for %d %d %d\n",
+       NV_DEBUG(drm, "Searching for output entry for %d %d %d\n",
                        dcbent->type, dcbent->location, dcbent->or);
        for (i = 0; i < table[3]; i++) {
                otable = ROMPTR(dev, table[table[1] + (i * table[2])]);
        }
  
        if (!otable) {
-               NV_DEBUG_KMS(dev, "failed to match any output table\n");
+               NV_DEBUG(drm, "failed to match any output table\n");
                return 1;
        }
  
                }
  
                if (i == otable[5]) {
-                       NV_ERROR(dev, "Table 0x%04x not found for %d/%d, "
+                       NV_ERROR(drm, "Table 0x%04x not found for %d/%d, "
                                      "using first\n",
                                 type, dcbent->type, dcbent->or);
                        i = 0;
        if (pclk == 0) {
                script = ROM16(otable[6]);
                if (!script) {
-                       NV_DEBUG_KMS(dev, "output script 0 not found\n");
+                       NV_DEBUG(drm, "output script 0 not found\n");
                        return 1;
                }
  
-               NV_DEBUG_KMS(dev, "0x%04X: parsing output script 0\n", script);
+               NV_DEBUG(drm, "0x%04X: parsing output script 0\n", script);
                nouveau_bios_run_init_table(dev, script, dcbent, crtc);
        } else
        if (pclk == -1) {
                script = ROM16(otable[8]);
                if (!script) {
-                       NV_DEBUG_KMS(dev, "output script 1 not found\n");
+                       NV_DEBUG(drm, "output script 1 not found\n");
                        return 1;
                }
  
-               NV_DEBUG_KMS(dev, "0x%04X: parsing output script 1\n", script);
+               NV_DEBUG(drm, "0x%04X: parsing output script 1\n", script);
                nouveau_bios_run_init_table(dev, script, dcbent, crtc);
        } else
        if (pclk == -2) {
                else
                        script = 0;
                if (!script) {
-                       NV_DEBUG_KMS(dev, "output script 2 not found\n");
+                       NV_DEBUG(drm, "output script 2 not found\n");
                        return 1;
                }
  
-               NV_DEBUG_KMS(dev, "0x%04X: parsing output script 2\n", script);
+               NV_DEBUG(drm, "0x%04X: parsing output script 2\n", script);
                nouveau_bios_run_init_table(dev, script, dcbent, crtc);
        } else
        if (pclk > 0) {
                if (script)
                        script = clkcmptable(bios, script, pclk);
                if (!script) {
-                       NV_DEBUG_KMS(dev, "clock script 0 not found\n");
+                       NV_DEBUG(drm, "clock script 0 not found\n");
                        return 1;
                }
  
-               NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 0\n", script);
+               NV_DEBUG(drm, "0x%04X: parsing clock script 0\n", script);
                nouveau_bios_run_init_table(dev, script, dcbent, crtc);
        } else
        if (pclk < 0) {
                if (script)
                        script = clkcmptable(bios, script, -pclk);
                if (!script) {
-                       NV_DEBUG_KMS(dev, "clock script 1 not found\n");
+                       NV_DEBUG(drm, "clock script 1 not found\n");
                        return 1;
                }
  
-               NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 1\n", script);
+               NV_DEBUG(drm, "0x%04X: parsing clock script 1\n", script);
                nouveau_bios_run_init_table(dev, script, dcbent, crtc);
        }
  
  }
  
  
- int run_tmds_table(struct drm_device *dev, struct dcb_entry *dcbent, int head, int pxclk)
+ int run_tmds_table(struct drm_device *dev, struct dcb_output *dcbent, int head, int pxclk)
  {
        /*
         * the pxclk parameter is in kHz
         * ffs(or) == 3, use the second.
         */
  
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nv_device(drm->device);
+       struct nvbios *bios = &drm->vbios;
        int cv = bios->chip_version;
        uint16_t clktable = 0, scriptptr;
        uint32_t sel_clk_binding, sel_clk;
        }
  
        if (!clktable) {
-               NV_ERROR(dev, "Pixel clock comparison table not found\n");
+               NV_ERROR(drm, "Pixel clock comparison table not found\n");
                return -EINVAL;
        }
  
        scriptptr = clkcmptable(bios, clktable, pxclk);
  
        if (!scriptptr) {
-               NV_ERROR(dev, "TMDS output init script not found\n");
+               NV_ERROR(drm, "TMDS output init script not found\n");
                return -ENOENT;
        }
  
        /* don't let script change pll->head binding */
-       sel_clk_binding = bios_rd32(bios, NV_PRAMDAC_SEL_CLK) & 0x50000;
+       sel_clk_binding = nv_rd32(device, NV_PRAMDAC_SEL_CLK) & 0x50000;
        run_digital_op_script(dev, scriptptr, dcbent, head, pxclk >= 165000);
        sel_clk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK) & ~0x50000;
        NVWriteRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK, sel_clk | sel_clk_binding);
        return 0;
  }
  
- struct pll_mapping {
-       u8  type;
-       u32 reg;
- };
- static struct pll_mapping nv04_pll_mapping[] = {
-       { PLL_CORE  , NV_PRAMDAC_NVPLL_COEFF },
-       { PLL_MEMORY, NV_PRAMDAC_MPLL_COEFF },
-       { PLL_VPLL0 , NV_PRAMDAC_VPLL_COEFF },
-       { PLL_VPLL1 , NV_RAMDAC_VPLL2 },
-       {}
- };
- static struct pll_mapping nv40_pll_mapping[] = {
-       { PLL_CORE  , 0x004000 },
-       { PLL_MEMORY, 0x004020 },
-       { PLL_VPLL0 , NV_PRAMDAC_VPLL_COEFF },
-       { PLL_VPLL1 , NV_RAMDAC_VPLL2 },
-       {}
- };
- static struct pll_mapping nv50_pll_mapping[] = {
-       { PLL_CORE  , 0x004028 },
-       { PLL_SHADER, 0x004020 },
-       { PLL_UNK03 , 0x004000 },
-       { PLL_MEMORY, 0x004008 },
-       { PLL_UNK40 , 0x00e810 },
-       { PLL_UNK41 , 0x00e818 },
-       { PLL_UNK42 , 0x00e824 },
-       { PLL_VPLL0 , 0x614100 },
-       { PLL_VPLL1 , 0x614900 },
-       {}
- };
- static struct pll_mapping nv84_pll_mapping[] = {
-       { PLL_CORE  , 0x004028 },
-       { PLL_SHADER, 0x004020 },
-       { PLL_MEMORY, 0x004008 },
-       { PLL_VDEC  , 0x004030 },
-       { PLL_UNK41 , 0x00e818 },
-       { PLL_VPLL0 , 0x614100 },
-       { PLL_VPLL1 , 0x614900 },
-       {}
- };
- u32
- get_pll_register(struct drm_device *dev, enum pll_types type)
- {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
-       struct pll_mapping *map;
-       int i;
-       if (dev_priv->card_type < NV_40)
-               map = nv04_pll_mapping;
-       else
-       if (dev_priv->card_type < NV_50)
-               map = nv40_pll_mapping;
-       else {
-               u8 *plim = &bios->data[bios->pll_limit_tbl_ptr];
-               if (plim[0] >= 0x30) {
-                       u8 *entry = plim + plim[1];
-                       for (i = 0; i < plim[3]; i++, entry += plim[2]) {
-                               if (entry[0] == type)
-                                       return ROM32(entry[3]);
-                       }
-                       return 0;
-               }
-               if (dev_priv->chipset == 0x50)
-                       map = nv50_pll_mapping;
-               else
-                       map = nv84_pll_mapping;
-       }
-       while (map->reg) {
-               if (map->type == type)
-                       return map->reg;
-               map++;
-       }
-       return 0;
- }
- int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims *pll_lim)
- {
-       /*
-        * PLL limits table
-        *
-        * Version 0x10: NV30, NV31
-        * One byte header (version), one record of 24 bytes
-        * Version 0x11: NV36 - Not implemented
-        * Seems to have same record style as 0x10, but 3 records rather than 1
-        * Version 0x20: Found on Geforce 6 cards
-        * Trivial 4 byte BIT header. 31 (0x1f) byte record length
-        * Version 0x21: Found on Geforce 7, 8 and some Geforce 6 cards
-        * 5 byte header, fifth byte of unknown purpose. 35 (0x23) byte record
-        * length in general, some (integrated) have an extra configuration byte
-        * Version 0x30: Found on Geforce 8, separates the register mapping
-        * from the limits tables.
-        */
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
-       int cv = bios->chip_version, pllindex = 0;
-       uint8_t pll_lim_ver = 0, headerlen = 0, recordlen = 0, entries = 0;
-       uint32_t crystal_strap_mask, crystal_straps;
-       if (!bios->pll_limit_tbl_ptr) {
-               if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
-                   cv >= 0x40) {
-                       NV_ERROR(dev, "Pointer to PLL limits table invalid\n");
-                       return -EINVAL;
-               }
-       } else
-               pll_lim_ver = bios->data[bios->pll_limit_tbl_ptr];
-       crystal_strap_mask = 1 << 6;
-       /* open coded dev->twoHeads test */
-       if (cv > 0x10 && cv != 0x15 && cv != 0x1a && cv != 0x20)
-               crystal_strap_mask |= 1 << 22;
-       crystal_straps = nvReadEXTDEV(dev, NV_PEXTDEV_BOOT_0) &
-                                                       crystal_strap_mask;
-       switch (pll_lim_ver) {
-       /*
-        * We use version 0 to indicate a pre limit table bios (single stage
-        * pll) and load the hard coded limits instead.
-        */
-       case 0:
-               break;
-       case 0x10:
-       case 0x11:
-               /*
-                * Strictly v0x11 has 3 entries, but the last two don't seem
-                * to get used.
-                */
-               headerlen = 1;
-               recordlen = 0x18;
-               entries = 1;
-               pllindex = 0;
-               break;
-       case 0x20:
-       case 0x21:
-       case 0x30:
-       case 0x40:
-               headerlen = bios->data[bios->pll_limit_tbl_ptr + 1];
-               recordlen = bios->data[bios->pll_limit_tbl_ptr + 2];
-               entries = bios->data[bios->pll_limit_tbl_ptr + 3];
-               break;
-       default:
-               NV_ERROR(dev, "PLL limits table revision 0x%X not currently "
-                               "supported\n", pll_lim_ver);
-               return -ENOSYS;
-       }
-       /* initialize all members to zero */
-       memset(pll_lim, 0, sizeof(struct pll_lims));
-       /* if we were passed a type rather than a register, figure
-        * out the register and store it
-        */
-       if (limit_match > PLL_MAX)
-               pll_lim->reg = limit_match;
-       else {
-               pll_lim->reg = get_pll_register(dev, limit_match);
-               if (!pll_lim->reg)
-                       return -ENOENT;
-       }
-       if (pll_lim_ver == 0x10 || pll_lim_ver == 0x11) {
-               uint8_t *pll_rec = &bios->data[bios->pll_limit_tbl_ptr + headerlen + recordlen * pllindex];
-               pll_lim->vco1.minfreq = ROM32(pll_rec[0]);
-               pll_lim->vco1.maxfreq = ROM32(pll_rec[4]);
-               pll_lim->vco2.minfreq = ROM32(pll_rec[8]);
-               pll_lim->vco2.maxfreq = ROM32(pll_rec[12]);
-               pll_lim->vco1.min_inputfreq = ROM32(pll_rec[16]);
-               pll_lim->vco2.min_inputfreq = ROM32(pll_rec[20]);
-               pll_lim->vco1.max_inputfreq = pll_lim->vco2.max_inputfreq = INT_MAX;
-               /* these values taken from nv30/31/36 */
-               pll_lim->vco1.min_n = 0x1;
-               if (cv == 0x36)
-                       pll_lim->vco1.min_n = 0x5;
-               pll_lim->vco1.max_n = 0xff;
-               pll_lim->vco1.min_m = 0x1;
-               pll_lim->vco1.max_m = 0xd;
-               pll_lim->vco2.min_n = 0x4;
-               /*
-                * On nv30, 31, 36 (i.e. all cards with two stage PLLs with this
-                * table version (apart from nv35)), N2 is compared to
-                * maxN2 (0x46) and 10 * maxM2 (0x4), so set maxN2 to 0x28 and
-                * save a comparison
-                */
-               pll_lim->vco2.max_n = 0x28;
-               if (cv == 0x30 || cv == 0x35)
-                       /* only 5 bits available for N2 on nv30/35 */
-                       pll_lim->vco2.max_n = 0x1f;
-               pll_lim->vco2.min_m = 0x1;
-               pll_lim->vco2.max_m = 0x4;
-               pll_lim->max_log2p = 0x7;
-               pll_lim->max_usable_log2p = 0x6;
-       } else if (pll_lim_ver == 0x20 || pll_lim_ver == 0x21) {
-               uint16_t plloffs = bios->pll_limit_tbl_ptr + headerlen;
-               uint8_t *pll_rec;
-               int i;
-               /*
-                * First entry is default match, if nothing better. warn if
-                * reg field nonzero
-                */
-               if (ROM32(bios->data[plloffs]))
-                       NV_WARN(dev, "Default PLL limit entry has non-zero "
-                                      "register field\n");
-               for (i = 1; i < entries; i++)
-                       if (ROM32(bios->data[plloffs + recordlen * i]) == pll_lim->reg) {
-                               pllindex = i;
-                               break;
-                       }
-               if ((dev_priv->card_type >= NV_50) && (pllindex == 0)) {
-                       NV_ERROR(dev, "Register 0x%08x not found in PLL "
-                                "limits table", pll_lim->reg);
-                       return -ENOENT;
-               }
-               pll_rec = &bios->data[plloffs + recordlen * pllindex];
-               BIOSLOG(bios, "Loading PLL limits for reg 0x%08x\n",
-                       pllindex ? pll_lim->reg : 0);
-               /*
-                * Frequencies are stored in tables in MHz, kHz are more
-                * useful, so we convert.
-                */
-               /* What output frequencies can each VCO generate? */
-               pll_lim->vco1.minfreq = ROM16(pll_rec[4]) * 1000;
-               pll_lim->vco1.maxfreq = ROM16(pll_rec[6]) * 1000;
-               pll_lim->vco2.minfreq = ROM16(pll_rec[8]) * 1000;
-               pll_lim->vco2.maxfreq = ROM16(pll_rec[10]) * 1000;
-               /* What input frequencies they accept (past the m-divider)? */
-               pll_lim->vco1.min_inputfreq = ROM16(pll_rec[12]) * 1000;
-               pll_lim->vco2.min_inputfreq = ROM16(pll_rec[14]) * 1000;
-               pll_lim->vco1.max_inputfreq = ROM16(pll_rec[16]) * 1000;
-               pll_lim->vco2.max_inputfreq = ROM16(pll_rec[18]) * 1000;
-               /* What values are accepted as multiplier and divider? */
-               pll_lim->vco1.min_n = pll_rec[20];
-               pll_lim->vco1.max_n = pll_rec[21];
-               pll_lim->vco1.min_m = pll_rec[22];
-               pll_lim->vco1.max_m = pll_rec[23];
-               pll_lim->vco2.min_n = pll_rec[24];
-               pll_lim->vco2.max_n = pll_rec[25];
-               pll_lim->vco2.min_m = pll_rec[26];
-               pll_lim->vco2.max_m = pll_rec[27];
-               pll_lim->max_usable_log2p = pll_lim->max_log2p = pll_rec[29];
-               if (pll_lim->max_log2p > 0x7)
-                       /* pll decoding in nv_hw.c assumes never > 7 */
-                       NV_WARN(dev, "Max log2 P value greater than 7 (%d)\n",
-                               pll_lim->max_log2p);
-               if (cv < 0x60)
-                       pll_lim->max_usable_log2p = 0x6;
-               pll_lim->log2p_bias = pll_rec[30];
-               if (recordlen > 0x22)
-                       pll_lim->refclk = ROM32(pll_rec[31]);
-               if (recordlen > 0x23 && pll_rec[35])
-                       NV_WARN(dev,
-                               "Bits set in PLL configuration byte (%x)\n",
-                               pll_rec[35]);
-               /* C51 special not seen elsewhere */
-               if (cv == 0x51 && !pll_lim->refclk) {
-                       uint32_t sel_clk = bios_rd32(bios, NV_PRAMDAC_SEL_CLK);
-                       if ((pll_lim->reg == NV_PRAMDAC_VPLL_COEFF && sel_clk & 0x20) ||
-                           (pll_lim->reg == NV_RAMDAC_VPLL2 && sel_clk & 0x80)) {
-                               if (bios_idxprt_rd(bios, NV_CIO_CRX__COLOR, NV_CIO_CRE_CHIP_ID_INDEX) < 0xa3)
-                                       pll_lim->refclk = 200000;
-                               else
-                                       pll_lim->refclk = 25000;
-                       }
-               }
-       } else if (pll_lim_ver == 0x30) { /* ver 0x30 */
-               uint8_t *entry = &bios->data[bios->pll_limit_tbl_ptr + headerlen];
-               uint8_t *record = NULL;
-               int i;
-               BIOSLOG(bios, "Loading PLL limits for register 0x%08x\n",
-                       pll_lim->reg);
-               for (i = 0; i < entries; i++, entry += recordlen) {
-                       if (ROM32(entry[3]) == pll_lim->reg) {
-                               record = &bios->data[ROM16(entry[1])];
-                               break;
-                       }
-               }
-               if (!record) {
-                       NV_ERROR(dev, "Register 0x%08x not found in PLL "
-                                "limits table", pll_lim->reg);
-                       return -ENOENT;
-               }
-               pll_lim->vco1.minfreq = ROM16(record[0]) * 1000;
-               pll_lim->vco1.maxfreq = ROM16(record[2]) * 1000;
-               pll_lim->vco2.minfreq = ROM16(record[4]) * 1000;
-               pll_lim->vco2.maxfreq = ROM16(record[6]) * 1000;
-               pll_lim->vco1.min_inputfreq = ROM16(record[8]) * 1000;
-               pll_lim->vco2.min_inputfreq = ROM16(record[10]) * 1000;
-               pll_lim->vco1.max_inputfreq = ROM16(record[12]) * 1000;
-               pll_lim->vco2.max_inputfreq = ROM16(record[14]) * 1000;
-               pll_lim->vco1.min_n = record[16];
-               pll_lim->vco1.max_n = record[17];
-               pll_lim->vco1.min_m = record[18];
-               pll_lim->vco1.max_m = record[19];
-               pll_lim->vco2.min_n = record[20];
-               pll_lim->vco2.max_n = record[21];
-               pll_lim->vco2.min_m = record[22];
-               pll_lim->vco2.max_m = record[23];
-               pll_lim->max_usable_log2p = pll_lim->max_log2p = record[25];
-               pll_lim->log2p_bias = record[27];
-               pll_lim->refclk = ROM32(record[28]);
-       } else if (pll_lim_ver) { /* ver 0x40 */
-               uint8_t *entry = &bios->data[bios->pll_limit_tbl_ptr + headerlen];
-               uint8_t *record = NULL;
-               int i;
-               BIOSLOG(bios, "Loading PLL limits for register 0x%08x\n",
-                       pll_lim->reg);
-               for (i = 0; i < entries; i++, entry += recordlen) {
-                       if (ROM32(entry[3]) == pll_lim->reg) {
-                               record = &bios->data[ROM16(entry[1])];
-                               break;
-                       }
-               }
-               if (!record) {
-                       NV_ERROR(dev, "Register 0x%08x not found in PLL "
-                                "limits table", pll_lim->reg);
-                       return -ENOENT;
-               }
-               pll_lim->vco1.minfreq = ROM16(record[0]) * 1000;
-               pll_lim->vco1.maxfreq = ROM16(record[2]) * 1000;
-               pll_lim->vco1.min_inputfreq = ROM16(record[4]) * 1000;
-               pll_lim->vco1.max_inputfreq = ROM16(record[6]) * 1000;
-               pll_lim->vco1.min_m = record[8];
-               pll_lim->vco1.max_m = record[9];
-               pll_lim->vco1.min_n = record[10];
-               pll_lim->vco1.max_n = record[11];
-               pll_lim->min_p = record[12];
-               pll_lim->max_p = record[13];
-               pll_lim->refclk = ROM16(entry[9]) * 1000;
-       }
-       /*
-        * By now any valid limit table ought to have set a max frequency for
-        * vco1, so if it's zero it's either a pre limit table bios, or one
-        * with an empty limit table (seen on nv18)
-        */
-       if (!pll_lim->vco1.maxfreq) {
-               pll_lim->vco1.minfreq = bios->fminvco;
-               pll_lim->vco1.maxfreq = bios->fmaxvco;
-               pll_lim->vco1.min_inputfreq = 0;
-               pll_lim->vco1.max_inputfreq = INT_MAX;
-               pll_lim->vco1.min_n = 0x1;
-               pll_lim->vco1.max_n = 0xff;
-               pll_lim->vco1.min_m = 0x1;
-               if (crystal_straps == 0) {
-                       /* nv05 does this, nv11 doesn't, nv10 unknown */
-                       if (cv < 0x11)
-                               pll_lim->vco1.min_m = 0x7;
-                       pll_lim->vco1.max_m = 0xd;
-               } else {
-                       if (cv < 0x11)
-                               pll_lim->vco1.min_m = 0x8;
-                       pll_lim->vco1.max_m = 0xe;
-               }
-               if (cv < 0x17 || cv == 0x1a || cv == 0x20)
-                       pll_lim->max_log2p = 4;
-               else
-                       pll_lim->max_log2p = 5;
-               pll_lim->max_usable_log2p = pll_lim->max_log2p;
-       }
-       if (!pll_lim->refclk)
-               switch (crystal_straps) {
-               case 0:
-                       pll_lim->refclk = 13500;
-                       break;
-               case (1 << 6):
-                       pll_lim->refclk = 14318;
-                       break;
-               case (1 << 22):
-                       pll_lim->refclk = 27000;
-                       break;
-               case (1 << 22 | 1 << 6):
-                       pll_lim->refclk = 25000;
-                       break;
-               }
-       NV_DEBUG(dev, "pll.vco1.minfreq: %d\n", pll_lim->vco1.minfreq);
-       NV_DEBUG(dev, "pll.vco1.maxfreq: %d\n", pll_lim->vco1.maxfreq);
-       NV_DEBUG(dev, "pll.vco1.min_inputfreq: %d\n", pll_lim->vco1.min_inputfreq);
-       NV_DEBUG(dev, "pll.vco1.max_inputfreq: %d\n", pll_lim->vco1.max_inputfreq);
-       NV_DEBUG(dev, "pll.vco1.min_n: %d\n", pll_lim->vco1.min_n);
-       NV_DEBUG(dev, "pll.vco1.max_n: %d\n", pll_lim->vco1.max_n);
-       NV_DEBUG(dev, "pll.vco1.min_m: %d\n", pll_lim->vco1.min_m);
-       NV_DEBUG(dev, "pll.vco1.max_m: %d\n", pll_lim->vco1.max_m);
-       if (pll_lim->vco2.maxfreq) {
-               NV_DEBUG(dev, "pll.vco2.minfreq: %d\n", pll_lim->vco2.minfreq);
-               NV_DEBUG(dev, "pll.vco2.maxfreq: %d\n", pll_lim->vco2.maxfreq);
-               NV_DEBUG(dev, "pll.vco2.min_inputfreq: %d\n", pll_lim->vco2.min_inputfreq);
-               NV_DEBUG(dev, "pll.vco2.max_inputfreq: %d\n", pll_lim->vco2.max_inputfreq);
-               NV_DEBUG(dev, "pll.vco2.min_n: %d\n", pll_lim->vco2.min_n);
-               NV_DEBUG(dev, "pll.vco2.max_n: %d\n", pll_lim->vco2.max_n);
-               NV_DEBUG(dev, "pll.vco2.min_m: %d\n", pll_lim->vco2.min_m);
-               NV_DEBUG(dev, "pll.vco2.max_m: %d\n", pll_lim->vco2.max_m);
-       }
-       if (!pll_lim->max_p) {
-               NV_DEBUG(dev, "pll.max_log2p: %d\n", pll_lim->max_log2p);
-               NV_DEBUG(dev, "pll.log2p_bias: %d\n", pll_lim->log2p_bias);
-       } else {
-               NV_DEBUG(dev, "pll.min_p: %d\n", pll_lim->min_p);
-               NV_DEBUG(dev, "pll.max_p: %d\n", pll_lim->max_p);
-       }
-       NV_DEBUG(dev, "pll.refclk: %d\n", pll_lim->refclk);
-       return 0;
- }
  static void parse_bios_version(struct drm_device *dev, struct nvbios *bios, uint16_t offset)
  {
        /*
         * offset + 2  (8 bits): Chip version
         * offset + 3  (8 bits): Major version
         */
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
        bios->major_version = bios->data[offset + 3];
        bios->chip_version = bios->data[offset + 2];
-       NV_TRACE(dev, "Bios version %02x.%02x.%02x.%02x\n",
+       NV_INFO(drm, "Bios version %02x.%02x.%02x.%02x\n",
                 bios->data[offset + 3], bios->data[offset + 2],
                 bios->data[offset + 1], bios->data[offset]);
  }
@@@ -5035,25 -925,26 +926,26 @@@ static int parse_bit_A_tbl_entry(struc
         * offset + 0 (16 bits): loadval table pointer
         */
  
+       struct nouveau_drm *drm = nouveau_drm(dev);
        uint16_t load_table_ptr;
        uint8_t version, headerlen, entrylen, num_entries;
  
        if (bitentry->length != 3) {
-               NV_ERROR(dev, "Do not understand BIT A table\n");
+               NV_ERROR(drm, "Do not understand BIT A table\n");
                return -EINVAL;
        }
  
        load_table_ptr = ROM16(bios->data[bitentry->offset]);
  
        if (load_table_ptr == 0x0) {
-               NV_DEBUG(dev, "Pointer to BIT loadval table invalid\n");
+               NV_DEBUG(drm, "Pointer to BIT loadval table invalid\n");
                return -EINVAL;
        }
  
        version = bios->data[load_table_ptr];
  
        if (version != 0x10) {
-               NV_ERROR(dev, "BIT loadval table version %d.%d not supported\n",
+               NV_ERROR(drm, "BIT loadval table version %d.%d not supported\n",
                         version >> 4, version & 0xF);
                return -ENOSYS;
        }
        num_entries = bios->data[load_table_ptr + 3];
  
        if (headerlen != 4 || entrylen != 4 || num_entries != 2) {
-               NV_ERROR(dev, "Do not understand BIT loadval table\n");
+               NV_ERROR(drm, "Do not understand BIT loadval table\n");
                return -EINVAL;
        }
  
@@@ -5080,9 -971,10 +972,10 @@@ static int parse_bit_C_tbl_entry(struc
         *
         * There's more in here, but that's unknown.
         */
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
        if (bitentry->length < 10) {
-               NV_ERROR(dev, "Do not understand BIT C table\n");
+               NV_ERROR(drm, "Do not understand BIT C table\n");
                return -EINVAL;
        }
  
@@@ -5101,9 -993,10 +994,10 @@@ static int parse_bit_display_tbl_entry(
         * records beginning with a freq.
         * offset + 2  (16 bits): mode table pointer
         */
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
        if (bitentry->length != 4) {
-               NV_ERROR(dev, "Do not understand BIT display table\n");
+               NV_ERROR(drm, "Do not understand BIT display table\n");
                return -EINVAL;
        }
  
@@@ -5119,9 -1012,10 +1013,10 @@@ static int parse_bit_init_tbl_entry(str
         *
         * See parse_script_table_pointers for layout
         */
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
        if (bitentry->length < 14) {
-               NV_ERROR(dev, "Do not understand init table\n");
+               NV_ERROR(drm, "Do not understand init table\n");
                return -EINVAL;
        }
  
@@@ -5148,11 -1042,12 +1043,12 @@@ static int parse_bit_i_tbl_entry(struc
         * There's other things in the table, purpose unknown
         */
  
+       struct nouveau_drm *drm = nouveau_drm(dev);
        uint16_t daccmpoffset;
        uint8_t dacver, dacheaderlen;
  
        if (bitentry->length < 6) {
-               NV_ERROR(dev, "BIT i table too short for needed information\n");
+               NV_ERROR(drm, "BIT i table too short for needed information\n");
                return -EINVAL;
        }
  
        bios->is_mobile = bios->feature_byte & FEATURE_MOBILE;
  
        if (bitentry->length < 15) {
-               NV_WARN(dev, "BIT i table not long enough for DAC load "
+               NV_WARN(drm, "BIT i table not long enough for DAC load "
                               "detection comparison table\n");
                return -EINVAL;
        }
        dacheaderlen = bios->data[daccmpoffset + 1];
  
        if (dacver != 0x00 && dacver != 0x10) {
-               NV_WARN(dev, "DAC load detection comparison table version "
+               NV_WARN(drm, "DAC load detection comparison table version "
                               "%d.%d not known\n", dacver >> 4, dacver & 0xf);
                return -ENOSYS;
        }
@@@ -5207,8 -1102,10 +1103,10 @@@ static int parse_bit_lvds_tbl_entry(str
         * offset + 0  (16 bits): LVDS strap xlate table pointer
         */
  
+       struct nouveau_drm *drm = nouveau_drm(dev);
        if (bitentry->length != 2) {
-               NV_ERROR(dev, "Do not understand BIT LVDS table\n");
+               NV_ERROR(drm, "Do not understand BIT LVDS table\n");
                return -EINVAL;
        }
  
@@@ -5278,20 -1175,21 +1176,21 @@@ static int parse_bit_tmds_tbl_entry(str
         * "or" from the DCB.
         */
  
+       struct nouveau_drm *drm = nouveau_drm(dev);
        uint16_t tmdstableptr, script1, script2;
  
        if (bitentry->length != 2) {
-               NV_ERROR(dev, "Do not understand BIT TMDS table\n");
+               NV_ERROR(drm, "Do not understand BIT TMDS table\n");
                return -EINVAL;
        }
  
        tmdstableptr = ROM16(bios->data[bitentry->offset]);
        if (!tmdstableptr) {
-               NV_ERROR(dev, "Pointer to TMDS table invalid\n");
+               NV_ERROR(drm, "Pointer to TMDS table invalid\n");
                return -EINVAL;
        }
  
-       NV_INFO(dev, "TMDS table version %d.%d\n",
+       NV_INFO(drm, "TMDS table version %d.%d\n",
                bios->data[tmdstableptr] >> 4, bios->data[tmdstableptr] & 0xf);
  
        /* nv50+ has v2.0, but we don't parse it atm */
        script1 = ROM16(bios->data[tmdstableptr + 7]);
        script2 = ROM16(bios->data[tmdstableptr + 9]);
        if (bios->data[script1] != 'q' || bios->data[script2] != 'q')
-               NV_WARN(dev, "TMDS table script pointers not stubbed\n");
+               NV_WARN(drm, "TMDS table script pointers not stubbed\n");
  
        bios->tmds.output0_script_ptr = ROM16(bios->data[tmdstableptr + 11]);
        bios->tmds.output1_script_ptr = ROM16(bios->data[tmdstableptr + 13]);
@@@ -5325,10 -1223,11 +1224,11 @@@ parse_bit_U_tbl_entry(struct drm_devic
         * offset + 0  (16 bits): output script table pointer
         */
  
+       struct nouveau_drm *drm = nouveau_drm(dev);
        uint16_t outputscripttableptr;
  
        if (bitentry->length != 3) {
-               NV_ERROR(dev, "Do not understand BIT U table\n");
+               NV_ERROR(drm, "Do not understand BIT U table\n");
                return -EINVAL;
        }
  
@@@ -5347,8 -1246,8 +1247,8 @@@ struct bit_table 
  int
  bit_table(struct drm_device *dev, u8 id, struct bit_entry *bit)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
        u8 entries, *entry;
  
        if (bios->type != NVBIOS_BIT)
@@@ -5377,12 -1276,13 +1277,13 @@@ parse_bit_table(struct nvbios *bios, co
                struct bit_table *table)
  {
        struct drm_device *dev = bios->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct bit_entry bitentry;
  
        if (bit_table(dev, table->id, &bitentry) == 0)
                return table->parse_fn(dev, bios, &bitentry);
  
-       NV_INFO(dev, "BIT table '%c' not found\n", table->id);
+       NV_INFO(drm, "BIT table '%c' not found\n", table->id);
        return -ENOSYS;
  }
  
@@@ -5462,6 -1362,7 +1363,7 @@@ static int parse_bmp_structure(struct d
         * offset + 156: minimum pixel clock for LVDS dual link
         */
  
+       struct nouveau_drm *drm = nouveau_drm(dev);
        uint8_t *bmp = &bios->data[offset], bmp_version_major, bmp_version_minor;
        uint16_t bmplength;
        uint16_t legacy_scripts_offset, legacy_i2c_offset;
        bmp_version_major = bmp[5];
        bmp_version_minor = bmp[6];
  
-       NV_TRACE(dev, "BMP version %d.%d\n",
+       NV_INFO(drm, "BMP version %d.%d\n",
                 bmp_version_major, bmp_version_minor);
  
        /*
         * happened instead.
         */
        if ((bmp_version_major < 5 && bmp_version_minor != 1) || bmp_version_major > 5) {
-               NV_ERROR(dev, "You have an unsupported BMP version. "
+               NV_ERROR(drm, "You have an unsupported BMP version. "
                                "Please send in your bios\n");
                return -ENOSYS;
        }
  
        /* checksum */
        if (nv_cksum(bmp, 8)) {
-               NV_ERROR(dev, "Bad BMP checksum\n");
+               NV_ERROR(drm, "Bad BMP checksum\n");
                return -EINVAL;
        }
  
@@@ -5625,20 -1526,20 +1527,20 @@@ static uint16_t findstr(uint8_t *data, 
  }
  
  void *
- dcb_table(struct drm_device *dev)
olddcb_table(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        u8 *dcb = NULL;
  
-       if (dev_priv->card_type > NV_04)
-               dcb = ROMPTR(dev, dev_priv->vbios.data[0x36]);
+       if (nv_device(drm->device)->card_type > NV_04)
+               dcb = ROMPTR(dev, drm->vbios.data[0x36]);
        if (!dcb) {
-               NV_WARNONCE(dev, "No DCB data found in VBIOS\n");
+               NV_WARN(drm, "No DCB data found in VBIOS\n");
                return NULL;
        }
  
        if (dcb[0] >= 0x41) {
-               NV_WARNONCE(dev, "DCB version 0x%02x unknown\n", dcb[0]);
+               NV_WARN(drm, "DCB version 0x%02x unknown\n", dcb[0]);
                return NULL;
        } else
        if (dcb[0] >= 0x30) {
                 *
                 * v1.1 (NV5+, maybe some NV4) is entirely unhelpful
                 */
-               NV_WARNONCE(dev, "No useful DCB data in VBIOS\n");
+               NV_WARN(drm, "No useful DCB data in VBIOS\n");
                return NULL;
        }
  
-       NV_WARNONCE(dev, "DCB header validation failed\n");
+       NV_WARN(drm, "DCB header validation failed\n");
        return NULL;
  }
  
  void *
- dcb_outp(struct drm_device *dev, u8 idx)
olddcb_outp(struct drm_device *dev, u8 idx)
  {
-       u8 *dcb = dcb_table(dev);
+       u8 *dcb = olddcb_table(dev);
        if (dcb && dcb[0] >= 0x30) {
                if (idx < dcb[2])
                        return dcb + dcb[1] + (idx * dcb[3]);
  }
  
  int
- dcb_outp_foreach(struct drm_device *dev, void *data,
olddcb_outp_foreach(struct drm_device *dev, void *data,
                 int (*exec)(struct drm_device *, void *, int idx, u8 *outp))
  {
        int ret, idx = -1;
        u8 *outp = NULL;
-       while ((outp = dcb_outp(dev, ++idx))) {
+       while ((outp = olddcb_outp(dev, ++idx))) {
                if (ROM32(outp[0]) == 0x00000000)
                        break; /* seen on an NV11 with DCB v1.5 */
                if (ROM32(outp[0]) == 0xffffffff)
                        break; /* seen on an NV17 with DCB v2.0 */
  
-               if ((outp[0] & 0x0f) == OUTPUT_UNUSED)
+               if ((outp[0] & 0x0f) == DCB_OUTPUT_UNUSED)
                        continue;
-               if ((outp[0] & 0x0f) == OUTPUT_EOL)
+               if ((outp[0] & 0x0f) == DCB_OUTPUT_EOL)
                        break;
  
                ret = exec(dev, data, idx, outp);
  }
  
  u8 *
- dcb_conntab(struct drm_device *dev)
olddcb_conntab(struct drm_device *dev)
  {
-       u8 *dcb = dcb_table(dev);
+       u8 *dcb = olddcb_table(dev);
        if (dcb && dcb[0] >= 0x30 && dcb[1] >= 0x16) {
                u8 *conntab = ROMPTR(dev, dcb[0x14]);
                if (conntab && conntab[0] >= 0x30 && conntab[0] <= 0x40)
  }
  
  u8 *
- dcb_conn(struct drm_device *dev, u8 idx)
olddcb_conn(struct drm_device *dev, u8 idx)
  {
-       u8 *conntab = dcb_conntab(dev);
+       u8 *conntab = olddcb_conntab(dev);
        if (conntab && idx < conntab[2])
                return conntab + conntab[1] + (idx * conntab[3]);
        return NULL;
  }
  
- static struct dcb_entry *new_dcb_entry(struct dcb_table *dcb)
+ static struct dcb_output *new_dcb_entry(struct dcb_table *dcb)
  {
-       struct dcb_entry *entry = &dcb->entry[dcb->entries];
+       struct dcb_output *entry = &dcb->entry[dcb->entries];
  
-       memset(entry, 0, sizeof(struct dcb_entry));
+       memset(entry, 0, sizeof(struct dcb_output));
        entry->index = dcb->entries++;
  
        return entry;
  static void fabricate_dcb_output(struct dcb_table *dcb, int type, int i2c,
                                 int heads, int or)
  {
-       struct dcb_entry *entry = new_dcb_entry(dcb);
+       struct dcb_output *entry = new_dcb_entry(dcb);
  
        entry->type = type;
        entry->i2c_index = i2c;
        entry->heads = heads;
-       if (type != OUTPUT_ANALOG)
+       if (type != DCB_OUTPUT_ANALOG)
                entry->location = !DCB_LOC_ON_CHIP; /* ie OFF CHIP */
        entry->or = or;
  }
  
  static bool
  parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
-                 uint32_t conn, uint32_t conf, struct dcb_entry *entry)
+                 uint32_t conn, uint32_t conf, struct dcb_output *entry)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        entry->type = conn & 0xf;
        entry->i2c_index = (conn >> 4) & 0xf;
        entry->heads = (conn >> 8) & 0xf;
        entry->or = (conn >> 24) & 0xf;
  
        switch (entry->type) {
-       case OUTPUT_ANALOG:
+       case DCB_OUTPUT_ANALOG:
                /*
                 * Although the rest of a CRT conf dword is usually
                 * zeros, mac biosen have stuff there so we must mask
                                         (conf & 0xffff) * 10 :
                                         (conf & 0xff) * 10000;
                break;
-       case OUTPUT_LVDS:
+       case DCB_OUTPUT_LVDS:
                {
                uint32_t mask;
                if (conf & 0x1)
                        if (dcb->version >= 0x40)
                                break;
  
-                       NV_ERROR(dev, "Unknown LVDS configuration bits, "
+                       NV_ERROR(drm, "Unknown LVDS configuration bits, "
                                      "please report\n");
                }
                break;
                }
-       case OUTPUT_TV:
+       case DCB_OUTPUT_TV:
        {
                if (dcb->version >= 0x30)
                        entry->tvconf.has_component_output = conf & (0x8 << 4);
  
                break;
        }
-       case OUTPUT_DP:
+       case DCB_OUTPUT_DP:
                entry->dpconf.sor.link = (conf & 0x00000030) >> 4;
                switch ((conf & 0x00e00000) >> 21) {
                case 0:
                        break;
                }
                break;
-       case OUTPUT_TMDS:
+       case DCB_OUTPUT_TMDS:
                if (dcb->version >= 0x40)
                        entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4;
                else if (dcb->version >= 0x30)
                        entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4;
  
                break;
-       case OUTPUT_EOL:
+       case DCB_OUTPUT_EOL:
                /* weird g80 mobile type that "nv" treats as a terminator */
                dcb->entries--;
                return false;
  
  static bool
  parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb,
-                 uint32_t conn, uint32_t conf, struct dcb_entry *entry)
+                 uint32_t conn, uint32_t conf, struct dcb_output *entry)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        switch (conn & 0x0000000f) {
        case 0:
-               entry->type = OUTPUT_ANALOG;
+               entry->type = DCB_OUTPUT_ANALOG;
                break;
        case 1:
-               entry->type = OUTPUT_TV;
+               entry->type = DCB_OUTPUT_TV;
                break;
        case 2:
        case 4:
                if (conn & 0x10)
-                       entry->type = OUTPUT_LVDS;
+                       entry->type = DCB_OUTPUT_LVDS;
                else
-                       entry->type = OUTPUT_TMDS;
+                       entry->type = DCB_OUTPUT_TMDS;
                break;
        case 3:
-               entry->type = OUTPUT_LVDS;
+               entry->type = DCB_OUTPUT_LVDS;
                break;
        default:
-               NV_ERROR(dev, "Unknown DCB type %d\n", conn & 0x0000000f);
+               NV_ERROR(drm, "Unknown DCB type %d\n", conn & 0x0000000f);
                return false;
        }
  
        entry->duallink_possible = false;
  
        switch (entry->type) {
-       case OUTPUT_ANALOG:
+       case DCB_OUTPUT_ANALOG:
                entry->crtconf.maxfreq = (conf & 0xffff) * 10;
                break;
-       case OUTPUT_TV:
+       case DCB_OUTPUT_TV:
                entry->tvconf.has_component_output = false;
                break;
-       case OUTPUT_LVDS:
+       case DCB_OUTPUT_LVDS:
                if ((conn & 0x00003f00) >> 8 != 0x10)
                        entry->lvdsconf.use_straps_for_mode = true;
                entry->lvdsconf.use_power_scripts = true;
@@@ -5959,14 -1864,15 +1865,15 @@@ void merge_like_dcb_entries(struct drm_
         * more options
         */
  
+       struct nouveau_drm *drm = nouveau_drm(dev);
        int i, newentries = 0;
  
        for (i = 0; i < dcb->entries; i++) {
-               struct dcb_entry *ient = &dcb->entry[i];
+               struct dcb_output *ient = &dcb->entry[i];
                int j;
  
                for (j = i + 1; j < dcb->entries; j++) {
-                       struct dcb_entry *jent = &dcb->entry[j];
+                       struct dcb_output *jent = &dcb->entry[j];
  
                        if (jent->type == 100) /* already merged entry */
                                continue;
                            jent->type == ient->type &&
                            jent->location == ient->location &&
                            jent->or == ient->or) {
-                               NV_TRACE(dev, "Merging DCB entries %d and %d\n",
+                               NV_INFO(drm, "Merging DCB entries %d and %d\n",
                                         i, j);
                                ient->heads |= jent->heads;
                                jent->type = 100; /* dummy value */
  static bool
  apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct dcb_table *dcb = &dev_priv->vbios.dcb;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct dcb_table *dcb = &drm->vbios.dcb;
  
        /* Dell Precision M6300
         *   DCB entry 2: 02025312 00000010
         */
        if (nv_match_device(dev, 0x0201, 0x1462, 0x8851)) {
                if (*conn == 0xf2005014 && *conf == 0xffffffff) {
-                       fabricate_dcb_output(dcb, OUTPUT_TMDS, 1, 1, 1);
+                       fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS, 1, 1, 1);
                        return false;
                }
        }
@@@ -6115,24 -2021,24 +2022,24 @@@ fabricate_dcb_encoder_table(struct drm_
  #ifdef __powerpc__
        /* Apple iMac G4 NV17 */
        if (of_machine_is_compatible("PowerMac4,5")) {
-               fabricate_dcb_output(dcb, OUTPUT_TMDS, 0, all_heads, 1);
-               fabricate_dcb_output(dcb, OUTPUT_ANALOG, 1, all_heads, 2);
+               fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS, 0, all_heads, 1);
+               fabricate_dcb_output(dcb, DCB_OUTPUT_ANALOG, 1, all_heads, 2);
                return;
        }
  #endif
  
        /* Make up some sane defaults */
-       fabricate_dcb_output(dcb, OUTPUT_ANALOG,
+       fabricate_dcb_output(dcb, DCB_OUTPUT_ANALOG,
                             bios->legacy.i2c_indices.crt, 1, 1);
  
        if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0)
-               fabricate_dcb_output(dcb, OUTPUT_TV,
+               fabricate_dcb_output(dcb, DCB_OUTPUT_TV,
                                     bios->legacy.i2c_indices.tv,
                                     all_heads, 0);
  
        else if (bios->tmds.output0_script_ptr ||
                 bios->tmds.output1_script_ptr)
-               fabricate_dcb_output(dcb, OUTPUT_TMDS,
+               fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS,
                                     bios->legacy.i2c_indices.panel,
                                     all_heads, 1);
  }
  static int
  parse_dcb_entry(struct drm_device *dev, void *data, int idx, u8 *outp)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct dcb_table *dcb = &dev_priv->vbios.dcb;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct dcb_table *dcb = &drm->vbios.dcb;
        u32 conf = (dcb->version >= 0x20) ? ROM32(outp[4]) : ROM32(outp[6]);
        u32 conn = ROM32(outp[0]);
        bool ret;
  
        if (apply_dcb_encoder_quirks(dev, idx, &conn, &conf)) {
-               struct dcb_entry *entry = new_dcb_entry(dcb);
+               struct dcb_output *entry = new_dcb_entry(dcb);
  
-               NV_TRACEWARN(dev, "DCB outp %02d: %08x %08x\n", idx, conn, conf);
+               NV_INFO(drm, "DCB outp %02d: %08x %08x\n", idx, conn, conf);
  
                if (dcb->version >= 0x20)
                        ret = parse_dcb20_entry(dev, dcb, conn, conf, entry);
                 * are cards with bogus values (nv31m in bug 23212),
                 * and it's otherwise useless.
                 */
-               if (entry->type == OUTPUT_TV &&
+               if (entry->type == DCB_OUTPUT_TV &&
                    entry->location == DCB_LOC_ON_CHIP)
                        entry->i2c_index = 0x0f;
        }
@@@ -6210,7 -2116,7 +2117,7 @@@ dcb_fake_connectors(struct nvbios *bios
         * table - just in case it has random, rather than stub, entries.
         */
        if (i > 1) {
-               u8 *conntab = dcb_conntab(bios->dev);
+               u8 *conntab = olddcb_conntab(bios->dev);
                if (conntab)
                        conntab[0] = 0x00;
        }
  static int
  parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct dcb_table *dcb = &bios->dcb;
        u8 *dcbt, *conn;
        int idx;
  
-       dcbt = dcb_table(dev);
+       dcbt = olddcb_table(dev);
        if (!dcbt) {
                /* handle pre-DCB boards */
                if (bios->type == NVBIOS_BMP) {
                return -EINVAL;
        }
  
-       NV_TRACE(dev, "DCB version %d.%d\n", dcbt[0] >> 4, dcbt[0] & 0xf);
+       NV_INFO(drm, "DCB version %d.%d\n", dcbt[0] >> 4, dcbt[0] & 0xf);
  
        dcb->version = dcbt[0];
-       dcb_outp_foreach(dev, NULL, parse_dcb_entry);
+       olddcb_outp_foreach(dev, NULL, parse_dcb_entry);
  
        /*
         * apart for v2.1+ not being known for requiring merging, this
  
        /* dump connector table entries to log, if any exist */
        idx = -1;
-       while ((conn = dcb_conn(dev, ++idx))) {
+       while ((conn = olddcb_conn(dev, ++idx))) {
                if (conn[0] != 0xff) {
-                       NV_TRACE(dev, "DCB conn %02d: ", idx);
-                       if (dcb_conntab(dev)[3] < 4)
+                       NV_INFO(drm, "DCB conn %02d: ", idx);
+                       if (olddcb_conntab(dev)[3] < 4)
                                printk("%04x\n", ROM16(conn[0]));
                        else
                                printk("%08x\n", ROM32(conn[0]));
@@@ -6275,12 -2182,14 +2183,14 @@@ static int load_nv17_hwsq_ucode_entry(s
         * starting at reg 0x00001400
         */
  
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nv_device(drm->device);
        uint8_t bytes_to_write;
        uint16_t hwsq_entry_offset;
        int i;
  
        if (bios->data[hwsq_offset] <= entry) {
-               NV_ERROR(dev, "Too few entries in HW sequencer table for "
+               NV_ERROR(drm, "Too few entries in HW sequencer table for "
                                "requested entry\n");
                return -ENOENT;
        }
        bytes_to_write = bios->data[hwsq_offset + 1];
  
        if (bytes_to_write != 36) {
-               NV_ERROR(dev, "Unknown HW sequencer entry size\n");
+               NV_ERROR(drm, "Unknown HW sequencer entry size\n");
                return -EINVAL;
        }
  
-       NV_TRACE(dev, "Loading NV17 power sequencing microcode\n");
+       NV_INFO(drm, "Loading NV17 power sequencing microcode\n");
  
        hwsq_entry_offset = hwsq_offset + 2 + entry * bytes_to_write;
  
        /* set sequencer control */
-       bios_wr32(bios, 0x00001304, ROM32(bios->data[hwsq_entry_offset]));
+       nv_wr32(device, 0x00001304, ROM32(bios->data[hwsq_entry_offset]));
        bytes_to_write -= 4;
  
        /* write ucode */
        for (i = 0; i < bytes_to_write; i += 4)
-               bios_wr32(bios, 0x00001400 + i, ROM32(bios->data[hwsq_entry_offset + i + 4]));
+               nv_wr32(device, 0x00001400 + i, ROM32(bios->data[hwsq_entry_offset + i + 4]));
  
        /* twiddle NV_PBUS_DEBUG_4 */
-       bios_wr32(bios, NV_PBUS_DEBUG_4, bios_rd32(bios, NV_PBUS_DEBUG_4) | 0x18);
+       nv_wr32(device, NV_PBUS_DEBUG_4, nv_rd32(device, NV_PBUS_DEBUG_4) | 0x18);
  
        return 0;
  }
@@@ -6336,8 -2245,8 +2246,8 @@@ static int load_nv17_hw_sequencer_ucode
  
  uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
        const uint8_t edid_sig[] = {
                        0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
        uint16_t offset = 0;
                offset++;
        }
  
-       NV_TRACE(dev, "Found EDID in BIOS\n");
+       NV_INFO(drm, "Found EDID in BIOS\n");
  
        return bios->fp.edid = &bios->data[offset];
  }
  
- void
- nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
-                           struct dcb_entry *dcbent, int crtc)
- {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
-       struct init_exec iexec = { true, false };
-       spin_lock_bh(&bios->lock);
-       bios->display.output = dcbent;
-       bios->display.crtc = crtc;
-       parse_init_table(bios, table, &iexec);
-       bios->display.output = NULL;
-       spin_unlock_bh(&bios->lock);
- }
- void
- nouveau_bios_init_exec(struct drm_device *dev, uint16_t table)
- {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
-       struct init_exec iexec = { true, false };
-       parse_init_table(bios, table, &iexec);
- }
  static bool NVInitVBIOS(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
  
        memset(bios, 0, sizeof(struct nvbios));
        spin_lock_init(&bios->lock);
        bios->dev = dev;
  
-       return bios_shadow(dev);
+       bios->data = nouveau_bios(drm->device)->data;
+       bios->length = nouveau_bios(drm->device)->size;
+       return true;
  }
  
  static int nouveau_parse_vbios_struct(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
        const uint8_t bit_signature[] = { 0xff, 0xb8, 'B', 'I', 'T' };
        const uint8_t bmp_signature[] = { 0xff, 0x7f, 'N', 'V', 0x0 };
        int offset;
        offset = findstr(bios->data, bios->length,
                                        bit_signature, sizeof(bit_signature));
        if (offset) {
-               NV_TRACE(dev, "BIT BIOS found\n");
+               NV_INFO(drm, "BIT BIOS found\n");
                bios->type = NVBIOS_BIT;
                bios->offset = offset;
                return parse_bit_structure(bios, offset + 6);
        offset = findstr(bios->data, bios->length,
                                        bmp_signature, sizeof(bmp_signature));
        if (offset) {
-               NV_TRACE(dev, "BMP BIOS found\n");
+               NV_INFO(drm, "BMP BIOS found\n");
                bios->type = NVBIOS_BMP;
                bios->offset = offset;
                return parse_bmp_structure(dev, bios, offset);
        }
  
-       NV_ERROR(dev, "No known BIOS signature found\n");
+       NV_ERROR(drm, "No known BIOS signature found\n");
        return -ENODEV;
  }
  
  int
  nouveau_run_vbios_init(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
        int i, ret = 0;
  
        /* Reset the BIOS head to 0. */
                bios->fp.lvds_init_run = false;
        }
  
-       parse_init_tables(bios);
-       /*
-        * Runs some additional script seen on G8x VBIOSen.  The VBIOS'
-        * parser will run this right after the init tables, the binary
-        * driver appears to run it at some point later.
-        */
-       if (bios->some_script_ptr) {
-               struct init_exec iexec = {true, false};
-               NV_INFO(dev, "Parsing VBIOS init table at offset 0x%04X\n",
-                       bios->some_script_ptr);
-               parse_init_table(bios, bios->some_script_ptr, &iexec);
-       }
-       if (dev_priv->card_type >= NV_50) {
-               for (i = 0; i < bios->dcb.entries; i++) {
+       if (nv_device(drm->device)->card_type >= NV_50) {
+               for (i = 0; bios->execute && i < bios->dcb.entries; i++) {
                        nouveau_bios_run_display_table(dev, 0, 0,
                                                       &bios->dcb.entry[i], -1);
                }
  static bool
  nouveau_bios_posted(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        unsigned htotal;
  
-       if (dev_priv->card_type >= NV_50) {
+       if (nv_device(drm->device)->card_type >= NV_50) {
                if (NVReadVgaCrtc(dev, 0, 0x00) == 0 &&
                    NVReadVgaCrtc(dev, 0, 0x1a) == 0)
                        return false;
  int
  nouveau_bios_init(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
        int ret;
  
        if (!NVInitVBIOS(dev))
        if (ret)
                return ret;
  
-       ret = nouveau_i2c_init(dev);
-       if (ret)
-               return ret;
-       ret = nouveau_mxm_init(dev);
-       if (ret)
-               return ret;
        ret = parse_dcb_table(dev, bios);
        if (ret)
                return ret;
  
        /* ... unless card isn't POSTed already */
        if (!nouveau_bios_posted(dev)) {
-               NV_INFO(dev, "Adaptor not initialised, "
+               NV_INFO(drm, "Adaptor not initialised, "
                        "running VBIOS init tables.\n");
                bios->execute = true;
        }
-       if (nouveau_force_post)
-               bios->execute = true;
  
        ret = nouveau_run_vbios_init(dev);
        if (ret)
  void
  nouveau_bios_takedown(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       nouveau_mxm_fini(dev);
-       nouveau_i2c_fini(dev);
-       kfree(dev_priv->vbios.data);
  }
   * SOFTWARE.
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
- #include "nouveau_drv.h"
++
+ #include "nouveau_drm.h"
+ #include "nouveau_reg.h"
  #include "nouveau_hw.h"
  
  /****************************************************************************\
@@@ -195,12 -196,13 +197,13 @@@ static voi
  nv04_update_arb(struct drm_device *dev, int VClk, int bpp,
                int *burst, int *lwm)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nouveau_dev(dev);
        struct nv_fifo_info fifo_data;
        struct nv_sim_state sim_data;
        int MClk = nouveau_hw_get_clock(dev, PLL_MEMORY);
        int NVClk = nouveau_hw_get_clock(dev, PLL_CORE);
-       uint32_t cfg1 = nvReadFB(dev, NV04_PFB_CFG1);
+       uint32_t cfg1 = nv_rd32(device, NV04_PFB_CFG1);
  
        sim_data.pclk_khz = VClk;
        sim_data.mclk_khz = MClk;
                sim_data.mem_latency = 3;
                sim_data.mem_page_miss = 10;
        } else {
-               sim_data.memory_type = nvReadFB(dev, NV04_PFB_CFG0) & 0x1;
-               sim_data.memory_width = (nvReadEXTDEV(dev, NV_PEXTDEV_BOOT_0) & 0x10) ? 128 : 64;
+               sim_data.memory_type = nv_rd32(device, NV04_PFB_CFG0) & 0x1;
+               sim_data.memory_width = (nv_rd32(device, NV_PEXTDEV_BOOT_0) & 0x10) ? 128 : 64;
                sim_data.mem_latency = cfg1 & 0xf;
                sim_data.mem_page_miss = ((cfg1 >> 4) & 0xf) + ((cfg1 >> 31) & 0x1);
        }
  
-       if (dev_priv->card_type == NV_04)
+       if (nv_device(drm->device)->card_type == NV_04)
                nv04_calc_arb(&fifo_data, &sim_data);
        else
                nv10_calc_arb(&fifo_data, &sim_data);
@@@ -249,9 -251,9 +252,9 @@@ nv20_update_arb(int *burst, int *lwm
  void
  nouveau_calc_arb(struct drm_device *dev, int vclk, int bpp, int *burst, int *lwm)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
-       if (dev_priv->card_type < NV_20)
+       if (nv_device(drm->device)->card_type < NV_20)
                nv04_update_arb(dev, vclk, bpp, burst, lwm);
        else if ((dev->pci_device & 0xfff0) == 0x0240 /*CHIPSET_C51*/ ||
                 (dev->pci_device & 0xfff0) == 0x03d0 /*CHIPSET_C512*/) {
        } else
                nv20_update_arb(burst, lwm);
  }
- static int
- getMNP_single(struct drm_device *dev, struct pll_lims *pll_lim, int clk,
-             struct nouveau_pll_vals *bestpv)
- {
-       /* Find M, N and P for a single stage PLL
-        *
-        * Note that some bioses (NV3x) have lookup tables of precomputed MNP
-        * values, but we're too lazy to use those atm
-        *
-        * "clk" parameter in kHz
-        * returns calculated clock
-        */
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       int cv = dev_priv->vbios.chip_version;
-       int minvco = pll_lim->vco1.minfreq, maxvco = pll_lim->vco1.maxfreq;
-       int minM = pll_lim->vco1.min_m, maxM = pll_lim->vco1.max_m;
-       int minN = pll_lim->vco1.min_n, maxN = pll_lim->vco1.max_n;
-       int minU = pll_lim->vco1.min_inputfreq;
-       int maxU = pll_lim->vco1.max_inputfreq;
-       int minP = pll_lim->max_p ? pll_lim->min_p : 0;
-       int maxP = pll_lim->max_p ? pll_lim->max_p : pll_lim->max_usable_log2p;
-       int crystal = pll_lim->refclk;
-       int M, N, thisP, P;
-       int clkP, calcclk;
-       int delta, bestdelta = INT_MAX;
-       int bestclk = 0;
-       /* this division verified for nv20, nv18, nv28 (Haiku), and nv34 */
-       /* possibly correlated with introduction of 27MHz crystal */
-       if (dev_priv->card_type < NV_50) {
-               if (cv < 0x17 || cv == 0x1a || cv == 0x20) {
-                       if (clk > 250000)
-                               maxM = 6;
-                       if (clk > 340000)
-                               maxM = 2;
-               } else if (cv < 0x40) {
-                       if (clk > 150000)
-                               maxM = 6;
-                       if (clk > 200000)
-                               maxM = 4;
-                       if (clk > 340000)
-                               maxM = 2;
-               }
-       }
-       P = pll_lim->max_p ? maxP : (1 << maxP);
-       if ((clk * P) < minvco) {
-               minvco = clk * maxP;
-               maxvco = minvco * 2;
-       }
-       if (clk + clk/200 > maxvco)     /* +0.5% */
-               maxvco = clk + clk/200;
-       /* NV34 goes maxlog2P->0, NV20 goes 0->maxlog2P */
-       for (thisP = minP; thisP <= maxP; thisP++) {
-               P = pll_lim->max_p ? thisP : (1 << thisP);
-               clkP = clk * P;
-               if (clkP < minvco)
-                       continue;
-               if (clkP > maxvco)
-                       return bestclk;
-               for (M = minM; M <= maxM; M++) {
-                       if (crystal/M < minU)
-                               return bestclk;
-                       if (crystal/M > maxU)
-                               continue;
-                       /* add crystal/2 to round better */
-                       N = (clkP * M + crystal/2) / crystal;
-                       if (N < minN)
-                               continue;
-                       if (N > maxN)
-                               break;
-                       /* more rounding additions */
-                       calcclk = ((N * crystal + P/2) / P + M/2) / M;
-                       delta = abs(calcclk - clk);
-                       /* we do an exhaustive search rather than terminating
-                        * on an optimality condition...
-                        */
-                       if (delta < bestdelta) {
-                               bestdelta = delta;
-                               bestclk = calcclk;
-                               bestpv->N1 = N;
-                               bestpv->M1 = M;
-                               bestpv->log2P = thisP;
-                               if (delta == 0) /* except this one */
-                                       return bestclk;
-                       }
-               }
-       }
-       return bestclk;
- }
- static int
- getMNP_double(struct drm_device *dev, struct pll_lims *pll_lim, int clk,
-             struct nouveau_pll_vals *bestpv)
- {
-       /* Find M, N and P for a two stage PLL
-        *
-        * Note that some bioses (NV30+) have lookup tables of precomputed MNP
-        * values, but we're too lazy to use those atm
-        *
-        * "clk" parameter in kHz
-        * returns calculated clock
-        */
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       int chip_version = dev_priv->vbios.chip_version;
-       int minvco1 = pll_lim->vco1.minfreq, maxvco1 = pll_lim->vco1.maxfreq;
-       int minvco2 = pll_lim->vco2.minfreq, maxvco2 = pll_lim->vco2.maxfreq;
-       int minU1 = pll_lim->vco1.min_inputfreq, minU2 = pll_lim->vco2.min_inputfreq;
-       int maxU1 = pll_lim->vco1.max_inputfreq, maxU2 = pll_lim->vco2.max_inputfreq;
-       int minM1 = pll_lim->vco1.min_m, maxM1 = pll_lim->vco1.max_m;
-       int minN1 = pll_lim->vco1.min_n, maxN1 = pll_lim->vco1.max_n;
-       int minM2 = pll_lim->vco2.min_m, maxM2 = pll_lim->vco2.max_m;
-       int minN2 = pll_lim->vco2.min_n, maxN2 = pll_lim->vco2.max_n;
-       int maxlog2P = pll_lim->max_usable_log2p;
-       int crystal = pll_lim->refclk;
-       bool fixedgain2 = (minM2 == maxM2 && minN2 == maxN2);
-       int M1, N1, M2, N2, log2P;
-       int clkP, calcclk1, calcclk2, calcclkout;
-       int delta, bestdelta = INT_MAX;
-       int bestclk = 0;
-       int vco2 = (maxvco2 - maxvco2/200) / 2;
-       for (log2P = 0; clk && log2P < maxlog2P && clk <= (vco2 >> log2P); log2P++)
-               ;
-       clkP = clk << log2P;
-       if (maxvco2 < clk + clk/200)    /* +0.5% */
-               maxvco2 = clk + clk/200;
-       for (M1 = minM1; M1 <= maxM1; M1++) {
-               if (crystal/M1 < minU1)
-                       return bestclk;
-               if (crystal/M1 > maxU1)
-                       continue;
-               for (N1 = minN1; N1 <= maxN1; N1++) {
-                       calcclk1 = crystal * N1 / M1;
-                       if (calcclk1 < minvco1)
-                               continue;
-                       if (calcclk1 > maxvco1)
-                               break;
-                       for (M2 = minM2; M2 <= maxM2; M2++) {
-                               if (calcclk1/M2 < minU2)
-                                       break;
-                               if (calcclk1/M2 > maxU2)
-                                       continue;
-                               /* add calcclk1/2 to round better */
-                               N2 = (clkP * M2 + calcclk1/2) / calcclk1;
-                               if (N2 < minN2)
-                                       continue;
-                               if (N2 > maxN2)
-                                       break;
-                               if (!fixedgain2) {
-                                       if (chip_version < 0x60)
-                                               if (N2/M2 < 4 || N2/M2 > 10)
-                                                       continue;
-                                       calcclk2 = calcclk1 * N2 / M2;
-                                       if (calcclk2 < minvco2)
-                                               break;
-                                       if (calcclk2 > maxvco2)
-                                               continue;
-                               } else
-                                       calcclk2 = calcclk1;
-                               calcclkout = calcclk2 >> log2P;
-                               delta = abs(calcclkout - clk);
-                               /* we do an exhaustive search rather than terminating
-                                * on an optimality condition...
-                                */
-                               if (delta < bestdelta) {
-                                       bestdelta = delta;
-                                       bestclk = calcclkout;
-                                       bestpv->N1 = N1;
-                                       bestpv->M1 = M1;
-                                       bestpv->N2 = N2;
-                                       bestpv->M2 = M2;
-                                       bestpv->log2P = log2P;
-                                       if (delta == 0) /* except this one */
-                                               return bestclk;
-                               }
-                       }
-               }
-       }
-       return bestclk;
- }
- int
- nouveau_calc_pll_mnp(struct drm_device *dev, struct pll_lims *pll_lim, int clk,
-                    struct nouveau_pll_vals *pv)
- {
-       int outclk;
-       if (!pll_lim->vco2.maxfreq)
-               outclk = getMNP_single(dev, pll_lim, clk, pv);
-       else
-               outclk = getMNP_double(dev, pll_lim, clk, pv);
-       if (!outclk)
-               NV_ERROR(dev, "Could not find a compatible set of PLL values\n");
-       return outclk;
- }
  
  #include <acpi/button.h>
  
 -#include "drmP.h"
 -#include "drm_edid.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_edid.h>
 +#include <drm/drm_crtc_helper.h>
  
  #include "nouveau_reg.h"
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_hw.h"
+ #include "nouveau_acpi.h"
+ #include "nouveau_display.h"
+ #include "nouveau_connector.h"
  #include "nouveau_encoder.h"
  #include "nouveau_crtc.h"
- #include "nouveau_connector.h"
- #include "nouveau_gpio.h"
- #include "nouveau_hw.h"
+ #include <subdev/i2c.h>
+ #include <subdev/gpio.h>
+ MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
+ static int nouveau_tv_disable = 0;
+ module_param_named(tv_disable, nouveau_tv_disable, int, 0400);
+ MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status");
+ static int nouveau_ignorelid = 0;
+ module_param_named(ignorelid, nouveau_ignorelid, int, 0400);
+ MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (default: enabled)");
+ static int nouveau_duallink = 1;
+ module_param_named(duallink, nouveau_duallink, int, 0400);
  
  static void nouveau_connector_hotplug(void *, int);
  
@@@ -58,7 -75,7 +75,7 @@@ find_encoder(struct drm_connector *conn
                        continue;
                nv_encoder = nouveau_encoder(obj_to_encoder(obj));
  
-               if (type == OUTPUT_ANY || nv_encoder->dcb->type == type)
+               if (type == DCB_OUTPUT_ANY || nv_encoder->dcb->type == type)
                        return nv_encoder;
        }
  
@@@ -83,19 -100,21 +100,21 @@@ static voi
  nouveau_connector_destroy(struct drm_connector *connector)
  {
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
-       struct drm_nouveau_private *dev_priv;
+       struct nouveau_gpio *gpio;
+       struct nouveau_drm *drm;
        struct drm_device *dev;
  
        if (!nv_connector)
                return;
  
-       dev = nv_connector->base.dev;
-       dev_priv = dev->dev_private;
-       NV_DEBUG_KMS(dev, "\n");
+       dev  = nv_connector->base.dev;
+       drm  = nouveau_drm(dev);
+       gpio = nouveau_gpio(drm->device);
+       NV_DEBUG(drm, "\n");
  
-       if (nv_connector->hpd != DCB_GPIO_UNUSED) {
-               nouveau_gpio_isr_del(dev, 0, nv_connector->hpd, 0xff,
-                                    nouveau_connector_hotplug, connector);
+       if (gpio && nv_connector->hpd != DCB_GPIO_UNUSED) {
+               gpio->isr_del(gpio, 0, nv_connector->hpd, 0xff,
+                             nouveau_connector_hotplug, connector);
        }
  
        kfree(nv_connector->edid);
        kfree(connector);
  }
  
- static struct nouveau_i2c_chan *
+ static struct nouveau_i2c_port *
  nouveau_connector_ddc_detect(struct drm_connector *connector,
                             struct nouveau_encoder **pnv_encoder)
  {
        struct drm_device *dev = connector->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
        int i;
  
        for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-               struct nouveau_i2c_chan *i2c = NULL;
+               struct nouveau_i2c_port *port = NULL;
                struct nouveau_encoder *nv_encoder;
                struct drm_mode_object *obj;
                int id;
                nv_encoder = nouveau_encoder(obj_to_encoder(obj));
  
                if (nv_encoder->dcb->i2c_index < 0xf)
-                       i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
-               if (i2c && nouveau_probe_i2c_addr(i2c, 0x50)) {
+                       port = i2c->find(i2c, nv_encoder->dcb->i2c_index);
+               if (port && nv_probe_i2c(port, 0x50)) {
                        *pnv_encoder = nv_encoder;
-                       return i2c;
+                       return port;
                }
        }
  
@@@ -148,8 -168,8 +168,8 @@@ nouveau_connector_of_detect(struct drm_
        struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev);
  
        if (!dn ||
-           !((nv_encoder = find_encoder(connector, OUTPUT_TMDS)) ||
-             (nv_encoder = find_encoder(connector, OUTPUT_ANALOG))))
+           !((nv_encoder = find_encoder(connector, DCB_OUTPUT_TMDS)) ||
+             (nv_encoder = find_encoder(connector, DCB_OUTPUT_ANALOG))))
                return NULL;
  
        for_each_child_of_node(dn, cn) {
@@@ -173,25 -193,25 +193,25 @@@ nouveau_connector_set_encoder(struct dr
                              struct nouveau_encoder *nv_encoder)
  {
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
-       struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(connector->dev);
        struct drm_device *dev = connector->dev;
  
        if (nv_connector->detected_encoder == nv_encoder)
                return;
        nv_connector->detected_encoder = nv_encoder;
  
-       if (dev_priv->card_type >= NV_50) {
+       if (nv_device(drm->device)->card_type >= NV_50) {
                connector->interlace_allowed = true;
                connector->doublescan_allowed = true;
        } else
-       if (nv_encoder->dcb->type == OUTPUT_LVDS ||
-           nv_encoder->dcb->type == OUTPUT_TMDS) {
+       if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS ||
+           nv_encoder->dcb->type == DCB_OUTPUT_TMDS) {
                connector->doublescan_allowed = false;
                connector->interlace_allowed = false;
        } else {
                connector->doublescan_allowed = true;
-               if (dev_priv->card_type == NV_20 ||
-                  (dev_priv->card_type == NV_10 &&
+               if (nv_device(drm->device)->card_type == NV_20 ||
+                  (nv_device(drm->device)->card_type == NV_10 &&
                    (dev->pci_device & 0x0ff0) != 0x0100 &&
                    (dev->pci_device & 0x0ff0) != 0x0150))
                        /* HW is broken */
        if (nv_connector->type == DCB_CONNECTOR_DVI_I) {
                drm_connector_property_set_value(connector,
                        dev->mode_config.dvi_i_subconnector_property,
-                       nv_encoder->dcb->type == OUTPUT_TMDS ?
+                       nv_encoder->dcb->type == DCB_OUTPUT_TMDS ?
                        DRM_MODE_SUBCONNECTOR_DVID :
                        DRM_MODE_SUBCONNECTOR_DVIA);
        }
@@@ -213,10 -233,11 +233,11 @@@ static enum drm_connector_statu
  nouveau_connector_detect(struct drm_connector *connector, bool force)
  {
        struct drm_device *dev = connector->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct nouveau_encoder *nv_encoder = NULL;
        struct nouveau_encoder *nv_partner;
-       struct nouveau_i2c_chan *i2c;
+       struct nouveau_i2c_port *i2c;
        int type;
  
        /* Cleanup the previous EDID block. */
                drm_mode_connector_update_edid_property(connector,
                                                        nv_connector->edid);
                if (!nv_connector->edid) {
-                       NV_ERROR(dev, "DDC responded, but no EDID for %s\n",
+                       NV_ERROR(drm, "DDC responded, but no EDID for %s\n",
                                 drm_get_connector_name(connector));
                        goto detect_analog;
                }
  
-               if (nv_encoder->dcb->type == OUTPUT_DP &&
+               if (nv_encoder->dcb->type == DCB_OUTPUT_DP &&
                    !nouveau_dp_detect(to_drm_encoder(nv_encoder))) {
-                       NV_ERROR(dev, "Detected %s, but failed init\n",
+                       NV_ERROR(drm, "Detected %s, but failed init\n",
                                 drm_get_connector_name(connector));
                        return connector_status_disconnected;
                }
                 * isn't necessarily correct.
                 */
                nv_partner = NULL;
-               if (nv_encoder->dcb->type == OUTPUT_TMDS)
-                       nv_partner = find_encoder(connector, OUTPUT_ANALOG);
-               if (nv_encoder->dcb->type == OUTPUT_ANALOG)
-                       nv_partner = find_encoder(connector, OUTPUT_TMDS);
-               if (nv_partner && ((nv_encoder->dcb->type == OUTPUT_ANALOG &&
-                                   nv_partner->dcb->type == OUTPUT_TMDS) ||
-                                  (nv_encoder->dcb->type == OUTPUT_TMDS &&
-                                   nv_partner->dcb->type == OUTPUT_ANALOG))) {
+               if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS)
+                       nv_partner = find_encoder(connector, DCB_OUTPUT_ANALOG);
+               if (nv_encoder->dcb->type == DCB_OUTPUT_ANALOG)
+                       nv_partner = find_encoder(connector, DCB_OUTPUT_TMDS);
+               if (nv_partner && ((nv_encoder->dcb->type == DCB_OUTPUT_ANALOG &&
+                                   nv_partner->dcb->type == DCB_OUTPUT_TMDS) ||
+                                  (nv_encoder->dcb->type == DCB_OUTPUT_TMDS &&
+                                   nv_partner->dcb->type == DCB_OUTPUT_ANALOG))) {
                        if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL)
-                               type = OUTPUT_TMDS;
+                               type = DCB_OUTPUT_TMDS;
                        else
-                               type = OUTPUT_ANALOG;
+                               type = DCB_OUTPUT_ANALOG;
  
                        nv_encoder = find_encoder(connector, type);
                }
        }
  
  detect_analog:
-       nv_encoder = find_encoder(connector, OUTPUT_ANALOG);
+       nv_encoder = find_encoder(connector, DCB_OUTPUT_ANALOG);
        if (!nv_encoder && !nouveau_tv_disable)
-               nv_encoder = find_encoder(connector, OUTPUT_TV);
+               nv_encoder = find_encoder(connector, DCB_OUTPUT_TV);
        if (nv_encoder && force) {
                struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
                struct drm_encoder_helper_funcs *helper =
@@@ -301,7 -322,7 +322,7 @@@ static enum drm_connector_statu
  nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
  {
        struct drm_device *dev = connector->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct nouveau_encoder *nv_encoder = NULL;
        enum drm_connector_status status = connector_status_disconnected;
                nv_connector->edid = NULL;
        }
  
-       nv_encoder = find_encoder(connector, OUTPUT_LVDS);
+       nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS);
        if (!nv_encoder)
                return connector_status_disconnected;
  
        /* Try retrieving EDID via DDC */
-       if (!dev_priv->vbios.fp_no_ddc) {
+       if (!drm->vbios.fp_no_ddc) {
                status = nouveau_connector_detect(connector, force);
                if (status == connector_status_connected)
                        goto out;
         * valid - it's not (rh#613284)
         */
        if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
-               if (!nouveau_acpi_edid(dev, connector)) {
+               if (!(nv_connector->edid = nouveau_acpi_edid(dev, connector))) {
                        status = connector_status_connected;
                        goto out;
                }
         * modeline is avalilable for the panel, set it as the panel's
         * native mode and exit.
         */
-       if (nouveau_bios_fp_mode(dev, NULL) && (dev_priv->vbios.fp_no_ddc ||
+       if (nouveau_bios_fp_mode(dev, NULL) && (drm->vbios.fp_no_ddc ||
            nv_encoder->dcb->lvdsconf.use_straps_for_mode)) {
                status = connector_status_connected;
                goto out;
        /* Still nothing, some VBIOS images have a hardcoded EDID block
         * stored for the panel stored in them.
         */
-       if (!dev_priv->vbios.fp_no_ddc) {
+       if (!drm->vbios.fp_no_ddc) {
                struct edid *edid =
                        (struct edid *)nouveau_bios_embedded_edid(dev);
                if (edid) {
@@@ -379,21 -400,22 +400,22 @@@ out
  static void
  nouveau_connector_force(struct drm_connector *connector)
  {
+       struct nouveau_drm *drm = nouveau_drm(connector->dev);
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct nouveau_encoder *nv_encoder;
        int type;
  
        if (nv_connector->type == DCB_CONNECTOR_DVI_I) {
                if (connector->force == DRM_FORCE_ON_DIGITAL)
-                       type = OUTPUT_TMDS;
+                       type = DCB_OUTPUT_TMDS;
                else
-                       type = OUTPUT_ANALOG;
+                       type = DCB_OUTPUT_ANALOG;
        } else
-               type = OUTPUT_ANY;
+               type = DCB_OUTPUT_ANY;
  
        nv_encoder = find_encoder(connector, type);
        if (!nv_encoder) {
-               NV_ERROR(connector->dev, "can't find encoder to force %s on!\n",
+               NV_ERROR(drm, "can't find encoder to force %s on!\n",
                         drm_get_connector_name(connector));
                connector->status = connector_status_disconnected;
                return;
@@@ -406,8 -428,7 +428,7 @@@ static in
  nouveau_connector_set_property(struct drm_connector *connector,
                               struct drm_property *property, uint64_t value)
  {
-       struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
-       struct nouveau_display_engine *disp = &dev_priv->engine.display;
+       struct nouveau_display *disp = nouveau_display(connector->dev);
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
        struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
                }
        }
  
-       if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV)
+       if (nv_encoder && nv_encoder->dcb->type == DCB_OUTPUT_TV)
                return get_slave_funcs(encoder)->set_property(
                        encoder, connector, property, value);
  
@@@ -543,6 -564,7 +564,7 @@@ static struct drm_display_mode 
  nouveau_connector_native_mode(struct drm_connector *connector)
  {
        struct drm_connector_helper_funcs *helper = connector->helper_private;
+       struct nouveau_drm *drm = nouveau_drm(connector->dev);
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct drm_device *dev = connector->dev;
        struct drm_display_mode *mode, *largest = NULL;
  
                /* Use preferred mode if there is one.. */
                if (mode->type & DRM_MODE_TYPE_PREFERRED) {
-                       NV_DEBUG_KMS(dev, "native mode from preferred\n");
+                       NV_DEBUG(drm, "native mode from preferred\n");
                        return drm_mode_duplicate(dev, mode);
                }
  
                largest = mode;
        }
  
-       NV_DEBUG_KMS(dev, "native mode from largest: %dx%d@%d\n",
+       NV_DEBUG(drm, "native mode from largest: %dx%d@%d\n",
                      high_w, high_h, high_v);
        return largest ? drm_mode_duplicate(dev, largest) : NULL;
  }
@@@ -643,10 -665,10 +665,10 @@@ nouveau_connector_scaler_modes_add(stru
  static void
  nouveau_connector_detect_depth(struct drm_connector *connector)
  {
-       struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(connector->dev);
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nvbios *bios = &drm->vbios;
        struct drm_display_mode *mode = nv_connector->native_mode;
        bool duallink;
  
        }
  
        /* we're out of options unless we're LVDS, default to 8bpc */
-       if (nv_encoder->dcb->type != OUTPUT_LVDS) {
+       if (nv_encoder->dcb->type != DCB_OUTPUT_LVDS) {
                connector->display_info.bpc = 8;
                return;
        }
@@@ -693,7 -715,7 +715,7 @@@ static in
  nouveau_connector_get_modes(struct drm_connector *connector)
  {
        struct drm_device *dev = connector->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
        struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
        if (nv_connector->edid)
                ret = drm_add_edid_modes(connector, nv_connector->edid);
        else
-       if (nv_encoder->dcb->type == OUTPUT_LVDS &&
+       if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS &&
            (nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
-            dev_priv->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) {
+            drm->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) {
                struct drm_display_mode mode;
  
                nouveau_bios_fp_mode(dev, &mode);
        if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
                nouveau_connector_detect_depth(connector);
  
-       if (nv_encoder->dcb->type == OUTPUT_TV)
+       if (nv_encoder->dcb->type == DCB_OUTPUT_TV)
                ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
  
        if (nv_connector->type == DCB_CONNECTOR_LVDS ||
@@@ -761,15 -783,15 +783,15 @@@ static unsigne
  get_tmds_link_bandwidth(struct drm_connector *connector)
  {
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
-       struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
-       struct dcb_entry *dcb = nv_connector->detected_encoder->dcb;
+       struct nouveau_drm *drm = nouveau_drm(connector->dev);
+       struct dcb_output *dcb = nv_connector->detected_encoder->dcb;
  
        if (dcb->location != DCB_LOC_ON_CHIP ||
-           dev_priv->chipset >= 0x46)
+           nv_device(drm->device)->chipset >= 0x46)
                return 165000;
-       else if (dev_priv->chipset >= 0x40)
+       else if (nv_device(drm->device)->chipset >= 0x40)
                return 155000;
-       else if (dev_priv->chipset >= 0x18)
+       else if (nv_device(drm->device)->chipset >= 0x18)
                return 135000;
        else
                return 112000;
@@@ -786,7 -808,7 +808,7 @@@ nouveau_connector_mode_valid(struct drm
        unsigned clock = mode->clock;
  
        switch (nv_encoder->dcb->type) {
-       case OUTPUT_LVDS:
+       case DCB_OUTPUT_LVDS:
                if (nv_connector->native_mode &&
                    (mode->hdisplay > nv_connector->native_mode->hdisplay ||
                     mode->vdisplay > nv_connector->native_mode->vdisplay))
                min_clock = 0;
                max_clock = 400000;
                break;
-       case OUTPUT_TMDS:
+       case DCB_OUTPUT_TMDS:
                max_clock = get_tmds_link_bandwidth(connector);
                if (nouveau_duallink && nv_encoder->dcb->duallink_possible)
                        max_clock *= 2;
                break;
-       case OUTPUT_ANALOG:
+       case DCB_OUTPUT_ANALOG:
                max_clock = nv_encoder->dcb->crtconf.maxfreq;
                if (!max_clock)
                        max_clock = 350000;
                break;
-       case OUTPUT_TV:
+       case DCB_OUTPUT_TV:
                return get_slave_funcs(encoder)->mode_valid(encoder, mode);
-       case OUTPUT_DP:
+       case DCB_OUTPUT_DP:
                max_clock  = nv_encoder->dp.link_nr;
                max_clock *= nv_encoder->dp.link_bw;
                clock = clock * (connector->display_info.bpc * 3) / 10;
@@@ -899,14 -921,15 +921,15 @@@ struct drm_connector 
  nouveau_connector_create(struct drm_device *dev, int index)
  {
        const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_display_engine *disp = &dev_priv->engine.display;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
+       struct nouveau_display *disp = nouveau_display(dev);
        struct nouveau_connector *nv_connector = NULL;
        struct drm_connector *connector;
        int type, ret = 0;
        bool dummy;
  
-       NV_DEBUG_KMS(dev, "\n");
+       NV_DEBUG(drm, "\n");
  
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                nv_connector = nouveau_connector(connector);
        nv_connector->index = index;
  
        /* attempt to parse vbios connector type and hotplug gpio */
-       nv_connector->dcb = dcb_conn(dev, index);
+       nv_connector->dcb = olddcb_conn(dev, index);
        if (nv_connector->dcb) {
                static const u8 hpd[16] = {
                        0xff, 0x07, 0x08, 0xff, 0xff, 0x51, 0x52, 0xff,
                };
  
                u32 entry = ROM16(nv_connector->dcb[0]);
-               if (dcb_conntab(dev)[3] >= 4)
+               if (olddcb_conntab(dev)[3] >= 4)
                        entry |= (u32)ROM16(nv_connector->dcb[2]) << 16;
  
                nv_connector->hpd = ffs((entry & 0x07033000) >> 12);
                nv_connector->type = nv_connector->dcb[0];
                if (drm_conntype_from_dcb(nv_connector->type) ==
                                          DRM_MODE_CONNECTOR_Unknown) {
-                       NV_WARN(dev, "unknown connector type %02x\n",
+                       NV_WARN(drm, "unknown connector type %02x\n",
                                nv_connector->type);
                        nv_connector->type = DCB_CONNECTOR_NONE;
                }
         * figure out something suitable ourselves
         */
        if (nv_connector->type == DCB_CONNECTOR_NONE) {
-               struct drm_nouveau_private *dev_priv = dev->dev_private;
-               struct dcb_table *dcbt = &dev_priv->vbios.dcb;
+               struct nouveau_drm *drm = nouveau_drm(dev);
+               struct dcb_table *dcbt = &drm->vbios.dcb;
                u32 encoders = 0;
                int i;
  
                                encoders |= (1 << dcbt->entry[i].type);
                }
  
-               if (encoders & (1 << OUTPUT_DP)) {
-                       if (encoders & (1 << OUTPUT_TMDS))
+               if (encoders & (1 << DCB_OUTPUT_DP)) {
+                       if (encoders & (1 << DCB_OUTPUT_TMDS))
                                nv_connector->type = DCB_CONNECTOR_DP;
                        else
                                nv_connector->type = DCB_CONNECTOR_eDP;
                } else
-               if (encoders & (1 << OUTPUT_TMDS)) {
-                       if (encoders & (1 << OUTPUT_ANALOG))
+               if (encoders & (1 << DCB_OUTPUT_TMDS)) {
+                       if (encoders & (1 << DCB_OUTPUT_ANALOG))
                                nv_connector->type = DCB_CONNECTOR_DVI_I;
                        else
                                nv_connector->type = DCB_CONNECTOR_DVI_D;
                } else
-               if (encoders & (1 << OUTPUT_ANALOG)) {
+               if (encoders & (1 << DCB_OUTPUT_ANALOG)) {
                        nv_connector->type = DCB_CONNECTOR_VGA;
                } else
-               if (encoders & (1 << OUTPUT_LVDS)) {
+               if (encoders & (1 << DCB_OUTPUT_LVDS)) {
                        nv_connector->type = DCB_CONNECTOR_LVDS;
                } else
-               if (encoders & (1 << OUTPUT_TV)) {
+               if (encoders & (1 << DCB_OUTPUT_TV)) {
                        nv_connector->type = DCB_CONNECTOR_TV_0;
                }
        }
        if (type == DRM_MODE_CONNECTOR_LVDS) {
                ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &dummy);
                if (ret) {
-                       NV_ERROR(dev, "Error parsing LVDS table, disabling\n");
+                       NV_ERROR(drm, "Error parsing LVDS table, disabling\n");
                        kfree(nv_connector);
                        return ERR_PTR(ret);
                }
  
        switch (nv_connector->type) {
        case DCB_CONNECTOR_VGA:
-               if (dev_priv->card_type >= NV_50) {
+               if (nv_device(drm->device)->card_type >= NV_50) {
                        drm_connector_attach_property(connector,
                                        dev->mode_config.scaling_mode_property,
                                        nv_connector->scaling_mode);
        }
  
        connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-       if (nv_connector->hpd != DCB_GPIO_UNUSED) {
-               ret = nouveau_gpio_isr_add(dev, 0, nv_connector->hpd, 0xff,
-                                          nouveau_connector_hotplug,
-                                          connector);
+       if (gpio && nv_connector->hpd != DCB_GPIO_UNUSED) {
+               ret = gpio->isr_add(gpio, 0, nv_connector->hpd, 0xff,
+                                   nouveau_connector_hotplug, connector);
                if (ret == 0)
                        connector->polled = DRM_CONNECTOR_POLL_HPD;
        }
@@@ -1101,8 -1123,9 +1123,9 @@@ nouveau_connector_hotplug(void *data, i
  {
        struct drm_connector *connector = data;
        struct drm_device *dev = connector->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
-       NV_DEBUG(dev, "%splugged %s\n", plugged ? "" : "un",
+       NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un",
                 drm_get_connector_name(connector));
  
        if (plugged)
@@@ -27,8 -27,9 +27,9 @@@
  #ifndef __NOUVEAU_CONNECTOR_H__
  #define __NOUVEAU_CONNECTOR_H__
  
 -#include "drm_edid.h"
 +#include <drm/drm_edid.h>
- #include "nouveau_i2c.h"
+ struct nouveau_i2c_port;
  
  enum nouveau_underscan_type {
        UNDERSCAN_OFF,
   *
   */
  
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
- #include "nouveau_drv.h"
- #include "nouveau_fb.h"
  #include "nouveau_fbcon.h"
  #include "nouveau_hw.h"
  #include "nouveau_crtc.h"
  #include "nouveau_dma.h"
+ #include "nouveau_gem.h"
  #include "nouveau_connector.h"
- #include "nouveau_software.h"
- #include "nouveau_gpio.h"
- #include "nouveau_fence.h"
  #include "nv50_display.h"
  
+ #include "nouveau_fence.h"
+ #include <subdev/bios/gpio.h>
+ #include <subdev/gpio.h>
+ #include <engine/disp.h>
  static void
  nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
  {
@@@ -71,7 -74,7 +74,7 @@@ nouveau_framebuffer_init(struct drm_dev
                         struct drm_mode_fb_cmd2 *mode_cmd,
                         struct nouveau_bo *nvbo)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct drm_framebuffer *fb = &nv_fb->base;
        int ret;
  
@@@ -83,7 -86,7 +86,7 @@@
        drm_helper_mode_fill_fb_struct(fb, mode_cmd);
        nv_fb->nvbo = nvbo;
  
-       if (dev_priv->card_type >= NV_50) {
+       if (nv_device(drm->device)->card_type >= NV_50) {
                u32 tile_flags = nouveau_bo_tile_layout(nvbo);
                if (tile_flags == 0x7a00 ||
                    tile_flags == 0xfe00)
                case 32: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_24; break;
                case 30: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_30; break;
                default:
-                        NV_ERROR(dev, "unknown depth %d\n", fb->depth);
+                        NV_ERROR(drm, "unknown depth %d\n", fb->depth);
                         return -EINVAL;
                }
  
-               if (dev_priv->chipset == 0x50)
+               if (nv_device(drm->device)->chipset == 0x50)
                        nv_fb->r_format |= (tile_flags << 8);
  
                if (!tile_flags) {
-                       if (dev_priv->card_type < NV_D0)
+                       if (nv_device(drm->device)->card_type < NV_D0)
                                nv_fb->r_pitch = 0x00100000 | fb->pitches[0];
                        else
                                nv_fb->r_pitch = 0x01000000 | fb->pitches[0];
                } else {
                        u32 mode = nvbo->tile_mode;
-                       if (dev_priv->card_type >= NV_C0)
+                       if (nv_device(drm->device)->card_type >= NV_C0)
                                mode >>= 4;
                        nv_fb->r_pitch = ((fb->pitches[0] / 4) << 4) | mode;
                }
@@@ -212,8 -215,9 +215,9 @@@ static struct nouveau_drm_prop_enum_lis
  int
  nouveau_display_init(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_display_engine *disp = &dev_priv->engine.display;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_display *disp = nouveau_display(dev);
+       struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
        struct drm_connector *connector;
        int ret;
  
         * some vbios default this to off for some reason, causing the
         * panel to not work after resume
         */
-       if (nouveau_gpio_func_get(dev, DCB_GPIO_PANEL_POWER) == 0) {
-               nouveau_gpio_func_set(dev, DCB_GPIO_PANEL_POWER, true);
+       if (gpio && gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff) == 0) {
+               gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
                msleep(300);
        }
  
        /* enable hotplug interrupts */
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct nouveau_connector *conn = nouveau_connector(connector);
-               nouveau_gpio_irq(dev, 0, conn->hpd, 0xff, true);
+               if (gpio)
+                       gpio->irq(gpio, 0, conn->hpd, 0xff, true);
        }
  
        return ret;
  void
  nouveau_display_fini(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_display_engine *disp = &dev_priv->engine.display;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_display *disp = nouveau_display(dev);
+       struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
        struct drm_connector *connector;
  
        /* disable hotplug interrupts */
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct nouveau_connector *conn = nouveau_connector(connector);
-               nouveau_gpio_irq(dev, 0, conn->hpd, 0xff, false);
+               if (gpio)
+                       gpio->irq(gpio, 0, conn->hpd, 0xff, false);
        }
  
        drm_kms_helper_poll_disable(dev);
        disp->fini(dev);
  }
  
+ static void
+ nouveau_display_vblank_notify(void *data, int crtc)
+ {
+       drm_handle_vblank(data, crtc);
+ }
+ static void
+ nouveau_display_vblank_get(void *data, int crtc)
+ {
+       drm_vblank_get(data, crtc);
+ }
+ static void
+ nouveau_display_vblank_put(void *data, int crtc)
+ {
+       drm_vblank_put(data, crtc);
+ }
  int
  nouveau_display_create(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_display_engine *disp = &dev_priv->engine.display;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_disp *pdisp = nouveau_disp(drm->device);
+       struct nouveau_display *disp;
        int ret, gen;
  
+       disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL);
+       if (!disp)
+               return -ENOMEM;
+       pdisp->vblank.data = dev;
+       pdisp->vblank.notify = nouveau_display_vblank_notify;
+       pdisp->vblank.get = nouveau_display_vblank_get;
+       pdisp->vblank.put = nouveau_display_vblank_put;
        drm_mode_config_init(dev);
        drm_mode_create_scaling_mode_property(dev);
        drm_mode_create_dvi_i_properties(dev);
  
-       if (dev_priv->card_type < NV_50)
+       if (nv_device(drm->device)->card_type < NV_50)
                gen = 0;
        else
-       if (dev_priv->card_type < NV_D0)
+       if (nv_device(drm->device)->card_type < NV_D0)
                gen = 1;
        else
                gen = 2;
  
        dev->mode_config.min_width = 0;
        dev->mode_config.min_height = 0;
-       if (dev_priv->card_type < NV_10) {
+       if (nv_device(drm->device)->card_type < NV_10) {
                dev->mode_config.max_width = 2048;
                dev->mode_config.max_height = 2048;
        } else
-       if (dev_priv->card_type < NV_50) {
+       if (nv_device(drm->device)->card_type < NV_50) {
                dev->mode_config.max_width = 4096;
                dev->mode_config.max_height = 4096;
        } else {
        drm_kms_helper_poll_init(dev);
        drm_kms_helper_poll_disable(dev);
  
-       ret = disp->create(dev);
+       if (nv_device(drm->device)->card_type < NV_50)
+               ret = nv04_display_create(dev);
+       else
+       if (nv_device(drm->device)->card_type < NV_D0)
+               ret = nv50_display_create(dev);
+       else
+               ret = nvd0_display_create(dev);
        if (ret)
                goto disp_create_err;
  
                        goto vblank_err;
        }
  
+       nouveau_backlight_init(dev);
        return 0;
  
  vblank_err:
-       disp->destroy(dev);
+       disp->dtor(dev);
  disp_create_err:
        drm_kms_helper_poll_fini(dev);
        drm_mode_config_cleanup(dev);
  void
  nouveau_display_destroy(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_display_engine *disp = &dev_priv->engine.display;
+       struct nouveau_display *disp = nouveau_display(dev);
  
+       nouveau_backlight_exit(dev);
        drm_vblank_cleanup(dev);
  
-       disp->destroy(dev);
+       disp->dtor(dev);
  
        drm_kms_helper_poll_fini(dev);
        drm_mode_config_cleanup(dev);
+       nouveau_drm(dev)->display = NULL;
+       kfree(disp);
+ }
+ int
+ nouveau_display_suspend(struct drm_device *dev)
+ {
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct drm_crtc *crtc;
+       nouveau_display_fini(dev);
+       NV_INFO(drm, "unpinning framebuffer(s)...\n");
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct nouveau_framebuffer *nouveau_fb;
+               nouveau_fb = nouveau_framebuffer(crtc->fb);
+               if (!nouveau_fb || !nouveau_fb->nvbo)
+                       continue;
+               nouveau_bo_unpin(nouveau_fb->nvbo);
+       }
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+               nouveau_bo_unmap(nv_crtc->cursor.nvbo);
+               nouveau_bo_unpin(nv_crtc->cursor.nvbo);
+       }
+       return 0;
+ }
+ void
+ nouveau_display_resume(struct drm_device *dev)
+ {
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct drm_crtc *crtc;
+       int ret;
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct nouveau_framebuffer *nouveau_fb;
+               nouveau_fb = nouveau_framebuffer(crtc->fb);
+               if (!nouveau_fb || !nouveau_fb->nvbo)
+                       continue;
+               nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM);
+       }
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+               ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
+               if (!ret)
+                       ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
+               if (ret)
+                       NV_ERROR(drm, "Could not pin/map cursor.\n");
+       }
+       nouveau_fbcon_set_suspend(dev, 0);
+       nouveau_fbcon_zfill_all(dev);
+       nouveau_display_init(dev);
+       /* Force CLUT to get re-loaded during modeset */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+               nv_crtc->lut.depth = 0;
+       }
+       drm_helper_resume_force_mode(dev);
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+               u32 offset = nv_crtc->cursor.nvbo->bo.offset;
+               nv_crtc->cursor.set_offset(nv_crtc, offset);
+               nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x,
+                                                nv_crtc->cursor_saved_y);
+       }
  }
  
  int
  nouveau_vblank_enable(struct drm_device *dev, int crtc)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
  
-       if (dev_priv->card_type >= NV_50)
-               nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0,
+       if (device->card_type >= NV_D0)
+               nv_mask(device, 0x6100c0 + (crtc * 0x800), 1, 1);
+       else
+       if (device->card_type >= NV_50)
+               nv_mask(device, NV50_PDISPLAY_INTR_EN_1, 0,
                        NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc));
        else
                NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0,
  void
  nouveau_vblank_disable(struct drm_device *dev, int crtc)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
  
-       if (dev_priv->card_type >= NV_50)
-               nv_mask(dev, NV50_PDISPLAY_INTR_EN_1,
+       if (device->card_type >= NV_D0)
+               nv_mask(device, 0x6100c0 + (crtc * 0x800), 1, 0);
+       else
+       if (device->card_type >= NV_50)
+               nv_mask(device, NV50_PDISPLAY_INTR_EN_1,
                        NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0);
        else
                NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0);
@@@ -434,15 -564,15 +564,15 @@@ nouveau_page_flip_emit(struct nouveau_c
                       struct nouveau_page_flip_state *s,
                       struct nouveau_fence **pfence)
  {
-       struct nouveau_software_chan *swch = chan->engctx[NVOBJ_ENGINE_SW];
-       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-       struct drm_device *dev = chan->dev;
+       struct nouveau_fence_chan *fctx = chan->fence;
+       struct nouveau_drm *drm = chan->drm;
+       struct drm_device *dev = drm->dev;
        unsigned long flags;
        int ret;
  
        /* Queue it to the pending list */
        spin_lock_irqsave(&dev->event_lock, flags);
-       list_add_tail(&s->head, &swch->flip);
+       list_add_tail(&s->head, &fctx->flip);
        spin_unlock_irqrestore(&dev->event_lock, flags);
  
        /* Synchronize with the old framebuffer */
        if (ret)
                goto fail;
  
-       if (dev_priv->card_type < NV_C0) {
+       if (nv_device(drm->device)->card_type < NV_C0) {
                BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
                OUT_RING  (chan, 0x00000000);
                OUT_RING  (chan, 0x00000000);
@@@ -483,7 -613,7 +613,7 @@@ nouveau_crtc_page_flip(struct drm_crtc 
                       struct drm_pending_vblank_event *event)
  {
        struct drm_device *dev = crtc->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
        struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
        struct nouveau_page_flip_state *s;
        struct nouveau_fence *fence;
        int ret;
  
-       if (!dev_priv->channel)
+       if (!drm->channel)
                return -ENODEV;
  
        s = kzalloc(sizeof(*s), GFP_KERNEL);
        /* Choose the channel the flip will be handled in */
        fence = new_bo->bo.sync_obj;
        if (fence)
-               chan = nouveau_channel_get_unlocked(fence->channel);
+               chan = fence->channel;
        if (!chan)
-               chan = nouveau_channel_get_unlocked(dev_priv->channel);
-       mutex_lock(&chan->mutex);
+               chan = drm->channel;
+       mutex_lock(&chan->cli->mutex);
  
        /* Emit a page flip */
-       if (dev_priv->card_type >= NV_50) {
-               if (dev_priv->card_type >= NV_D0)
+       if (nv_device(drm->device)->card_type >= NV_50) {
+               if (nv_device(drm->device)->card_type >= NV_D0)
                        ret = nvd0_display_flip_next(crtc, fb, chan, 0);
                else
                        ret = nv50_display_flip_next(crtc, fb, chan);
                if (ret) {
-                       nouveau_channel_put(&chan);
+                       mutex_unlock(&chan->cli->mutex);
                        goto fail_unreserve;
                }
        }
  
        ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
-       nouveau_channel_put(&chan);
+       mutex_unlock(&chan->cli->mutex);
        if (ret)
                goto fail_unreserve;
  
@@@ -552,20 -682,21 +682,21 @@@ in
  nouveau_finish_page_flip(struct nouveau_channel *chan,
                         struct nouveau_page_flip_state *ps)
  {
-       struct nouveau_software_chan *swch = chan->engctx[NVOBJ_ENGINE_SW];
-       struct drm_device *dev = chan->dev;
+       struct nouveau_fence_chan *fctx = chan->fence;
+       struct nouveau_drm *drm = chan->drm;
+       struct drm_device *dev = drm->dev;
        struct nouveau_page_flip_state *s;
        unsigned long flags;
  
        spin_lock_irqsave(&dev->event_lock, flags);
  
-       if (list_empty(&swch->flip)) {
-               NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id);
+       if (list_empty(&fctx->flip)) {
+               NV_ERROR(drm, "unexpected pageflip\n");
                spin_unlock_irqrestore(&dev->event_lock, flags);
                return -EINVAL;
        }
  
-       s = list_first_entry(&swch->flip, struct nouveau_page_flip_state, head);
+       s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head);
        if (s->event) {
                struct drm_pending_vblank_event *e = s->event;
                struct timeval now;
  }
  
  int
+ nouveau_flip_complete(void *data)
+ {
+       struct nouveau_channel *chan = data;
+       struct nouveau_drm *drm = chan->drm;
+       struct nouveau_page_flip_state state;
+       if (!nouveau_finish_page_flip(chan, &state)) {
+               if (nv_device(drm->device)->card_type < NV_50) {
+                       nv_set_crtc_base(drm->dev, state.crtc, state.offset +
+                                        state.y * state.pitch +
+                                        state.x * state.bpp / 8);
+               }
+       }
+       return 0;
+ }
+ int
  nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
                            struct drm_mode_create_dumb *args)
  {
   * Authors: Ben Skeggs
   */
  
 -#include "drmP.h"
 -#include "drm_dp_helper.h"
 +#include <drm/drmP.h>
++#include <drm/drm_dp_helper.h>
  
- #include "nouveau_drv.h"
- #include "nouveau_i2c.h"
+ #include "nouveau_drm.h"
  #include "nouveau_connector.h"
  #include "nouveau_encoder.h"
  #include "nouveau_crtc.h"
- #include "nouveau_gpio.h"
  
- /******************************************************************************
-  * aux channel util functions
-  *****************************************************************************/
- #define AUX_DBG(fmt, args...) do {                                             \
-       if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_AUXCH) {                     \
-               NV_PRINTK(KERN_DEBUG, dev, "AUXCH(%d): " fmt, ch, ##args);     \
-       }                                                                      \
- } while (0)
- #define AUX_ERR(fmt, args...) NV_ERROR(dev, "AUXCH(%d): " fmt, ch, ##args)
- static void
- auxch_fini(struct drm_device *dev, int ch)
- {
-       nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
- }
- static int
- auxch_init(struct drm_device *dev, int ch)
- {
-       const u32 unksel = 1; /* nfi which to use, or if it matters.. */
-       const u32 ureq = unksel ? 0x00100000 : 0x00200000;
-       const u32 urep = unksel ? 0x01000000 : 0x02000000;
-       u32 ctrl, timeout;
-       /* wait up to 1ms for any previous transaction to be done... */
-       timeout = 1000;
-       do {
-               ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
-               udelay(1);
-               if (!timeout--) {
-                       AUX_ERR("begin idle timeout 0x%08x", ctrl);
-                       return -EBUSY;
-               }
-       } while (ctrl & 0x03010000);
-       /* set some magic, and wait up to 1ms for it to appear */
-       nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq);
-       timeout = 1000;
-       do {
-               ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
-               udelay(1);
-               if (!timeout--) {
-                       AUX_ERR("magic wait 0x%08x\n", ctrl);
-                       auxch_fini(dev, ch);
-                       return -EBUSY;
-               }
-       } while ((ctrl & 0x03000000) != urep);
-       return 0;
- }
- static int
- auxch_tx(struct drm_device *dev, int ch, u8 type, u32 addr, u8 *data, u8 size)
- {
-       u32 ctrl, stat, timeout, retries;
-       u32 xbuf[4] = {};
-       int ret, i;
-       AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
-       ret = auxch_init(dev, ch);
-       if (ret)
-               goto out;
-       stat = nv_rd32(dev, 0x00e4e8 + (ch * 0x50));
-       if (!(stat & 0x10000000)) {
-               AUX_DBG("sink not detected\n");
-               ret = -ENXIO;
-               goto out;
-       }
-       if (!(type & 1)) {
-               memcpy(xbuf, data, size);
-               for (i = 0; i < 16; i += 4) {
-                       AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
-                       nv_wr32(dev, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]);
-               }
-       }
-       ctrl  = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
-       ctrl &= ~0x0001f0ff;
-       ctrl |= type << 12;
-       ctrl |= size - 1;
-       nv_wr32(dev, 0x00e4e0 + (ch * 0x50), addr);
-       /* retry transaction a number of times on failure... */
-       ret = -EREMOTEIO;
-       for (retries = 0; retries < 32; retries++) {
-               /* reset, and delay a while if this is a retry */
-               nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
-               nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
-               if (retries)
-                       udelay(400);
-               /* transaction request, wait up to 1ms for it to complete */
-               nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl);
-               timeout = 1000;
-               do {
-                       ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
-                       udelay(1);
-                       if (!timeout--) {
-                               AUX_ERR("tx req timeout 0x%08x\n", ctrl);
-                               goto out;
-                       }
-               } while (ctrl & 0x00010000);
-               /* read status, and check if transaction completed ok */
-               stat = nv_mask(dev, 0x00e4e8 + (ch * 0x50), 0, 0);
-               if (!(stat & 0x000f0f00)) {
-                       ret = 0;
-                       break;
-               }
-               AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
-       }
-       if (type & 1) {
-               for (i = 0; i < 16; i += 4) {
-                       xbuf[i / 4] = nv_rd32(dev, 0x00e4d0 + (ch * 0x50) + i);
-                       AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
-               }
-               memcpy(data, xbuf, size);
-       }
- out:
-       auxch_fini(dev, ch);
-       return ret;
- }
+ #include <subdev/gpio.h>
+ #include <subdev/i2c.h>
  
  u8 *
- nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
+ nouveau_dp_bios_data(struct drm_device *dev, struct dcb_output *dcb, u8 **entry)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct bit_entry d;
        u8 *table;
        int i;
  
        if (bit_table(dev, 'd', &d)) {
-               NV_ERROR(dev, "BIT 'd' table not found\n");
+               NV_ERROR(drm, "BIT 'd' table not found\n");
                return NULL;
        }
  
        if (d.version != 1) {
-               NV_ERROR(dev, "BIT 'd' table version %d unknown\n", d.version);
+               NV_ERROR(drm, "BIT 'd' table version %d unknown\n", d.version);
                return NULL;
        }
  
        table = ROMPTR(dev, d.data[0]);
        if (!table) {
-               NV_ERROR(dev, "displayport table pointer invalid\n");
+               NV_ERROR(drm, "displayport table pointer invalid\n");
                return NULL;
        }
  
        case 0x40:
                break;
        default:
-               NV_ERROR(dev, "displayport table 0x%02x unknown\n", table[0]);
+               NV_ERROR(drm, "displayport table 0x%02x unknown\n", table[0]);
                return NULL;
        }
  
                        return table;
        }
  
-       NV_ERROR(dev, "displayport encoder table not found\n");
+       NV_ERROR(drm, "displayport encoder table not found\n");
        return NULL;
  }
  
   * link training
   *****************************************************************************/
  struct dp_state {
+       struct nouveau_i2c_port *auxch;
        struct dp_train_func *func;
-       struct dcb_entry *dcb;
-       int auxch;
+       struct dcb_output *dcb;
        int crtc;
        u8 *dpcd;
        int link_nr;
  static void
  dp_set_link_config(struct drm_device *dev, struct dp_state *dp)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        u8 sink[2];
  
-       NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
+       NV_DEBUG(drm, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
  
        /* set desired link configuration on the source */
        dp->func->link_set(dev, dp->dcb, dp->crtc, dp->link_nr, dp->link_bw,
        if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)
                sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
  
-       auxch_tx(dev, dp->auxch, 8, DP_LINK_BW_SET, sink, 2);
+       nv_wraux(dp->auxch, DP_LINK_BW_SET, sink, 2);
  }
  
  static void
  dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 pattern)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        u8 sink_tp;
  
-       NV_DEBUG_KMS(dev, "training pattern %d\n", pattern);
+       NV_DEBUG(drm, "training pattern %d\n", pattern);
  
        dp->func->train_set(dev, dp->dcb, pattern);
  
-       auxch_tx(dev, dp->auxch, 9, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
+       nv_rdaux(dp->auxch, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
        sink_tp &= ~DP_TRAINING_PATTERN_MASK;
        sink_tp |= pattern;
-       auxch_tx(dev, dp->auxch, 8, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
+       nv_wraux(dp->auxch, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
  }
  
  static int
  dp_link_train_commit(struct drm_device *dev, struct dp_state *dp)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        int i;
  
        for (i = 0; i < dp->link_nr; i++) {
                if ((lpre << 3) == DP_TRAIN_PRE_EMPHASIS_9_5)
                        dp->conf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
  
-               NV_DEBUG_KMS(dev, "config lane %d %02x\n", i, dp->conf[i]);
+               NV_DEBUG(drm, "config lane %d %02x\n", i, dp->conf[i]);
                dp->func->train_adj(dev, dp->dcb, i, lvsw, lpre);
        }
  
-       return auxch_tx(dev, dp->auxch, 8, DP_TRAINING_LANE0_SET, dp->conf, 4);
+       return nv_wraux(dp->auxch, DP_TRAINING_LANE0_SET, dp->conf, 4);
  }
  
  static int
  dp_link_train_update(struct drm_device *dev, struct dp_state *dp, u32 delay)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        int ret;
  
        udelay(delay);
  
-       ret = auxch_tx(dev, dp->auxch, 9, DP_LANE0_1_STATUS, dp->stat, 6);
+       ret = nv_rdaux(dp->auxch, DP_LANE0_1_STATUS, dp->stat, 6);
        if (ret)
                return ret;
  
-       NV_DEBUG_KMS(dev, "status %02x %02x %02x %02x %02x %02x\n",
-                    dp->stat[0], dp->stat[1], dp->stat[2], dp->stat[3],
-                    dp->stat[4], dp->stat[5]);
+       NV_DEBUG(drm, "status %*ph\n", 6, dp->stat);
        return 0;
  }
  
@@@ -409,7 -284,7 +284,7 @@@ dp_link_train_fini(struct drm_device *d
        nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
  }
  
- bool
static bool
  nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
                      struct dp_train_func *func)
  {
        struct nouveau_connector *nv_connector =
                nouveau_encoder_connector_get(nv_encoder);
        struct drm_device *dev = encoder->dev;
-       struct nouveau_i2c_chan *auxch;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
+       struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
        const u32 bw_list[] = { 270000, 162000, 0 };
        const u32 *link_bw = bw_list;
        struct dp_state dp;
  
-       auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
-       if (!auxch)
+       dp.auxch = i2c->find(i2c, nv_encoder->dcb->i2c_index);
+       if (!dp.auxch)
                return false;
  
        dp.func = func;
        dp.dcb = nv_encoder->dcb;
        dp.crtc = nv_crtc->index;
-       dp.auxch = auxch->drive;
        dp.dpcd = nv_encoder->dp.dpcd;
  
        /* adjust required bandwidth for 8B/10B coding overhead */
         * we take during link training (DP_SET_POWER is one), we need
         * to ignore them for the moment to avoid races.
         */
-       nouveau_gpio_irq(dev, 0, nv_connector->hpd, 0xff, false);
+       gpio->irq(gpio, 0, nv_connector->hpd, 0xff, false);
  
        /* enable down-spreading, if possible */
        dp_set_downspread(dev, &dp, nv_encoder->dp.dpcd[3] & 1);
        dp_link_train_fini(dev, &dp);
  
        /* re-enable hotplug detect */
-       nouveau_gpio_irq(dev, 0, nv_connector->hpd, 0xff, true);
+       gpio->irq(gpio, 0, nv_connector->hpd, 0xff, true);
        return true;
  }
  
@@@ -492,10 -368,12 +368,12 @@@ nouveau_dp_dpms(struct drm_encoder *enc
                struct dp_train_func *func)
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-       struct nouveau_i2c_chan *auxch;
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+       struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
+       struct nouveau_i2c_port *auxch;
        u8 status;
  
-       auxch = nouveau_i2c_find(encoder->dev, nv_encoder->dcb->i2c_index);
+       auxch = i2c->find(i2c, nv_encoder->dcb->i2c_index);
        if (!auxch)
                return;
  
        else
                status = DP_SET_POWER_D3;
  
-       nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
+       nv_wraux(auxch, DP_SET_POWER, &status, 1);
  
        if (mode == DRM_MODE_DPMS_ON)
                nouveau_dp_link_train(encoder, datarate, func);
  }
  
  static void
- nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_chan *auxch,
+ nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch,
                     u8 *dpcd)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        u8 buf[3];
  
        if (!(dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
                return;
  
-       if (!auxch_tx(dev, auxch->drive, 9, DP_SINK_OUI, buf, 3))
-               NV_DEBUG_KMS(dev, "Sink OUI: %02hx%02hx%02hx\n",
+       if (!nv_rdaux(auxch, DP_SINK_OUI, buf, 3))
+               NV_DEBUG(drm, "Sink OUI: %02hx%02hx%02hx\n",
                             buf[0], buf[1], buf[2]);
  
-       if (!auxch_tx(dev, auxch->drive, 9, DP_BRANCH_OUI, buf, 3))
-               NV_DEBUG_KMS(dev, "Branch OUI: %02hx%02hx%02hx\n",
+       if (!nv_rdaux(auxch, DP_BRANCH_OUI, buf, 3))
+               NV_DEBUG(drm, "Branch OUI: %02hx%02hx%02hx\n",
                             buf[0], buf[1], buf[2]);
  
  }
@@@ -534,24 -413,26 +413,26 @@@ nouveau_dp_detect(struct drm_encoder *e
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_device *dev = encoder->dev;
-       struct nouveau_i2c_chan *auxch;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
+       struct nouveau_i2c_port *auxch;
        u8 *dpcd = nv_encoder->dp.dpcd;
        int ret;
  
-       auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
+       auxch = i2c->find(i2c, nv_encoder->dcb->i2c_index);
        if (!auxch)
                return false;
  
-       ret = auxch_tx(dev, auxch->drive, 9, DP_DPCD_REV, dpcd, 8);
+       ret = nv_rdaux(auxch, DP_DPCD_REV, dpcd, 8);
        if (ret)
                return false;
  
        nv_encoder->dp.link_bw = 27000 * dpcd[1];
        nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK;
  
-       NV_DEBUG_KMS(dev, "display: %dx%d dpcd 0x%02x\n",
+       NV_DEBUG(drm, "display: %dx%d dpcd 0x%02x\n",
                     nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, dpcd[0]);
-       NV_DEBUG_KMS(dev, "encoder: %dx%d\n",
+       NV_DEBUG(drm, "encoder: %dx%d\n",
                     nv_encoder->dcb->dpconf.link_nr,
                     nv_encoder->dcb->dpconf.link_bw);
  
        if (nv_encoder->dcb->dpconf.link_bw < nv_encoder->dp.link_bw)
                nv_encoder->dp.link_bw = nv_encoder->dcb->dpconf.link_bw;
  
-       NV_DEBUG_KMS(dev, "maximum: %dx%d\n",
+       NV_DEBUG(drm, "maximum: %dx%d\n",
                     nv_encoder->dp.link_nr, nv_encoder->dp.link_bw);
  
        nouveau_dp_probe_oui(dev, auxch, dpcd);
  
        return true;
  }
- int
- nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
-                uint8_t *data, int data_nr)
- {
-       return auxch_tx(auxch->dev, auxch->drive, cmd, addr, data, data_nr);
- }
- static int
- nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
- {
-       struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap;
-       struct i2c_msg *msg = msgs;
-       int ret, mcnt = num;
-       while (mcnt--) {
-               u8 remaining = msg->len;
-               u8 *ptr = msg->buf;
-               while (remaining) {
-                       u8 cnt = (remaining > 16) ? 16 : remaining;
-                       u8 cmd;
-                       if (msg->flags & I2C_M_RD)
-                               cmd = AUX_I2C_READ;
-                       else
-                               cmd = AUX_I2C_WRITE;
-                       if (mcnt || remaining > 16)
-                               cmd |= AUX_I2C_MOT;
-                       ret = nouveau_dp_auxch(auxch, cmd, msg->addr, ptr, cnt);
-                       if (ret < 0)
-                               return ret;
-                       ptr += cnt;
-                       remaining -= cnt;
-               }
-               msg++;
-       }
-       return num;
- }
- static u32
- nouveau_dp_i2c_func(struct i2c_adapter *adap)
- {
-       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
- }
- const struct i2c_algorithm nouveau_dp_i2c_algo = {
-       .master_xfer = nouveau_dp_i2c_xfer,
-       .functionality = nouveau_dp_i2c_func
- };
index 0000000,e96507e..ccae8c2
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,693 +1,693 @@@
 -      snprintf(name, sizeof(name), "%d", fpriv->pid);
+ /*
+  * Copyright 2012 Red Hat Inc.
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+  * copy of this software and associated documentation files (the "Software"),
+  * to deal in the Software without restriction, including without limitation
+  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+  * and/or sell copies of the Software, and to permit persons to whom the
+  * Software is furnished to do so, subject to the following conditions:
+  *
+  * The above copyright notice and this permission notice shall be included in
+  * all copies or substantial portions of the Software.
+  *
+  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  * OTHER DEALINGS IN THE SOFTWARE.
+  *
+  * Authors: Ben Skeggs
+  */
+ #include <linux/console.h>
+ #include <linux/module.h>
+ #include <linux/pci.h>
+ #include <core/device.h>
+ #include <core/client.h>
+ #include <core/gpuobj.h>
+ #include <core/class.h>
+ #include <subdev/device.h>
+ #include <subdev/vm.h>
+ #include "nouveau_drm.h"
+ #include "nouveau_irq.h"
+ #include "nouveau_dma.h"
+ #include "nouveau_ttm.h"
+ #include "nouveau_gem.h"
+ #include "nouveau_agp.h"
+ #include "nouveau_vga.h"
+ #include "nouveau_pm.h"
+ #include "nouveau_acpi.h"
+ #include "nouveau_bios.h"
+ #include "nouveau_ioctl.h"
+ #include "nouveau_abi16.h"
+ #include "nouveau_fbcon.h"
+ #include "nouveau_fence.h"
+ #include "nouveau_ttm.h"
+ MODULE_PARM_DESC(config, "option string to pass to driver core");
+ static char *nouveau_config;
+ module_param_named(config, nouveau_config, charp, 0400);
+ MODULE_PARM_DESC(debug, "debug string to pass to driver core");
+ static char *nouveau_debug;
+ module_param_named(debug, nouveau_debug, charp, 0400);
+ MODULE_PARM_DESC(noaccel, "disable kernel/abi16 acceleration");
+ static int nouveau_noaccel = 0;
+ module_param_named(noaccel, nouveau_noaccel, int, 0400);
+ MODULE_PARM_DESC(modeset, "enable driver");
+ static int nouveau_modeset = -1;
+ module_param_named(modeset, nouveau_modeset, int, 0400);
+ static struct drm_driver driver;
+ static u64
+ nouveau_name(struct pci_dev *pdev)
+ {
+       u64 name = (u64)pci_domain_nr(pdev->bus) << 32;
+       name |= pdev->bus->number << 16;
+       name |= PCI_SLOT(pdev->devfn) << 8;
+       return name | PCI_FUNC(pdev->devfn);
+ }
+ static int
+ nouveau_cli_create(struct pci_dev *pdev, const char *name,
+                  int size, void **pcli)
+ {
+       struct nouveau_cli *cli;
+       int ret;
+       ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config,
+                                    nouveau_debug, size, pcli);
+       cli = *pcli;
+       if (ret)
+               return ret;
+       mutex_init(&cli->mutex);
+       return 0;
+ }
+ static void
+ nouveau_cli_destroy(struct nouveau_cli *cli)
+ {
+       struct nouveau_object *client = nv_object(cli);
+       nouveau_vm_ref(NULL, &cli->base.vm, NULL);
+       nouveau_client_fini(&cli->base, false);
+       atomic_set(&client->refcount, 1);
+       nouveau_object_ref(NULL, &client);
+ }
+ static void
+ nouveau_accel_fini(struct nouveau_drm *drm)
+ {
+       nouveau_gpuobj_ref(NULL, &drm->notify);
+       nouveau_channel_del(&drm->channel);
+       nouveau_channel_del(&drm->cechan);
+       if (drm->fence)
+               nouveau_fence(drm)->dtor(drm);
+ }
+ static void
+ nouveau_accel_init(struct nouveau_drm *drm)
+ {
+       struct nouveau_device *device = nv_device(drm->device);
+       struct nouveau_object *object;
+       u32 arg0, arg1;
+       int ret;
+       if (nouveau_noaccel)
+               return;
+       /* initialise synchronisation routines */
+       if      (device->card_type < NV_10) ret = nv04_fence_create(drm);
+       else if (device->chipset   <  0x84) ret = nv10_fence_create(drm);
+       else if (device->card_type < NV_C0) ret = nv84_fence_create(drm);
+       else                                ret = nvc0_fence_create(drm);
+       if (ret) {
+               NV_ERROR(drm, "failed to initialise sync subsystem, %d\n", ret);
+               nouveau_accel_fini(drm);
+               return;
+       }
+       if (device->card_type >= NV_E0) {
+               ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE,
+                                         NVDRM_CHAN + 1,
+                                         NVE0_CHANNEL_IND_ENGINE_CE0 |
+                                         NVE0_CHANNEL_IND_ENGINE_CE1, 0,
+                                         &drm->cechan);
+               if (ret)
+                       NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
+               arg0 = NVE0_CHANNEL_IND_ENGINE_GR;
+               arg1 = 0;
+       } else {
+               arg0 = NvDmaFB;
+               arg1 = NvDmaTT;
+       }
+       ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, NVDRM_CHAN,
+                                 arg0, arg1, &drm->channel);
+       if (ret) {
+               NV_ERROR(drm, "failed to create kernel channel, %d\n", ret);
+               nouveau_accel_fini(drm);
+               return;
+       }
+       if (device->card_type < NV_C0) {
+               ret = nouveau_gpuobj_new(drm->device, NULL, 32, 0, 0,
+                                       &drm->notify);
+               if (ret) {
+                       NV_ERROR(drm, "failed to allocate notifier, %d\n", ret);
+                       nouveau_accel_fini(drm);
+                       return;
+               }
+               ret = nouveau_object_new(nv_object(drm),
+                                        drm->channel->handle, NvNotify0,
+                                        0x003d, &(struct nv_dma_class) {
+                                               .flags = NV_DMA_TARGET_VRAM |
+                                                        NV_DMA_ACCESS_RDWR,
+                                               .start = drm->notify->addr,
+                                               .limit = drm->notify->addr + 31
+                                               }, sizeof(struct nv_dma_class),
+                                        &object);
+               if (ret) {
+                       nouveau_accel_fini(drm);
+                       return;
+               }
+       }
+       nouveau_bo_move_init(drm);
+ }
+ static int __devinit
+ nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent)
+ {
+       struct nouveau_device *device;
+       struct apertures_struct *aper;
+       bool boot = false;
+       int ret;
+       /* remove conflicting drivers (vesafb, efifb etc) */
+       aper = alloc_apertures(3);
+       if (!aper)
+               return -ENOMEM;
+       aper->ranges[0].base = pci_resource_start(pdev, 1);
+       aper->ranges[0].size = pci_resource_len(pdev, 1);
+       aper->count = 1;
+       if (pci_resource_len(pdev, 2)) {
+               aper->ranges[aper->count].base = pci_resource_start(pdev, 2);
+               aper->ranges[aper->count].size = pci_resource_len(pdev, 2);
+               aper->count++;
+       }
+       if (pci_resource_len(pdev, 3)) {
+               aper->ranges[aper->count].base = pci_resource_start(pdev, 3);
+               aper->ranges[aper->count].size = pci_resource_len(pdev, 3);
+               aper->count++;
+       }
+ #ifdef CONFIG_X86
+       boot = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
+ #endif
+       remove_conflicting_framebuffers(aper, "nouveaufb", boot);
+       ret = nouveau_device_create(pdev, nouveau_name(pdev), pci_name(pdev),
+                                   nouveau_config, nouveau_debug, &device);
+       if (ret)
+               return ret;
+       pci_set_master(pdev);
+       ret = drm_get_pci_dev(pdev, pent, &driver);
+       if (ret) {
+               nouveau_object_ref(NULL, (struct nouveau_object **)&device);
+               return ret;
+       }
+       return 0;
+ }
+ static int
+ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
+ {
+       struct pci_dev *pdev = dev->pdev;
+       struct nouveau_device *device;
+       struct nouveau_drm *drm;
+       int ret;
+       ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
+       if (ret)
+               return ret;
+       dev->dev_private = drm;
+       drm->dev = dev;
+       INIT_LIST_HEAD(&drm->clients);
+       spin_lock_init(&drm->tile.lock);
+       /* make sure AGP controller is in a consistent state before we
+        * (possibly) execute vbios init tables (see nouveau_agp.h)
+        */
+       if (drm_pci_device_is_agp(dev) && dev->agp) {
+               /* dummy device object, doesn't init anything, but allows
+                * agp code access to registers
+                */
+               ret = nouveau_object_new(nv_object(drm), NVDRM_CLIENT,
+                                        NVDRM_DEVICE, 0x0080,
+                                        &(struct nv_device_class) {
+                                               .device = ~0,
+                                               .disable =
+                                                ~(NV_DEVICE_DISABLE_MMIO |
+                                                  NV_DEVICE_DISABLE_IDENTIFY),
+                                               .debug0 = ~0,
+                                        }, sizeof(struct nv_device_class),
+                                        &drm->device);
+               if (ret)
+                       goto fail_device;
+               nouveau_agp_reset(drm);
+               nouveau_object_del(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE);
+       }
+       ret = nouveau_object_new(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE,
+                                0x0080, &(struct nv_device_class) {
+                                       .device = ~0,
+                                       .disable = 0,
+                                       .debug0 = 0,
+                                }, sizeof(struct nv_device_class),
+                                &drm->device);
+       if (ret)
+               goto fail_device;
+       /* workaround an odd issue on nvc1 by disabling the device's
+        * nosnoop capability.  hopefully won't cause issues until a
+        * better fix is found - assuming there is one...
+        */
+       device = nv_device(drm->device);
+       if (nv_device(drm->device)->chipset == 0xc1)
+               nv_mask(device, 0x00088080, 0x00000800, 0x00000000);
+       nouveau_vga_init(drm);
+       nouveau_agp_init(drm);
+       if (device->card_type >= NV_50) {
+               ret = nouveau_vm_new(nv_device(drm->device), 0, (1ULL << 40),
+                                    0x1000, &drm->client.base.vm);
+               if (ret)
+                       goto fail_device;
+       }
+       ret = nouveau_ttm_init(drm);
+       if (ret)
+               goto fail_ttm;
+       ret = nouveau_bios_init(dev);
+       if (ret)
+               goto fail_bios;
+       ret = nouveau_irq_init(dev);
+       if (ret)
+               goto fail_irq;
+       ret = nouveau_display_create(dev);
+       if (ret)
+               goto fail_dispctor;
+       if (dev->mode_config.num_crtc) {
+               ret = nouveau_display_init(dev);
+               if (ret)
+                       goto fail_dispinit;
+       }
+       nouveau_pm_init(dev);
+       nouveau_accel_init(drm);
+       nouveau_fbcon_init(dev);
+       return 0;
+ fail_dispinit:
+       nouveau_display_destroy(dev);
+ fail_dispctor:
+       nouveau_irq_fini(dev);
+ fail_irq:
+       nouveau_bios_takedown(dev);
+ fail_bios:
+       nouveau_ttm_fini(drm);
+ fail_ttm:
+       nouveau_agp_fini(drm);
+       nouveau_vga_fini(drm);
+ fail_device:
+       nouveau_cli_destroy(&drm->client);
+       return ret;
+ }
+ static int
+ nouveau_drm_unload(struct drm_device *dev)
+ {
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       nouveau_fbcon_fini(dev);
+       nouveau_accel_fini(drm);
+       nouveau_pm_fini(dev);
+       nouveau_display_fini(dev);
+       nouveau_display_destroy(dev);
+       nouveau_irq_fini(dev);
+       nouveau_bios_takedown(dev);
+       nouveau_ttm_fini(drm);
+       nouveau_agp_fini(drm);
+       nouveau_vga_fini(drm);
+       nouveau_cli_destroy(&drm->client);
+       return 0;
+ }
+ static void
+ nouveau_drm_remove(struct pci_dev *pdev)
+ {
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_object *device;
+       device = drm->client.base.device;
+       drm_put_dev(dev);
+       nouveau_object_ref(NULL, &device);
+       nouveau_object_debug();
+ }
+ int
+ nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state)
+ {
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_cli *cli;
+       int ret;
+       if (dev->switch_power_state == DRM_SWITCH_POWER_OFF ||
+           pm_state.event == PM_EVENT_PRETHAW)
+               return 0;
+       NV_INFO(drm, "suspending fbcon...\n");
+       nouveau_fbcon_set_suspend(dev, 1);
+       NV_INFO(drm, "suspending display...\n");
+       ret = nouveau_display_suspend(dev);
+       if (ret)
+               return ret;
+       NV_INFO(drm, "evicting buffers...\n");
+       ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM);
+       if (drm->fence && nouveau_fence(drm)->suspend) {
+               if (!nouveau_fence(drm)->suspend(drm))
+                       return -ENOMEM;
+       }
+       NV_INFO(drm, "suspending client object trees...\n");
+       list_for_each_entry(cli, &drm->clients, head) {
+               ret = nouveau_client_fini(&cli->base, true);
+               if (ret)
+                       goto fail_client;
+       }
+       ret = nouveau_client_fini(&drm->client.base, true);
+       if (ret)
+               goto fail_client;
+       nouveau_agp_fini(drm);
+       pci_save_state(pdev);
+       if (pm_state.event == PM_EVENT_SUSPEND) {
+               pci_disable_device(pdev);
+               pci_set_power_state(pdev, PCI_D3hot);
+       }
+       return 0;
+ fail_client:
+       list_for_each_entry_continue_reverse(cli, &drm->clients, head) {
+               nouveau_client_init(&cli->base);
+       }
+       NV_INFO(drm, "resuming display...\n");
+       nouveau_display_resume(dev);
+       return ret;
+ }
+ int
+ nouveau_drm_resume(struct pci_dev *pdev)
+ {
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_cli *cli;
+       int ret;
+       if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+               return 0;
+       NV_INFO(drm, "re-enabling device...\n");
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+       pci_set_master(pdev);
+       nouveau_agp_reset(drm);
+       NV_INFO(drm, "resuming client object trees...\n");
+       nouveau_client_init(&drm->client.base);
+       nouveau_agp_init(drm);
+       list_for_each_entry(cli, &drm->clients, head) {
+               nouveau_client_init(&cli->base);
+       }
+       if (drm->fence && nouveau_fence(drm)->resume)
+               nouveau_fence(drm)->resume(drm);
+       nouveau_run_vbios_init(dev);
+       nouveau_irq_postinstall(dev);
+       nouveau_pm_resume(dev);
+       NV_INFO(drm, "resuming display...\n");
+       nouveau_display_resume(dev);
+       return 0;
+ }
+ static int
+ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
+ {
+       struct pci_dev *pdev = dev->pdev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_cli *cli;
+       char name[16];
+       int ret;
++      snprintf(name, sizeof(name), "%d", pid_nr(fpriv->pid));
+       ret = nouveau_cli_create(pdev, name, sizeof(*cli), (void **)&cli);
+       if (ret)
+               return ret;
+       if (nv_device(drm->device)->card_type >= NV_50) {
+               ret = nouveau_vm_new(nv_device(drm->device), 0, (1ULL << 40),
+                                    0x1000, &cli->base.vm);
+               if (ret) {
+                       nouveau_cli_destroy(cli);
+                       return ret;
+               }
+       }
+       fpriv->driver_priv = cli;
+       mutex_lock(&drm->client.mutex);
+       list_add(&cli->head, &drm->clients);
+       mutex_unlock(&drm->client.mutex);
+       return 0;
+ }
+ static void
+ nouveau_drm_preclose(struct drm_device *dev, struct drm_file *fpriv)
+ {
+       struct nouveau_cli *cli = nouveau_cli(fpriv);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       if (cli->abi16)
+               nouveau_abi16_fini(cli->abi16);
+       mutex_lock(&drm->client.mutex);
+       list_del(&cli->head);
+       mutex_unlock(&drm->client.mutex);
+ }
+ static void
+ nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv)
+ {
+       struct nouveau_cli *cli = nouveau_cli(fpriv);
+       nouveau_cli_destroy(cli);
+ }
+ static struct drm_ioctl_desc
+ nouveau_ioctls[] = {
+       DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_abi16_ioctl_getparam, DRM_UNLOCKED|DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_abi16_ioctl_setparam, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_abi16_ioctl_channel_alloc, DRM_UNLOCKED|DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_abi16_ioctl_channel_free, DRM_UNLOCKED|DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_abi16_ioctl_grobj_alloc, DRM_UNLOCKED|DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_abi16_ioctl_notifierobj_alloc, DRM_UNLOCKED|DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_abi16_ioctl_gpuobj_free, DRM_UNLOCKED|DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_UNLOCKED|DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_UNLOCKED|DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_UNLOCKED|DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_UNLOCKED|DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_UNLOCKED|DRM_AUTH),
+ };
+ static const struct file_operations
+ nouveau_driver_fops = {
+       .owner = THIS_MODULE,
+       .open = drm_open,
+       .release = drm_release,
+       .unlocked_ioctl = drm_ioctl,
+       .mmap = nouveau_ttm_mmap,
+       .poll = drm_poll,
+       .fasync = drm_fasync,
+       .read = drm_read,
+ #if defined(CONFIG_COMPAT)
+       .compat_ioctl = nouveau_compat_ioctl,
+ #endif
+       .llseek = noop_llseek,
+ };
+ static struct drm_driver
+ driver = {
+       .driver_features =
+               DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG |
+               DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
+               DRIVER_MODESET | DRIVER_PRIME,
+       .load = nouveau_drm_load,
+       .unload = nouveau_drm_unload,
+       .open = nouveau_drm_open,
+       .preclose = nouveau_drm_preclose,
+       .postclose = nouveau_drm_postclose,
+       .lastclose = nouveau_vga_lastclose,
+       .irq_preinstall = nouveau_irq_preinstall,
+       .irq_postinstall = nouveau_irq_postinstall,
+       .irq_uninstall = nouveau_irq_uninstall,
+       .irq_handler = nouveau_irq_handler,
+       .get_vblank_counter = drm_vblank_count,
+       .enable_vblank = nouveau_vblank_enable,
+       .disable_vblank = nouveau_vblank_disable,
+       .ioctls = nouveau_ioctls,
+       .fops = &nouveau_driver_fops,
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+       .gem_prime_export = nouveau_gem_prime_export,
+       .gem_prime_import = nouveau_gem_prime_import,
+       .gem_init_object = nouveau_gem_object_new,
+       .gem_free_object = nouveau_gem_object_del,
+       .gem_open_object = nouveau_gem_object_open,
+       .gem_close_object = nouveau_gem_object_close,
+       .dumb_create = nouveau_display_dumb_create,
+       .dumb_map_offset = nouveau_display_dumb_map_offset,
+       .dumb_destroy = nouveau_display_dumb_destroy,
+       .name = DRIVER_NAME,
+       .desc = DRIVER_DESC,
+ #ifdef GIT_REVISION
+       .date = GIT_REVISION,
+ #else
+       .date = DRIVER_DATE,
+ #endif
+       .major = DRIVER_MAJOR,
+       .minor = DRIVER_MINOR,
+       .patchlevel = DRIVER_PATCHLEVEL,
+ };
+ static struct pci_device_id
+ nouveau_drm_pci_table[] = {
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
+               .class = PCI_BASE_CLASS_DISPLAY << 16,
+               .class_mask  = 0xff << 16,
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA_SGS, PCI_ANY_ID),
+               .class = PCI_BASE_CLASS_DISPLAY << 16,
+               .class_mask  = 0xff << 16,
+       },
+       {}
+ };
+ static struct pci_driver
+ nouveau_drm_pci_driver = {
+       .name = "nouveau",
+       .id_table = nouveau_drm_pci_table,
+       .probe = nouveau_drm_probe,
+       .remove = nouveau_drm_remove,
+       .suspend = nouveau_drm_suspend,
+       .resume = nouveau_drm_resume,
+ };
+ static int __init
+ nouveau_drm_init(void)
+ {
+       driver.num_ioctls = ARRAY_SIZE(nouveau_ioctls);
+       if (nouveau_modeset == -1) {
+ #ifdef CONFIG_VGA_CONSOLE
+               if (vgacon_text_force())
+                       nouveau_modeset = 0;
+               else
+ #endif
+                       nouveau_modeset = 1;
+       }
+       if (!nouveau_modeset)
+               return 0;
+       nouveau_register_dsm_handler();
+       return drm_pci_init(&driver, &nouveau_drm_pci_driver);
+ }
+ static void __exit
+ nouveau_drm_exit(void)
+ {
+       if (!nouveau_modeset)
+               return;
+       drm_pci_exit(&driver, &nouveau_drm_pci_driver);
+       nouveau_unregister_dsm_handler();
+ }
+ module_init(nouveau_drm_init);
+ module_exit(nouveau_drm_exit);
+ MODULE_DEVICE_TABLE(pci, nouveau_drm_pci_table);
+ MODULE_AUTHOR(DRIVER_AUTHOR);
+ MODULE_DESCRIPTION(DRIVER_DESC);
+ MODULE_LICENSE("GPL and additional rights");
index 0000000,3c12e98..8194712
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,144 +1,144 @@@
 -#include "ttm/ttm_bo_api.h"
 -#include "ttm/ttm_bo_driver.h"
 -#include "ttm/ttm_placement.h"
 -#include "ttm/ttm_memory.h"
 -#include "ttm/ttm_module.h"
 -#include "ttm/ttm_page_alloc.h"
+ #ifndef __NOUVEAU_DRMCLI_H__
+ #define __NOUVEAU_DRMCLI_H__
+ #define DRIVER_AUTHOR         "Nouveau Project"
+ #define DRIVER_EMAIL          "nouveau@lists.freedesktop.org"
+ #define DRIVER_NAME           "nouveau"
+ #define DRIVER_DESC           "nVidia Riva/TNT/GeForce/Quadro/Tesla"
+ #define DRIVER_DATE           "20120801"
+ #define DRIVER_MAJOR          1
+ #define DRIVER_MINOR          1
+ #define DRIVER_PATCHLEVEL     0
+ #include <core/client.h>
+ #include <subdev/vm.h>
+ #include <drmP.h>
+ #include <drm/nouveau_drm.h>
++#include <drm/ttm/ttm_bo_api.h>
++#include <drm/ttm/ttm_bo_driver.h>
++#include <drm/ttm/ttm_placement.h>
++#include <drm/ttm/ttm_memory.h>
++#include <drm/ttm/ttm_module.h>
++#include <drm/ttm/ttm_page_alloc.h>
+ struct nouveau_channel;
+ #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+ #include "nouveau_fence.h"
+ #include "nouveau_bios.h"
+ struct nouveau_drm_tile {
+       struct nouveau_fence *fence;
+       bool used;
+ };
+ enum nouveau_drm_handle {
+       NVDRM_CLIENT = 0xffffffff,
+       NVDRM_DEVICE = 0xdddddddd,
+       NVDRM_PUSH   = 0xbbbb0000, /* |= client chid */
+       NVDRM_CHAN   = 0xcccc0000, /* |= client chid */
+ };
+ struct nouveau_cli {
+       struct nouveau_client base;
+       struct list_head head;
+       struct mutex mutex;
+       void *abi16;
+ };
+ static inline struct nouveau_cli *
+ nouveau_cli(struct drm_file *fpriv)
+ {
+       return fpriv ? fpriv->driver_priv : NULL;
+ }
+ struct nouveau_drm {
+       struct nouveau_cli client;
+       struct drm_device *dev;
+       struct nouveau_object *device;
+       struct list_head clients;
+       struct {
+               enum {
+                       UNKNOWN = 0,
+                       DISABLE = 1,
+                       ENABLED = 2
+               } stat;
+               u32 base;
+               u32 size;
+       } agp;
+       /* TTM interface support */
+       struct {
+               struct drm_global_reference mem_global_ref;
+               struct ttm_bo_global_ref bo_global_ref;
+               struct ttm_bo_device bdev;
+               atomic_t validate_sequence;
+               int (*move)(struct nouveau_channel *,
+                           struct ttm_buffer_object *,
+                           struct ttm_mem_reg *, struct ttm_mem_reg *);
+               int mtrr;
+       } ttm;
+       /* GEM interface support */
+       struct {
+               u64 vram_available;
+               u64 gart_available;
+       } gem;
+       /* synchronisation */
+       void *fence;
+       /* context for accelerated drm-internal operations */
+       struct nouveau_channel *cechan;
+       struct nouveau_channel *channel;
+       struct nouveau_gpuobj *notify;
+       struct nouveau_fbdev *fbcon;
+       /* nv10-nv40 tiling regions */
+       struct {
+               struct nouveau_drm_tile reg[15];
+               spinlock_t lock;
+       } tile;
+       /* modesetting */
+       struct nvbios vbios;
+       struct nouveau_display *display;
+       struct backlight_device *backlight;
+       /* power management */
+       struct nouveau_pm *pm;
+ };
+ static inline struct nouveau_drm *
+ nouveau_drm(struct drm_device *dev)
+ {
+       return dev->dev_private;
+ }
+ static inline struct nouveau_device *
+ nouveau_dev(struct drm_device *dev)
+ {
+       return nv_device(nouveau_drm(dev)->device);
+ }
+ int nouveau_drm_suspend(struct pci_dev *, pm_message_t);
+ int nouveau_drm_resume(struct pci_dev *);
+ #define NV_FATAL(cli, fmt, args...) nv_fatal((cli), fmt, ##args)
+ #define NV_ERROR(cli, fmt, args...) nv_error((cli), fmt, ##args)
+ #define NV_WARN(cli, fmt, args...) nv_warn((cli), fmt, ##args)
+ #define NV_INFO(cli, fmt, args...) nv_info((cli), fmt, ##args)
+ #define NV_DEBUG(cli, fmt, args...) do {                                       \
+       if (drm_debug & DRM_UT_DRIVER)                                         \
+               nv_info((cli), fmt, ##args);                                   \
+ } while (0)
+ #endif
  #ifndef __NOUVEAU_ENCODER_H__
  #define __NOUVEAU_ENCODER_H__
  
 -#include "drm_encoder_slave.h"
+ #include <subdev/bios/dcb.h>
- #include "nouveau_drv.h"
 +#include <drm/drm_encoder_slave.h>
+ #include "nv04_display.h"
  
  #define NV_DPMS_CLEARED 0x80
  
+ struct nouveau_i2c_port;
  struct dp_train_func {
-       void (*link_set)(struct drm_device *, struct dcb_entry *, int crtc,
+       void (*link_set)(struct drm_device *, struct dcb_output *, int crtc,
                         int nr, u32 bw, bool enhframe);
-       void (*train_set)(struct drm_device *, struct dcb_entry *, u8 pattern);
-       void (*train_adj)(struct drm_device *, struct dcb_entry *,
+       void (*train_set)(struct drm_device *, struct dcb_output *, u8 pattern);
+       void (*train_adj)(struct drm_device *, struct dcb_output *,
                          u8 lane, u8 swing, u8 preem);
  };
  
  struct nouveau_encoder {
        struct drm_encoder_slave base;
  
-       struct dcb_entry *dcb;
+       struct dcb_output *dcb;
        int or;
  
        /* different to drm_encoder.crtc, this reflects what's
@@@ -87,18 -91,16 +91,16 @@@ get_slave_funcs(struct drm_encoder *enc
  }
  
  /* nouveau_dp.c */
- int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
-                    uint8_t *data, int data_nr);
  bool nouveau_dp_detect(struct drm_encoder *);
  void nouveau_dp_dpms(struct drm_encoder *, int mode, u32 datarate,
                     struct dp_train_func *);
- u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_entry *, u8 **);
+ u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_output *, u8 **);
  
  struct nouveau_connector *
  nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
- int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
+ int nv50_sor_create(struct drm_connector *, struct dcb_output *);
  void nv50_sor_dp_calc_tu(struct drm_device *, int, int, u32, u32);
- int nv50_dac_create(struct drm_connector *, struct dcb_entry *);
+ int nv50_dac_create(struct drm_connector *, struct dcb_output *);
  
  
  #endif /* __NOUVEAU_ENCODER_H__ */
  #include <linux/vga_switcheroo.h>
  #include <linux/console.h>
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 -#include "drm_crtc_helper.h"
 -#include "drm_fb_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/drm_fb_helper.h>
- #include "nouveau_drv.h"
- #include <drm/nouveau_drm.h>
- #include "nouveau_crtc.h"
- #include "nouveau_fb.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_gem.h"
+ #include "nouveau_bo.h"
  #include "nouveau_fbcon.h"
- #include "nouveau_dma.h"
+ #include "nouveau_chan.h"
+ #include "nouveau_crtc.h"
+ #include <core/client.h>
+ #include <core/device.h>
+ #include <subdev/fb.h>
+ MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration");
+ static int nouveau_nofbaccel = 0;
+ module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
  
  static void
  nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
  {
-       struct nouveau_fbdev *nfbdev = info->par;
-       struct drm_device *dev = nfbdev->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_fbdev *fbcon = info->par;
+       struct nouveau_drm *drm = nouveau_drm(fbcon->dev);
+       struct nouveau_device *device = nv_device(drm->device);
        int ret;
  
        if (info->state != FBINFO_STATE_RUNNING)
  
        ret = -ENODEV;
        if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
-           mutex_trylock(&dev_priv->channel->mutex)) {
-               if (dev_priv->card_type < NV_50)
+           mutex_trylock(&drm->client.mutex)) {
+               if (device->card_type < NV_50)
                        ret = nv04_fbcon_fillrect(info, rect);
                else
-               if (dev_priv->card_type < NV_C0)
+               if (device->card_type < NV_C0)
                        ret = nv50_fbcon_fillrect(info, rect);
                else
                        ret = nvc0_fbcon_fillrect(info, rect);
-               mutex_unlock(&dev_priv->channel->mutex);
+               mutex_unlock(&drm->client.mutex);
        }
  
        if (ret == 0)
@@@ -84,9 -96,9 +95,9 @@@
  static void
  nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image)
  {
-       struct nouveau_fbdev *nfbdev = info->par;
-       struct drm_device *dev = nfbdev->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_fbdev *fbcon = info->par;
+       struct nouveau_drm *drm = nouveau_drm(fbcon->dev);
+       struct nouveau_device *device = nv_device(drm->device);
        int ret;
  
        if (info->state != FBINFO_STATE_RUNNING)
  
        ret = -ENODEV;
        if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
-           mutex_trylock(&dev_priv->channel->mutex)) {
-               if (dev_priv->card_type < NV_50)
+           mutex_trylock(&drm->client.mutex)) {
+               if (device->card_type < NV_50)
                        ret = nv04_fbcon_copyarea(info, image);
                else
-               if (dev_priv->card_type < NV_C0)
+               if (device->card_type < NV_C0)
                        ret = nv50_fbcon_copyarea(info, image);
                else
                        ret = nvc0_fbcon_copyarea(info, image);
-               mutex_unlock(&dev_priv->channel->mutex);
+               mutex_unlock(&drm->client.mutex);
        }
  
        if (ret == 0)
  static void
  nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
  {
-       struct nouveau_fbdev *nfbdev = info->par;
-       struct drm_device *dev = nfbdev->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_fbdev *fbcon = info->par;
+       struct nouveau_drm *drm = nouveau_drm(fbcon->dev);
+       struct nouveau_device *device = nv_device(drm->device);
        int ret;
  
        if (info->state != FBINFO_STATE_RUNNING)
  
        ret = -ENODEV;
        if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
-           mutex_trylock(&dev_priv->channel->mutex)) {
-               if (dev_priv->card_type < NV_50)
+           mutex_trylock(&drm->client.mutex)) {
+               if (device->card_type < NV_50)
                        ret = nv04_fbcon_imageblit(info, image);
                else
-               if (dev_priv->card_type < NV_C0)
+               if (device->card_type < NV_C0)
                        ret = nv50_fbcon_imageblit(info, image);
                else
                        ret = nvc0_fbcon_imageblit(info, image);
-               mutex_unlock(&dev_priv->channel->mutex);
+               mutex_unlock(&drm->client.mutex);
        }
  
        if (ret == 0)
  static int
  nouveau_fbcon_sync(struct fb_info *info)
  {
-       struct nouveau_fbdev *nfbdev = info->par;
-       struct drm_device *dev = nfbdev->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_channel *chan = dev_priv->channel;
+       struct nouveau_fbdev *fbcon = info->par;
+       struct nouveau_drm *drm = nouveau_drm(fbcon->dev);
+       struct nouveau_channel *chan = drm->channel;
        int ret;
  
        if (!chan || !chan->accel_done || in_interrupt() ||
            info->flags & FBINFO_HWACCEL_DISABLED)
                return 0;
  
-       if (!mutex_trylock(&chan->mutex))
+       if (!mutex_trylock(&drm->client.mutex))
                return 0;
  
        ret = nouveau_channel_idle(chan);
-       mutex_unlock(&chan->mutex);
+       mutex_unlock(&drm->client.mutex);
        if (ret) {
                nouveau_fbcon_gpu_lockup(info);
                return 0;
@@@ -223,9 -234,9 +233,9 @@@ static void nouveau_fbcon_gamma_get(str
  }
  
  static void
- nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
+ nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *fbcon)
  {
-       struct fb_info *info = nfbdev->helper.fbdev;
+       struct fb_info *info = fbcon->helper.fbdev;
        struct fb_fillrect rect;
  
        /* Clear the entire fbcon.  The drm will program every connector
  }
  
  static int
- nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
+ nouveau_fbcon_create(struct nouveau_fbdev *fbcon,
                     struct drm_fb_helper_surface_size *sizes)
  {
-       struct drm_device *dev = nfbdev->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct drm_device *dev = fbcon->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nv_device(drm->device);
        struct fb_info *info;
        struct drm_framebuffer *fb;
        struct nouveau_framebuffer *nouveau_fb;
        struct nouveau_bo *nvbo;
        struct drm_mode_fb_cmd2 mode_cmd;
        struct pci_dev *pdev = dev->pdev;
-       struct device *device = &pdev->dev;
        int size, ret;
  
        mode_cmd.width = sizes->surface_width;
        ret = nouveau_gem_new(dev, size, 0, NOUVEAU_GEM_DOMAIN_VRAM,
                              0, 0x0000, &nvbo);
        if (ret) {
-               NV_ERROR(dev, "failed to allocate framebuffer\n");
+               NV_ERROR(drm, "failed to allocate framebuffer\n");
                goto out;
        }
  
        ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM);
        if (ret) {
-               NV_ERROR(dev, "failed to pin fb: %d\n", ret);
+               NV_ERROR(drm, "failed to pin fb: %d\n", ret);
                nouveau_bo_ref(NULL, &nvbo);
                goto out;
        }
  
        ret = nouveau_bo_map(nvbo);
        if (ret) {
-               NV_ERROR(dev, "failed to map fb: %d\n", ret);
+               NV_ERROR(drm, "failed to map fb: %d\n", ret);
                nouveau_bo_unpin(nvbo);
                nouveau_bo_ref(NULL, &nvbo);
                goto out;
        }
  
-       chan = nouveau_nofbaccel ? NULL : dev_priv->channel;
-       if (chan && dev_priv->card_type >= NV_50) {
-               ret = nouveau_bo_vma_add(nvbo, chan->vm, &nfbdev->nouveau_fb.vma);
+       chan = nouveau_nofbaccel ? NULL : drm->channel;
+       if (chan && device->card_type >= NV_50) {
+               ret = nouveau_bo_vma_add(nvbo, nv_client(chan->cli)->vm,
+                                       &fbcon->nouveau_fb.vma);
                if (ret) {
-                       NV_ERROR(dev, "failed to map fb into chan: %d\n", ret);
+                       NV_ERROR(drm, "failed to map fb into chan: %d\n", ret);
                        chan = NULL;
                }
        }
  
        mutex_lock(&dev->struct_mutex);
  
-       info = framebuffer_alloc(0, device);
+       info = framebuffer_alloc(0, &pdev->dev);
        if (!info) {
                ret = -ENOMEM;
                goto out_unref;
                goto out_unref;
        }
  
-       info->par = nfbdev;
+       info->par = fbcon;
  
-       nouveau_framebuffer_init(dev, &nfbdev->nouveau_fb, &mode_cmd, nvbo);
+       nouveau_framebuffer_init(dev, &fbcon->nouveau_fb, &mode_cmd, nvbo);
  
-       nouveau_fb = &nfbdev->nouveau_fb;
+       nouveau_fb = &fbcon->nouveau_fb;
        fb = &nouveau_fb->base;
  
        /* setup helper */
-       nfbdev->helper.fb = fb;
-       nfbdev->helper.fbdev = info;
+       fbcon->helper.fb = fb;
+       fbcon->helper.fbdev = info;
  
        strcpy(info->fix.id, "nouveaufb");
        if (nouveau_nofbaccel)
        info->screen_size = size;
  
        drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
-       drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height);
-       /* Set aperture base/size for vesafb takeover */
-       info->apertures = dev_priv->apertures;
-       if (!info->apertures) {
-               ret = -ENOMEM;
-               goto out_unref;
-       }
+       drm_fb_helper_fill_var(info, &fbcon->helper, sizes->fb_width, sizes->fb_height);
  
        /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
  
        mutex_unlock(&dev->struct_mutex);
  
-       if (dev_priv->channel && !nouveau_nofbaccel) {
+       if (chan) {
                ret = -ENODEV;
-               if (dev_priv->card_type < NV_50)
+               if (device->card_type < NV_50)
                        ret = nv04_fbcon_accel_init(info);
                else
-               if (dev_priv->card_type < NV_C0)
+               if (device->card_type < NV_C0)
                        ret = nv50_fbcon_accel_init(info);
                else
                        ret = nvc0_fbcon_accel_init(info);
                        info->fbops = &nouveau_fbcon_ops;
        }
  
-       nouveau_fbcon_zfill(dev, nfbdev);
+       nouveau_fbcon_zfill(dev, fbcon);
  
        /* To allow resizeing without swapping buffers */
-       NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n",
-                                               nouveau_fb->base.width,
-                                               nouveau_fb->base.height,
-                                               nvbo->bo.offset, nvbo);
+       NV_INFO(drm, "allocated %dx%d fb: 0x%lx, bo %p\n",
+               nouveau_fb->base.width, nouveau_fb->base.height,
+               nvbo->bo.offset, nvbo);
  
        vga_switcheroo_client_fb_set(dev->pdev, info);
        return 0;
@@@ -389,12 -393,12 +392,12 @@@ static in
  nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper,
                                    struct drm_fb_helper_surface_size *sizes)
  {
-       struct nouveau_fbdev *nfbdev = (struct nouveau_fbdev *)helper;
+       struct nouveau_fbdev *fbcon = (struct nouveau_fbdev *)helper;
        int new_fb = 0;
        int ret;
  
        if (!helper->fb) {
-               ret = nouveau_fbcon_create(nfbdev, sizes);
+               ret = nouveau_fbcon_create(fbcon, sizes);
                if (ret)
                        return ret;
                new_fb = 1;
  void
  nouveau_fbcon_output_poll_changed(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       drm_fb_helper_hotplug_event(&dev_priv->nfbdev->helper);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       drm_fb_helper_hotplug_event(&drm->fbcon->helper);
  }
  
  static int
- nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
+ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
  {
-       struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb;
+       struct nouveau_framebuffer *nouveau_fb = &fbcon->nouveau_fb;
        struct fb_info *info;
  
-       if (nfbdev->helper.fbdev) {
-               info = nfbdev->helper.fbdev;
+       if (fbcon->helper.fbdev) {
+               info = fbcon->helper.fbdev;
                unregister_framebuffer(info);
                if (info->cmap.len)
                        fb_dealloc_cmap(&info->cmap);
                drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
                nouveau_fb->nvbo = NULL;
        }
-       drm_fb_helper_fini(&nfbdev->helper);
+       drm_fb_helper_fini(&fbcon->helper);
        drm_framebuffer_cleanup(&nouveau_fb->base);
        return 0;
  }
  
  void nouveau_fbcon_gpu_lockup(struct fb_info *info)
  {
-       struct nouveau_fbdev *nfbdev = info->par;
-       struct drm_device *dev = nfbdev->dev;
+       struct nouveau_fbdev *fbcon = info->par;
+       struct nouveau_drm *drm = nouveau_drm(fbcon->dev);
  
-       NV_ERROR(dev, "GPU lockup - switching to software fbcon\n");
+       NV_ERROR(drm, "GPU lockup - switching to software fbcon\n");
        info->flags |= FBINFO_HWACCEL_DISABLED;
  }
  
@@@ -450,74 -454,81 +453,81 @@@ static struct drm_fb_helper_funcs nouve
  };
  
  
- int nouveau_fbcon_init(struct drm_device *dev)
+ int
+ nouveau_fbcon_init(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_fbdev *nfbdev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_fb *pfb = nouveau_fb(drm->device);
+       struct nouveau_fbdev *fbcon;
        int preferred_bpp;
        int ret;
  
-       nfbdev = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL);
-       if (!nfbdev)
+       if (!dev->mode_config.num_crtc)
+               return 0;
+       fbcon = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL);
+       if (!fbcon)
                return -ENOMEM;
  
-       nfbdev->dev = dev;
-       dev_priv->nfbdev = nfbdev;
-       nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
+       fbcon->dev = dev;
+       drm->fbcon = fbcon;
+       fbcon->helper.funcs = &nouveau_fbcon_helper_funcs;
  
-       ret = drm_fb_helper_init(dev, &nfbdev->helper,
+       ret = drm_fb_helper_init(dev, &fbcon->helper,
                                 dev->mode_config.num_crtc, 4);
        if (ret) {
-               kfree(nfbdev);
+               kfree(fbcon);
                return ret;
        }
  
-       drm_fb_helper_single_add_all_connectors(&nfbdev->helper);
+       drm_fb_helper_single_add_all_connectors(&fbcon->helper);
  
-       if (dev_priv->vram_size <= 32 * 1024 * 1024)
+       if (pfb->ram.size <= 32 * 1024 * 1024)
                preferred_bpp = 8;
-       else if (dev_priv->vram_size <= 64 * 1024 * 1024)
+       else
+       if (pfb->ram.size <= 64 * 1024 * 1024)
                preferred_bpp = 16;
        else
                preferred_bpp = 32;
  
-       drm_fb_helper_initial_config(&nfbdev->helper, preferred_bpp);
+       drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp);
        return 0;
  }
  
- void nouveau_fbcon_fini(struct drm_device *dev)
+ void
+ nouveau_fbcon_fini(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
-       if (!dev_priv->nfbdev)
+       if (!drm->fbcon)
                return;
  
-       nouveau_fbcon_destroy(dev, dev_priv->nfbdev);
-       kfree(dev_priv->nfbdev);
-       dev_priv->nfbdev = NULL;
+       nouveau_fbcon_destroy(dev, drm->fbcon);
+       kfree(drm->fbcon);
+       drm->fbcon = NULL;
  }
  
  void nouveau_fbcon_save_disable_accel(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
-       dev_priv->nfbdev->saved_flags = dev_priv->nfbdev->helper.fbdev->flags;
-       dev_priv->nfbdev->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
+       drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags;
+       drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
  }
  
  void nouveau_fbcon_restore_accel(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       dev_priv->nfbdev->helper.fbdev->flags = dev_priv->nfbdev->saved_flags;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags;
  }
  
  void nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        console_lock();
        if (state == 0)
                nouveau_fbcon_save_disable_accel(dev);
-       fb_set_suspend(dev_priv->nfbdev->helper.fbdev, state);
+       fb_set_suspend(drm->fbcon->helper.fbdev, state);
        if (state == 1)
                nouveau_fbcon_restore_accel(dev);
        console_unlock();
  
  void nouveau_fbcon_zfill_all(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       nouveau_fbcon_zfill(dev, dev_priv->nfbdev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       nouveau_fbcon_zfill(dev, drm->fbcon);
  }
  #ifndef __NOUVEAU_FBCON_H__
  #define __NOUVEAU_FBCON_H__
  
 -#include "drm_fb_helper.h"
 +#include <drm/drm_fb_helper.h>
  
- #include "nouveau_fb.h"
+ #include "nouveau_display.h"
  struct nouveau_fbdev {
        struct drm_fb_helper helper;
        struct nouveau_framebuffer nouveau_fb;
   *
   */
  
 -#include "drmP.h"
 -#include "drm.h"
 +#include <drm/drmP.h>
  
  #include <linux/ktime.h>
  #include <linux/hrtimer.h>
  
- #include "nouveau_drv.h"
- #include "nouveau_ramht.h"
- #include "nouveau_fence.h"
- #include "nouveau_software.h"
+ #include "nouveau_drm.h"
  #include "nouveau_dma.h"
+ #include "nouveau_fence.h"
  
  void
  nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
  void
  nouveau_fence_context_new(struct nouveau_fence_chan *fctx)
  {
+       INIT_LIST_HEAD(&fctx->flip);
        INIT_LIST_HEAD(&fctx->pending);
        spin_lock_init(&fctx->lock);
  }
  
- void
static void
  nouveau_fence_update(struct nouveau_channel *chan)
  {
-       struct drm_device *dev = chan->dev;
-       struct nouveau_fence_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FENCE);
-       struct nouveau_fence_chan *fctx = chan->engctx[NVOBJ_ENGINE_FENCE];
+       struct nouveau_fence_priv *priv = chan->drm->fence;
+       struct nouveau_fence_chan *fctx = chan->fence;
        struct nouveau_fence *fence, *fnext;
  
        spin_lock(&fctx->lock);
@@@ -82,9 -81,8 +80,8 @@@
  int
  nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
  {
-       struct drm_device *dev = chan->dev;
-       struct nouveau_fence_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FENCE);
-       struct nouveau_fence_chan *fctx = chan->engctx[NVOBJ_ENGINE_FENCE];
+       struct nouveau_fence_priv *priv = chan->drm->fence;
+       struct nouveau_fence_chan *fctx = chan->fence;
        int ret;
  
        fence->channel  = chan;
@@@ -146,19 -144,17 +143,17 @@@ nouveau_fence_wait(struct nouveau_fenc
  int
  nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan)
  {
-       struct drm_device *dev = chan->dev;
-       struct nouveau_fence_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FENCE);
+       struct nouveau_fence_priv *priv = chan->drm->fence;
        struct nouveau_channel *prev;
        int ret = 0;
  
-       prev = fence ? nouveau_channel_get_unlocked(fence->channel) : NULL;
+       prev = fence ? fence->channel : NULL;
        if (prev) {
                if (unlikely(prev != chan && !nouveau_fence_done(fence))) {
                        ret = priv->sync(fence, prev, chan);
                        if (unlikely(ret))
                                ret = nouveau_fence_wait(fence, true, false);
                }
-               nouveau_channel_put_unlocked(&prev);
        }
  
        return ret;
@@@ -192,7 -188,7 +187,7 @@@ nouveau_fence_new(struct nouveau_channe
        struct nouveau_fence *fence;
        int ret = 0;
  
-       if (unlikely(!chan->engctx[NVOBJ_ENGINE_FENCE]))
+       if (unlikely(!chan->fence))
                return -ENODEV;
  
        fence = kzalloc(sizeof(*fence), GFP_KERNEL);
   * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   *
   */
  #include <linux/dma-buf.h>
- #include <drm/drmP.h>
 -#include <nouveau_drm.h>
  
- #include "nouveau_drv.h"
- #include <drm/nouveau_drm.h>
+ #include <subdev/fb.h>
+ #include "nouveau_drm.h"
  #include "nouveau_dma.h"
  #include "nouveau_fence.h"
+ #include "nouveau_abi16.h"
  
- #define nouveau_gem_pushbuf_sync(chan) 0
+ #include "nouveau_ttm.h"
+ #include "nouveau_gem.h"
  
  int
  nouveau_gem_object_new(struct drm_gem_object *gem)
@@@ -66,19 -70,19 +69,19 @@@ nouveau_gem_object_del(struct drm_gem_o
  int
  nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)
  {
-       struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
+       struct nouveau_cli *cli = nouveau_cli(file_priv);
        struct nouveau_bo *nvbo = nouveau_gem_object(gem);
        struct nouveau_vma *vma;
        int ret;
  
-       if (!fpriv->vm)
+       if (!cli->base.vm)
                return 0;
  
        ret = ttm_bo_reserve(&nvbo->bo, false, false, false, 0);
        if (ret)
                return ret;
  
-       vma = nouveau_bo_vma_find(nvbo, fpriv->vm);
+       vma = nouveau_bo_vma_find(nvbo, cli->base.vm);
        if (!vma) {
                vma = kzalloc(sizeof(*vma), GFP_KERNEL);
                if (!vma) {
@@@ -86,7 -90,7 +89,7 @@@
                        goto out;
                }
  
-               ret = nouveau_bo_vma_add(nvbo, fpriv->vm, vma);
+               ret = nouveau_bo_vma_add(nvbo, cli->base.vm, vma);
                if (ret) {
                        kfree(vma);
                        goto out;
@@@ -103,19 -107,19 +106,19 @@@ out
  void
  nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
  {
-       struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
+       struct nouveau_cli *cli = nouveau_cli(file_priv);
        struct nouveau_bo *nvbo = nouveau_gem_object(gem);
        struct nouveau_vma *vma;
        int ret;
  
-       if (!fpriv->vm)
+       if (!cli->base.vm)
                return;
  
        ret = ttm_bo_reserve(&nvbo->bo, false, false, false, 0);
        if (ret)
                return;
  
-       vma = nouveau_bo_vma_find(nvbo, fpriv->vm);
+       vma = nouveau_bo_vma_find(nvbo, cli->base.vm);
        if (vma) {
                if (--vma->refcount == 0) {
                        nouveau_bo_vma_del(nvbo, vma);
@@@ -130,7 -134,7 +133,7 @@@ nouveau_gem_new(struct drm_device *dev
                uint32_t tile_mode, uint32_t tile_flags,
                struct nouveau_bo **pnvbo)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_bo *nvbo;
        u32 flags = 0;
        int ret;
         */
        nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM |
                              NOUVEAU_GEM_DOMAIN_GART;
-       if (dev_priv->card_type >= NV_50)
+       if (nv_device(drm->device)->card_type >= NV_50)
                nvbo->valid_domains &= domain;
  
        nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size);
@@@ -172,7 -176,7 +175,7 @@@ static in
  nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem,
                 struct drm_nouveau_gem_info *rep)
  {
-       struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
+       struct nouveau_cli *cli = nouveau_cli(file_priv);
        struct nouveau_bo *nvbo = nouveau_gem_object(gem);
        struct nouveau_vma *vma;
  
                rep->domain = NOUVEAU_GEM_DOMAIN_VRAM;
  
        rep->offset = nvbo->bo.offset;
-       if (fpriv->vm) {
-               vma = nouveau_bo_vma_find(nvbo, fpriv->vm);
+       if (cli->base.vm) {
+               vma = nouveau_bo_vma_find(nvbo, cli->base.vm);
                if (!vma)
                        return -EINVAL;
  
@@@ -201,15 -205,16 +204,16 @@@ in
  nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
                      struct drm_file *file_priv)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_fb *pfb = nouveau_fb(drm->device);
        struct drm_nouveau_gem_new *req = data;
        struct nouveau_bo *nvbo = NULL;
        int ret = 0;
  
-       dev_priv->ttm.bdev.dev_mapping = dev->dev_mapping;
+       drm->ttm.bdev.dev_mapping = drm->dev->dev_mapping;
  
-       if (!dev_priv->engine.vram.flags_valid(dev, req->info.tile_flags)) {
-               NV_ERROR(dev, "bad page flags: 0x%08x\n", req->info.tile_flags);
+       if (!pfb->memtype_valid(pfb, req->info.tile_flags)) {
+               NV_ERROR(drm, "bad page flags: 0x%08x\n", req->info.tile_flags);
                return -EINVAL;
        }
  
@@@ -311,16 -316,16 +315,16 @@@ validate_init(struct nouveau_channel *c
              struct drm_nouveau_gem_pushbuf_bo *pbbo,
              int nr_buffers, struct validate_op *op)
  {
-       struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct drm_device *dev = chan->drm->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        uint32_t sequence;
        int trycnt = 0;
        int ret, i;
  
-       sequence = atomic_add_return(1, &dev_priv->ttm.validate_sequence);
+       sequence = atomic_add_return(1, &drm->ttm.validate_sequence);
  retry:
        if (++trycnt > 100000) {
-               NV_ERROR(dev, "%s failed and gave up.\n", __func__);
+               NV_ERROR(drm, "%s failed and gave up.\n", __func__);
                return -EINVAL;
        }
  
  
                gem = drm_gem_object_lookup(dev, file_priv, b->handle);
                if (!gem) {
-                       NV_ERROR(dev, "Unknown handle 0x%08x\n", b->handle);
+                       NV_ERROR(drm, "Unknown handle 0x%08x\n", b->handle);
                        validate_fini(op, NULL);
                        return -ENOENT;
                }
                nvbo = gem->driver_private;
  
                if (nvbo->reserved_by && nvbo->reserved_by == file_priv) {
-                       NV_ERROR(dev, "multiple instances of buffer %d on "
+                       NV_ERROR(drm, "multiple instances of buffer %d on "
                                      "validation list\n", b->handle);
                        drm_gem_object_unreference_unlocked(gem);
                        validate_fini(op, NULL);
                        drm_gem_object_unreference_unlocked(gem);
                        if (unlikely(ret)) {
                                if (ret != -ERESTARTSYS)
-                                       NV_ERROR(dev, "fail reserve\n");
+                                       NV_ERROR(drm, "fail reserve\n");
                                return ret;
                        }
                        goto retry;
                if (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART)
                        list_add_tail(&nvbo->entry, &op->gart_list);
                else {
-                       NV_ERROR(dev, "invalid valid domains: 0x%08x\n",
+                       NV_ERROR(drm, "invalid valid domains: 0x%08x\n",
                                 b->valid_domains);
                        list_add_tail(&nvbo->entry, &op->both_list);
                        validate_fini(op, NULL);
@@@ -406,10 -411,9 +410,9 @@@ static in
  validate_list(struct nouveau_channel *chan, struct list_head *list,
              struct drm_nouveau_gem_pushbuf_bo *pbbo, uint64_t user_pbbo_ptr)
  {
-       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+       struct nouveau_drm *drm = chan->drm;
        struct drm_nouveau_gem_pushbuf_bo __user *upbbo =
                                (void __force __user *)(uintptr_t)user_pbbo_ptr;
-       struct drm_device *dev = chan->dev;
        struct nouveau_bo *nvbo;
        int ret, relocs = 0;
  
  
                ret = validate_sync(chan, nvbo);
                if (unlikely(ret)) {
-                       NV_ERROR(dev, "fail pre-validate sync\n");
+                       NV_ERROR(drm, "fail pre-validate sync\n");
                        return ret;
                }
  
                                             b->write_domains,
                                             b->valid_domains);
                if (unlikely(ret)) {
-                       NV_ERROR(dev, "fail set_domain\n");
+                       NV_ERROR(drm, "fail set_domain\n");
                        return ret;
                }
  
                ret = nouveau_bo_validate(nvbo, true, false, false);
                if (unlikely(ret)) {
                        if (ret != -ERESTARTSYS)
-                               NV_ERROR(dev, "fail ttm_validate\n");
+                               NV_ERROR(drm, "fail ttm_validate\n");
                        return ret;
                }
  
                ret = validate_sync(chan, nvbo);
                if (unlikely(ret)) {
-                       NV_ERROR(dev, "fail post-validate sync\n");
+                       NV_ERROR(drm, "fail post-validate sync\n");
                        return ret;
                }
  
-               if (dev_priv->card_type < NV_50) {
+               if (nv_device(drm->device)->card_type < NV_50) {
                        if (nvbo->bo.offset == b->presumed.offset &&
                            ((nvbo->bo.mem.mem_type == TTM_PL_VRAM &&
                              b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) ||
@@@ -475,7 -479,7 +478,7 @@@ nouveau_gem_pushbuf_validate(struct nou
                             uint64_t user_buffers, int nr_buffers,
                             struct validate_op *op, int *apply_relocs)
  {
-       struct drm_device *dev = chan->dev;
+       struct nouveau_drm *drm = chan->drm;
        int ret, relocs = 0;
  
        INIT_LIST_HEAD(&op->vram_list);
        ret = validate_init(chan, file_priv, pbbo, nr_buffers, op);
        if (unlikely(ret)) {
                if (ret != -ERESTARTSYS)
-                       NV_ERROR(dev, "validate_init\n");
+                       NV_ERROR(drm, "validate_init\n");
                return ret;
        }
  
        ret = validate_list(chan, &op->vram_list, pbbo, user_buffers);
        if (unlikely(ret < 0)) {
                if (ret != -ERESTARTSYS)
-                       NV_ERROR(dev, "validate vram_list\n");
+                       NV_ERROR(drm, "validate vram_list\n");
                validate_fini(op, NULL);
                return ret;
        }
        ret = validate_list(chan, &op->gart_list, pbbo, user_buffers);
        if (unlikely(ret < 0)) {
                if (ret != -ERESTARTSYS)
-                       NV_ERROR(dev, "validate gart_list\n");
+                       NV_ERROR(drm, "validate gart_list\n");
                validate_fini(op, NULL);
                return ret;
        }
        ret = validate_list(chan, &op->both_list, pbbo, user_buffers);
        if (unlikely(ret < 0)) {
                if (ret != -ERESTARTSYS)
-                       NV_ERROR(dev, "validate both_list\n");
+                       NV_ERROR(drm, "validate both_list\n");
                validate_fini(op, NULL);
                return ret;
        }
@@@ -546,6 -550,7 +549,7 @@@ nouveau_gem_pushbuf_reloc_apply(struct 
                                struct drm_nouveau_gem_pushbuf *req,
                                struct drm_nouveau_gem_pushbuf_bo *bo)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL;
        int ret = 0;
        unsigned i;
                uint32_t data;
  
                if (unlikely(r->bo_index > req->nr_buffers)) {
-                       NV_ERROR(dev, "reloc bo index invalid\n");
+                       NV_ERROR(drm, "reloc bo index invalid\n");
                        ret = -EINVAL;
                        break;
                }
                        continue;
  
                if (unlikely(r->reloc_bo_index > req->nr_buffers)) {
-                       NV_ERROR(dev, "reloc container bo index invalid\n");
+                       NV_ERROR(drm, "reloc container bo index invalid\n");
                        ret = -EINVAL;
                        break;
                }
  
                if (unlikely(r->reloc_bo_offset + 4 >
                             nvbo->bo.mem.num_pages << PAGE_SHIFT)) {
-                       NV_ERROR(dev, "reloc outside of bo\n");
+                       NV_ERROR(drm, "reloc outside of bo\n");
                        ret = -EINVAL;
                        break;
                }
                        ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages,
                                          &nvbo->kmap);
                        if (ret) {
-                               NV_ERROR(dev, "failed kmap for reloc\n");
+                               NV_ERROR(drm, "failed kmap for reloc\n");
                                break;
                        }
                        nvbo->validate_mapped = true;
                ret = ttm_bo_wait(&nvbo->bo, false, false, false);
                spin_unlock(&nvbo->bo.bdev->fence_lock);
                if (ret) {
-                       NV_ERROR(dev, "reloc wait_idle failed: %d\n", ret);
+                       NV_ERROR(drm, "reloc wait_idle failed: %d\n", ret);
                        break;
                }
  
@@@ -628,62 -633,67 +632,67 @@@ in
  nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
+       struct nouveau_abi16_chan *temp;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct drm_nouveau_gem_pushbuf *req = data;
        struct drm_nouveau_gem_pushbuf_push *push;
        struct drm_nouveau_gem_pushbuf_bo *bo;
-       struct nouveau_channel *chan;
+       struct nouveau_channel *chan = NULL;
        struct validate_op op;
        struct nouveau_fence *fence = NULL;
        int i, j, ret = 0, do_reloc = 0;
  
-       chan = nouveau_channel_get(file_priv, req->channel);
-       if (IS_ERR(chan))
-               return PTR_ERR(chan);
+       if (unlikely(!abi16))
+               return -ENOMEM;
+       list_for_each_entry(temp, &abi16->channels, head) {
+               if (temp->chan->handle == (NVDRM_CHAN | req->channel)) {
+                       chan = temp->chan;
+                       break;
+               }
+       }
  
-       req->vram_available = dev_priv->fb_aper_free;
-       req->gart_available = dev_priv->gart_info.aper_free;
+       if (!chan)
+               return nouveau_abi16_put(abi16, -ENOENT);
+       req->vram_available = drm->gem.vram_available;
+       req->gart_available = drm->gem.gart_available;
        if (unlikely(req->nr_push == 0))
                goto out_next;
  
        if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) {
-               NV_ERROR(dev, "pushbuf push count exceeds limit: %d max %d\n",
+               NV_ERROR(drm, "pushbuf push count exceeds limit: %d max %d\n",
                         req->nr_push, NOUVEAU_GEM_MAX_PUSH);
-               nouveau_channel_put(&chan);
-               return -EINVAL;
+               return nouveau_abi16_put(abi16, -EINVAL);
        }
  
        if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) {
-               NV_ERROR(dev, "pushbuf bo count exceeds limit: %d max %d\n",
+               NV_ERROR(drm, "pushbuf bo count exceeds limit: %d max %d\n",
                         req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS);
-               nouveau_channel_put(&chan);
-               return -EINVAL;
+               return nouveau_abi16_put(abi16, -EINVAL);
        }
  
        if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) {
-               NV_ERROR(dev, "pushbuf reloc count exceeds limit: %d max %d\n",
+               NV_ERROR(drm, "pushbuf reloc count exceeds limit: %d max %d\n",
                         req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS);
-               nouveau_channel_put(&chan);
-               return -EINVAL;
+               return nouveau_abi16_put(abi16, -EINVAL);
        }
  
        push = u_memcpya(req->push, req->nr_push, sizeof(*push));
-       if (IS_ERR(push)) {
-               nouveau_channel_put(&chan);
-               return PTR_ERR(push);
-       }
+       if (IS_ERR(push))
+               return nouveau_abi16_put(abi16, PTR_ERR(push));
  
        bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo));
        if (IS_ERR(bo)) {
                kfree(push);
-               nouveau_channel_put(&chan);
-               return PTR_ERR(bo);
+               return nouveau_abi16_put(abi16, PTR_ERR(bo));
        }
  
        /* Ensure all push buffers are on validate list */
        for (i = 0; i < req->nr_push; i++) {
                if (push[i].bo_index >= req->nr_buffers) {
-                       NV_ERROR(dev, "push %d buffer not in list\n", i);
+                       NV_ERROR(drm, "push %d buffer not in list\n", i);
                        ret = -EINVAL;
                        goto out_prevalid;
                }
                                           req->nr_buffers, &op, &do_reloc);
        if (ret) {
                if (ret != -ERESTARTSYS)
-                       NV_ERROR(dev, "validate: %d\n", ret);
+                       NV_ERROR(drm, "validate: %d\n", ret);
                goto out_prevalid;
        }
  
        if (do_reloc) {
                ret = nouveau_gem_pushbuf_reloc_apply(dev, req, bo);
                if (ret) {
-                       NV_ERROR(dev, "reloc apply: %d\n", ret);
+                       NV_ERROR(drm, "reloc apply: %d\n", ret);
                        goto out;
                }
        }
        if (chan->dma.ib_max) {
                ret = nouveau_dma_wait(chan, req->nr_push + 1, 16);
                if (ret) {
-                       NV_INFO(dev, "nv50cal_space: %d\n", ret);
+                       NV_ERROR(drm, "nv50cal_space: %d\n", ret);
                        goto out;
                }
  
                                      push[i].length);
                }
        } else
-       if (dev_priv->chipset >= 0x25) {
+       if (nv_device(drm->device)->chipset >= 0x25) {
                ret = RING_SPACE(chan, req->nr_push * 2);
                if (ret) {
-                       NV_ERROR(dev, "cal_space: %d\n", ret);
+                       NV_ERROR(drm, "cal_space: %d\n", ret);
                        goto out;
                }
  
                for (i = 0; i < req->nr_push; i++) {
                        struct nouveau_bo *nvbo = (void *)(unsigned long)
                                bo[push[i].bo_index].user_priv;
-                       struct drm_mm_node *mem = nvbo->bo.mem.mm_node;
  
-                       OUT_RING(chan, ((mem->start << PAGE_SHIFT) +
-                                       push[i].offset) | 2);
+                       OUT_RING(chan, (nvbo->bo.offset + push[i].offset) | 2);
                        OUT_RING(chan, 0);
                }
        } else {
                ret = RING_SPACE(chan, req->nr_push * (2 + NOUVEAU_DMA_SKIPS));
                if (ret) {
-                       NV_ERROR(dev, "jmp_space: %d\n", ret);
+                       NV_ERROR(drm, "jmp_space: %d\n", ret);
                        goto out;
                }
  
                for (i = 0; i < req->nr_push; i++) {
                        struct nouveau_bo *nvbo = (void *)(unsigned long)
                                bo[push[i].bo_index].user_priv;
-                       struct drm_mm_node *mem = nvbo->bo.mem.mm_node;
                        uint32_t cmd;
  
-                       cmd = chan->pushbuf_base + ((chan->dma.cur + 2) << 2);
+                       cmd = chan->push.vma.offset + ((chan->dma.cur + 2) << 2);
                        cmd |= 0x20000000;
                        if (unlikely(cmd != req->suffix0)) {
                                if (!nvbo->kmap.virtual) {
                                                push[i].length - 8) / 4, cmd);
                        }
  
-                       OUT_RING(chan, ((mem->start << PAGE_SHIFT) +
-                                       push[i].offset) | 0x20000000);
+                       OUT_RING(chan, 0x20000000 |
+                                     (nvbo->bo.offset + push[i].offset));
                        OUT_RING(chan, 0);
                        for (j = 0; j < NOUVEAU_DMA_SKIPS; j++)
                                OUT_RING(chan, 0);
  
        ret = nouveau_fence_new(chan, &fence);
        if (ret) {
-               NV_ERROR(dev, "error fencing pushbuf: %d\n", ret);
+               NV_ERROR(drm, "error fencing pushbuf: %d\n", ret);
                WIND_RING(chan);
                goto out;
        }
@@@ -798,17 -805,16 +804,16 @@@ out_next
                req->suffix0 = 0x00000000;
                req->suffix1 = 0x00000000;
        } else
-       if (dev_priv->chipset >= 0x25) {
+       if (nv_device(drm->device)->chipset >= 0x25) {
                req->suffix0 = 0x00020000;
                req->suffix1 = 0x00000000;
        } else {
                req->suffix0 = 0x20000000 |
-                             (chan->pushbuf_base + ((chan->dma.cur + 2) << 2));
+                             (chan->push.vma.offset + ((chan->dma.cur + 2) << 2));
                req->suffix1 = 0x00000000;
        }
  
-       nouveau_channel_put(&chan);
-       return ret;
+       return nouveau_abi16_put(abi16, ret);
  }
  
  static inline uint32_t
index 0000000,085ece9..5c10492
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,43 +1,43 @@@
 -#include "drmP.h"
+ #ifndef __NOUVEAU_GEM_H__
+ #define __NOUVEAU_GEM_H__
 -#include <nouveau_drm.h>
++#include <drm/drmP.h>
++#include "nouveau_drm.h"
+ #include "nouveau_bo.h"
+ #define nouveau_bo_tile_layout(nvbo)                          \
+       ((nvbo)->tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)
+ static inline struct nouveau_bo *
+ nouveau_gem_object(struct drm_gem_object *gem)
+ {
+       return gem ? gem->driver_private : NULL;
+ }
+ /* nouveau_gem.c */
+ extern int nouveau_gem_new(struct drm_device *, int size, int align,
+                          uint32_t domain, uint32_t tile_mode,
+                          uint32_t tile_flags, struct nouveau_bo **);
+ extern int nouveau_gem_object_new(struct drm_gem_object *);
+ extern void nouveau_gem_object_del(struct drm_gem_object *);
+ extern int nouveau_gem_object_open(struct drm_gem_object *, struct drm_file *);
+ extern void nouveau_gem_object_close(struct drm_gem_object *,
+                                    struct drm_file *);
+ extern int nouveau_gem_ioctl_new(struct drm_device *, void *,
+                                struct drm_file *);
+ extern int nouveau_gem_ioctl_pushbuf(struct drm_device *, void *,
+                                    struct drm_file *);
+ extern int nouveau_gem_ioctl_cpu_prep(struct drm_device *, void *,
+                                     struct drm_file *);
+ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
+                                     struct drm_file *);
+ extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
+                                 struct drm_file *);
+ extern struct dma_buf *nouveau_gem_prime_export(struct drm_device *dev,
+                               struct drm_gem_object *obj, int flags);
+ extern struct drm_gem_object *nouveau_gem_prime_import(struct drm_device *dev,
+                               struct dma_buf *dma_buf);
+ #endif
@@@ -22,8 -22,8 +22,8 @@@
   * Authors: Ben Skeggs
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
  #include "nouveau_connector.h"
  #include "nouveau_encoder.h"
  #include "nouveau_crtc.h"
  static bool
  hdmi_sor(struct drm_encoder *encoder)
  {
-       struct drm_nouveau_private *dev_priv = encoder->dev->dev_private;
-       if (dev_priv->chipset <  0xa3 ||
-           dev_priv->chipset == 0xaa ||
-           dev_priv->chipset == 0xac)
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+       if (nv_device(drm->device)->chipset <  0xa3 ||
+           nv_device(drm->device)->chipset == 0xaa ||
+           nv_device(drm->device)->chipset == 0xac)
                return false;
        return true;
  }
@@@ -52,13 -52,15 +52,15 @@@ hdmi_base(struct drm_encoder *encoder
  static void
  hdmi_wr32(struct drm_encoder *encoder, u32 reg, u32 val)
  {
-       nv_wr32(encoder->dev, hdmi_base(encoder) + reg, val);
+       struct nouveau_device *device = nouveau_dev(encoder->dev);
+       nv_wr32(device, hdmi_base(encoder) + reg, val);
  }
  
  static u32
  hdmi_rd32(struct drm_encoder *encoder, u32 reg)
  {
-       return nv_rd32(encoder->dev, hdmi_base(encoder) + reg);
+       struct nouveau_device *device = nouveau_dev(encoder->dev);
+       return nv_rd32(device, hdmi_base(encoder) + reg);
  }
  
  static u32
@@@ -73,12 -75,11 +75,11 @@@ static voi
  nouveau_audio_disconnect(struct drm_encoder *encoder)
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-       struct drm_device *dev = encoder->dev;
+       struct nouveau_device *device = nouveau_dev(encoder->dev);
        u32 or = nv_encoder->or * 0x800;
  
-       if (hdmi_sor(encoder)) {
-               nv_mask(dev, 0x61c448 + or, 0x00000003, 0x00000000);
-       }
+       if (hdmi_sor(encoder))
+               nv_mask(device, 0x61c448 + or, 0x00000003, 0x00000000);
  }
  
  static void
@@@ -86,8 -87,8 +87,8 @@@ nouveau_audio_mode_set(struct drm_encod
                       struct drm_display_mode *mode)
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+       struct nouveau_device *device = nouveau_dev(encoder->dev);
        struct nouveau_connector *nv_connector;
-       struct drm_device *dev = encoder->dev;
        u32 or = nv_encoder->or * 0x800;
        int i;
  
        }
  
        if (hdmi_sor(encoder)) {
-               nv_mask(dev, 0x61c448 + or, 0x00000001, 0x00000001);
+               nv_mask(device, 0x61c448 + or, 0x00000001, 0x00000001);
  
                drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
                if (nv_connector->base.eld[0]) {
                        u8 *eld = nv_connector->base.eld;
                        for (i = 0; i < eld[2] * 4; i++)
-                               nv_wr32(dev, 0x61c440 + or, (i << 8) | eld[i]);
+                               nv_wr32(device, 0x61c440 + or, (i << 8) | eld[i]);
                        for (i = eld[2] * 4; i < 0x60; i++)
-                               nv_wr32(dev, 0x61c440 + or, (i << 8) | 0x00);
-                       nv_mask(dev, 0x61c448 + or, 0x00000002, 0x00000002);
+                               nv_wr32(device, 0x61c440 + or, (i << 8) | 0x00);
+                       nv_mask(device, 0x61c448 + or, 0x00000002, 0x00000002);
                }
        }
  }
@@@ -219,9 -220,9 +220,9 @@@ voi
  nouveau_hdmi_mode_set(struct drm_encoder *encoder,
                      struct drm_display_mode *mode)
  {
+       struct nouveau_device *device = nouveau_dev(encoder->dev);
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct nouveau_connector *nv_connector;
-       struct drm_device *dev = encoder->dev;
        u32 max_ac_packet, rekey;
  
        nv_connector = nouveau_encoder_connector_get(nv_encoder);
        hdmi_mask(encoder, 0x068, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
        hdmi_mask(encoder, 0x078, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
  
-       nv_mask(dev, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
-       nv_mask(dev, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
-       nv_mask(dev, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
+       nv_mask(device, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
+       nv_mask(device, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
+       nv_mask(device, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
  
        /* value matches nvidia binary driver, and tegra constant */
        rekey = 56;
   * SOFTWARE.
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
  #include "nouveau_hw.h"
  
+ #include <subdev/bios/pll.h>
+ #include <subdev/clock.h>
+ #include <subdev/timer.h>
  #define CHIPSET_NFORCE 0x01a0
  #define CHIPSET_NFORCE2 0x01f0
  
@@@ -82,12 -86,12 +86,12 @@@ NVReadVgaGr(struct drm_device *dev, in
  void
  NVSetOwner(struct drm_device *dev, int owner)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
        if (owner == 1)
                owner *= 3;
  
-       if (dev_priv->chipset == 0x11) {
+       if (nv_device(drm->device)->chipset == 0x11) {
                /* This might seem stupid, but the blob does it and
                 * omitting it often locks the system up.
                 */
        /* CR44 is always changed on CRTC0 */
        NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_44, owner);
  
-       if (dev_priv->chipset == 0x11) {        /* set me harder */
+       if (nv_device(drm->device)->chipset == 0x11) {  /* set me harder */
                NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_2E, owner);
                NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_2E, owner);
        }
@@@ -123,270 -127,6 +127,6 @@@ NVBlankScreen(struct drm_device *dev, i
  }
  
  /*
-  * PLL setting
-  */
- static int
- powerctrl_1_shift(int chip_version, int reg)
- {
-       int shift = -4;
-       if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20)
-               return shift;
-       switch (reg) {
-       case NV_RAMDAC_VPLL2:
-               shift += 4;
-       case NV_PRAMDAC_VPLL_COEFF:
-               shift += 4;
-       case NV_PRAMDAC_MPLL_COEFF:
-               shift += 4;
-       case NV_PRAMDAC_NVPLL_COEFF:
-               shift += 4;
-       }
-       /*
-        * the shift for vpll regs is only used for nv3x chips with a single
-        * stage pll
-        */
-       if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 ||
-                         chip_version == 0x36 || chip_version >= 0x40))
-               shift = -4;
-       return shift;
- }
- static void
- setPLL_single(struct drm_device *dev, uint32_t reg, struct nouveau_pll_vals *pv)
- {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       int chip_version = dev_priv->vbios.chip_version;
-       uint32_t oldpll = NVReadRAMDAC(dev, 0, reg);
-       int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff;
-       uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1;
-       uint32_t saved_powerctrl_1 = 0;
-       int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg);
-       if (oldpll == pll)
-               return; /* already set */
-       if (shift_powerctrl_1 >= 0) {
-               saved_powerctrl_1 = nvReadMC(dev, NV_PBUS_POWERCTRL_1);
-               nvWriteMC(dev, NV_PBUS_POWERCTRL_1,
-                       (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
-                       1 << shift_powerctrl_1);
-       }
-       if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1))
-               /* upclock -- write new post divider first */
-               NVWriteRAMDAC(dev, 0, reg, pv->log2P << 16 | (oldpll & 0xffff));
-       else
-               /* downclock -- write new NM first */
-               NVWriteRAMDAC(dev, 0, reg, (oldpll & 0xffff0000) | pv->NM1);
-       if (chip_version < 0x17 && chip_version != 0x11)
-               /* wait a bit on older chips */
-               msleep(64);
-       NVReadRAMDAC(dev, 0, reg);
-       /* then write the other half as well */
-       NVWriteRAMDAC(dev, 0, reg, pll);
-       if (shift_powerctrl_1 >= 0)
-               nvWriteMC(dev, NV_PBUS_POWERCTRL_1, saved_powerctrl_1);
- }
- static uint32_t
- new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580)
- {
-       bool head_a = (reg1 == NV_PRAMDAC_VPLL_COEFF);
-       if (ss) /* single stage pll mode */
-               ramdac580 |= head_a ? NV_RAMDAC_580_VPLL1_ACTIVE :
-                                     NV_RAMDAC_580_VPLL2_ACTIVE;
-       else
-               ramdac580 &= head_a ? ~NV_RAMDAC_580_VPLL1_ACTIVE :
-                                     ~NV_RAMDAC_580_VPLL2_ACTIVE;
-       return ramdac580;
- }
- static void
- setPLL_double_highregs(struct drm_device *dev, uint32_t reg1,
-                      struct nouveau_pll_vals *pv)
- {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       int chip_version = dev_priv->vbios.chip_version;
-       bool nv3035 = chip_version == 0x30 || chip_version == 0x35;
-       uint32_t reg2 = reg1 + ((reg1 == NV_RAMDAC_VPLL2) ? 0x5c : 0x70);
-       uint32_t oldpll1 = NVReadRAMDAC(dev, 0, reg1);
-       uint32_t oldpll2 = !nv3035 ? NVReadRAMDAC(dev, 0, reg2) : 0;
-       uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1;
-       uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2;
-       uint32_t oldramdac580 = 0, ramdac580 = 0;
-       bool single_stage = !pv->NM2 || pv->N2 == pv->M2;       /* nv41+ only */
-       uint32_t saved_powerctrl_1 = 0, savedc040 = 0;
-       int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg1);
-       /* model specific additions to generic pll1 and pll2 set up above */
-       if (nv3035) {
-               pll1 = (pll1 & 0xfcc7ffff) | (pv->N2 & 0x18) << 21 |
-                      (pv->N2 & 0x7) << 19 | 8 << 4 | (pv->M2 & 7) << 4;
-               pll2 = 0;
-       }
-       if (chip_version > 0x40 && reg1 >= NV_PRAMDAC_VPLL_COEFF) { /* !nv40 */
-               oldramdac580 = NVReadRAMDAC(dev, 0, NV_PRAMDAC_580);
-               ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580);
-               if (oldramdac580 != ramdac580)
-                       oldpll1 = ~0;   /* force mismatch */
-               if (single_stage)
-                       /* magic value used by nvidia in single stage mode */
-                       pll2 |= 0x011f;
-       }
-       if (chip_version > 0x70)
-               /* magic bits set by the blob (but not the bios) on g71-73 */
-               pll1 = (pll1 & 0x7fffffff) | (single_stage ? 0x4 : 0xc) << 28;
-       if (oldpll1 == pll1 && oldpll2 == pll2)
-               return; /* already set */
-       if (shift_powerctrl_1 >= 0) {
-               saved_powerctrl_1 = nvReadMC(dev, NV_PBUS_POWERCTRL_1);
-               nvWriteMC(dev, NV_PBUS_POWERCTRL_1,
-                       (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
-                       1 << shift_powerctrl_1);
-       }
-       if (chip_version >= 0x40) {
-               int shift_c040 = 14;
-               switch (reg1) {
-               case NV_PRAMDAC_MPLL_COEFF:
-                       shift_c040 += 2;
-               case NV_PRAMDAC_NVPLL_COEFF:
-                       shift_c040 += 2;
-               case NV_RAMDAC_VPLL2:
-                       shift_c040 += 2;
-               case NV_PRAMDAC_VPLL_COEFF:
-                       shift_c040 += 2;
-               }
-               savedc040 = nvReadMC(dev, 0xc040);
-               if (shift_c040 != 14)
-                       nvWriteMC(dev, 0xc040, savedc040 & ~(3 << shift_c040));
-       }
-       if (oldramdac580 != ramdac580)
-               NVWriteRAMDAC(dev, 0, NV_PRAMDAC_580, ramdac580);
-       if (!nv3035)
-               NVWriteRAMDAC(dev, 0, reg2, pll2);
-       NVWriteRAMDAC(dev, 0, reg1, pll1);
-       if (shift_powerctrl_1 >= 0)
-               nvWriteMC(dev, NV_PBUS_POWERCTRL_1, saved_powerctrl_1);
-       if (chip_version >= 0x40)
-               nvWriteMC(dev, 0xc040, savedc040);
- }
- static void
- setPLL_double_lowregs(struct drm_device *dev, uint32_t NMNMreg,
-                     struct nouveau_pll_vals *pv)
- {
-       /* When setting PLLs, there is a merry game of disabling and enabling
-        * various bits of hardware during the process. This function is a
-        * synthesis of six nv4x traces, nearly each card doing a subtly
-        * different thing. With luck all the necessary bits for each card are
-        * combined herein. Without luck it deviates from each card's formula
-        * so as to not work on any :)
-        */
-       uint32_t Preg = NMNMreg - 4;
-       bool mpll = Preg == 0x4020;
-       uint32_t oldPval = nvReadMC(dev, Preg);
-       uint32_t NMNM = pv->NM2 << 16 | pv->NM1;
-       uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) |
-                       0xc << 28 | pv->log2P << 16;
-       uint32_t saved4600 = 0;
-       /* some cards have different maskc040s */
-       uint32_t maskc040 = ~(3 << 14), savedc040;
-       bool single_stage = !pv->NM2 || pv->N2 == pv->M2;
-       if (nvReadMC(dev, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval)
-               return;
-       if (Preg == 0x4000)
-               maskc040 = ~0x333;
-       if (Preg == 0x4058)
-               maskc040 = ~(0xc << 24);
-       if (mpll) {
-               struct pll_lims pll_lim;
-               uint8_t Pval2;
-               if (get_pll_limits(dev, Preg, &pll_lim))
-                       return;
-               Pval2 = pv->log2P + pll_lim.log2p_bias;
-               if (Pval2 > pll_lim.max_log2p)
-                       Pval2 = pll_lim.max_log2p;
-               Pval |= 1 << 28 | Pval2 << 20;
-               saved4600 = nvReadMC(dev, 0x4600);
-               nvWriteMC(dev, 0x4600, saved4600 | 8 << 28);
-       }
-       if (single_stage)
-               Pval |= mpll ? 1 << 12 : 1 << 8;
-       nvWriteMC(dev, Preg, oldPval | 1 << 28);
-       nvWriteMC(dev, Preg, Pval & ~(4 << 28));
-       if (mpll) {
-               Pval |= 8 << 20;
-               nvWriteMC(dev, 0x4020, Pval & ~(0xc << 28));
-               nvWriteMC(dev, 0x4038, Pval & ~(0xc << 28));
-       }
-       savedc040 = nvReadMC(dev, 0xc040);
-       nvWriteMC(dev, 0xc040, savedc040 & maskc040);
-       nvWriteMC(dev, NMNMreg, NMNM);
-       if (NMNMreg == 0x4024)
-               nvWriteMC(dev, 0x403c, NMNM);
-       nvWriteMC(dev, Preg, Pval);
-       if (mpll) {
-               Pval &= ~(8 << 20);
-               nvWriteMC(dev, 0x4020, Pval);
-               nvWriteMC(dev, 0x4038, Pval);
-               nvWriteMC(dev, 0x4600, saved4600);
-       }
-       nvWriteMC(dev, 0xc040, savedc040);
-       if (mpll) {
-               nvWriteMC(dev, 0x4020, Pval & ~(1 << 28));
-               nvWriteMC(dev, 0x4038, Pval & ~(1 << 28));
-       }
- }
- void
- nouveau_hw_setpll(struct drm_device *dev, uint32_t reg1,
-                 struct nouveau_pll_vals *pv)
- {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       int cv = dev_priv->vbios.chip_version;
-       if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
-           cv >= 0x40) {
-               if (reg1 > 0x405c)
-                       setPLL_double_highregs(dev, reg1, pv);
-               else
-                       setPLL_double_lowregs(dev, reg1, pv);
-       } else
-               setPLL_single(dev, reg1, pv);
- }
- /*
   * PLL getting
   */
  
@@@ -394,7 -134,7 +134,7 @@@ static voi
  nouveau_hw_decode_pll(struct drm_device *dev, uint32_t reg1, uint32_t pll1,
                      uint32_t pll2, struct nouveau_pll_vals *pllvals)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
        /* to force parsing as single stage (i.e. nv40 vplls) pass pll2 as 0 */
  
                pllvals->NM1 = pll1 & 0xffff;
                if (nv_two_reg_pll(dev) && pll2 & NV31_RAMDAC_ENABLE_VCO2)
                        pllvals->NM2 = pll2 & 0xffff;
-               else if (dev_priv->chipset == 0x30 || dev_priv->chipset == 0x35) {
+               else if (nv_device(drm->device)->chipset == 0x30 || nv_device(drm->device)->chipset == 0x35) {
                        pllvals->M1 &= 0xf; /* only 4 bits */
                        if (pll1 & NV30_RAMDAC_ENABLE_VCO2) {
                                pllvals->M2 = (pll1 >> 4) & 0x7;
  }
  
  int
- nouveau_hw_get_pllvals(struct drm_device *dev, enum pll_types plltype,
+ nouveau_hw_get_pllvals(struct drm_device *dev, enum nvbios_pll_type plltype,
                       struct nouveau_pll_vals *pllvals)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t reg1 = get_pll_register(dev, plltype), pll1, pll2 = 0;
-       struct pll_lims pll_lim;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nv_device(drm->device);
+       struct nouveau_bios *bios = nouveau_bios(device);
+       uint32_t reg1, pll1, pll2 = 0;
+       struct nvbios_pll pll_lim;
        int ret;
  
-       if (reg1 == 0)
+       ret = nvbios_pll_parse(bios, plltype, &pll_lim);
+       if (ret || !(reg1 = pll_lim.reg))
                return -ENOENT;
  
-       pll1 = nvReadMC(dev, reg1);
+       pll1 = nv_rd32(device, reg1);
        if (reg1 <= 0x405c)
-               pll2 = nvReadMC(dev, reg1 + 4);
+               pll2 = nv_rd32(device, reg1 + 4);
        else if (nv_two_reg_pll(dev)) {
                uint32_t reg2 = reg1 + (reg1 == NV_RAMDAC_VPLL2 ? 0x5c : 0x70);
  
-               pll2 = nvReadMC(dev, reg2);
+               pll2 = nv_rd32(device, reg2);
        }
  
-       if (dev_priv->card_type == 0x40 && reg1 >= NV_PRAMDAC_VPLL_COEFF) {
+       if (nv_device(drm->device)->card_type == 0x40 && reg1 >= NV_PRAMDAC_VPLL_COEFF) {
                uint32_t ramdac580 = NVReadRAMDAC(dev, 0, NV_PRAMDAC_580);
  
                /* check whether vpll has been forced into single stage mode */
        }
  
        nouveau_hw_decode_pll(dev, reg1, pll1, pll2, pllvals);
-       ret = get_pll_limits(dev, plltype, &pll_lim);
-       if (ret)
-               return ret;
        pllvals->refclk = pll_lim.refclk;
        return 0;
  }
  
@@@ -478,7 -214,7 +214,7 @@@ nouveau_hw_pllvals_to_clk(struct nouvea
  }
  
  int
- nouveau_hw_get_clock(struct drm_device *dev, enum pll_types plltype)
+ nouveau_hw_get_clock(struct drm_device *dev, enum nvbios_pll_type plltype)
  {
        struct nouveau_pll_vals pllvals;
        int ret;
@@@ -517,26 -253,30 +253,30 @@@ nouveau_hw_fix_bad_vpll(struct drm_devi
         * when such a condition detected.  only seen on nv11 to date
         */
  
-       struct pll_lims pll_lim;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nv_device(drm->device);
+       struct nouveau_clock *clk = nouveau_clock(device);
+       struct nouveau_bios *bios = nouveau_bios(device);
+       struct nvbios_pll pll_lim;
        struct nouveau_pll_vals pv;
-       enum pll_types pll = head ? PLL_VPLL1 : PLL_VPLL0;
+       enum nvbios_pll_type pll = head ? PLL_VPLL1 : PLL_VPLL0;
  
-       if (get_pll_limits(dev, pll, &pll_lim))
+       if (nvbios_pll_parse(bios, pll, &pll_lim))
                return;
        nouveau_hw_get_pllvals(dev, pll, &pv);
  
        if (pv.M1 >= pll_lim.vco1.min_m && pv.M1 <= pll_lim.vco1.max_m &&
            pv.N1 >= pll_lim.vco1.min_n && pv.N1 <= pll_lim.vco1.max_n &&
-           pv.log2P <= pll_lim.max_log2p)
+           pv.log2P <= pll_lim.max_p)
                return;
  
-       NV_WARN(dev, "VPLL %d outwith limits, attempting to fix\n", head + 1);
+       NV_WARN(drm, "VPLL %d outwith limits, attempting to fix\n", head + 1);
  
        /* set lowest clock within static limits */
        pv.M1 = pll_lim.vco1.max_m;
        pv.N1 = pll_lim.vco1.min_n;
-       pv.log2P = pll_lim.max_usable_log2p;
-       nouveau_hw_setpll(dev, pll_lim.reg, &pv);
+       pv.log2P = pll_lim.max_p_usable;
+       clk->pll_prog(clk, pll_lim.reg, &pv);
  }
  
  /*
@@@ -547,17 -287,16 +287,16 @@@ static void nouveau_vga_font_io(struct 
                                void __iomem *iovram,
                                bool save, unsigned plane)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        unsigned i;
  
        NVWriteVgaSeq(dev, 0, NV_VIO_SR_PLANE_MASK_INDEX, 1 << plane);
        NVWriteVgaGr(dev, 0, NV_VIO_GX_READ_MAP_INDEX, plane);
        for (i = 0; i < 16384; i++) {
                if (save) {
-                       dev_priv->saved_vga_font[plane][i] =
+                       nv04_display(dev)->saved_vga_font[plane][i] =
                                        ioread32_native(iovram + i * 4);
                } else {
-                       iowrite32_native(dev_priv->saved_vga_font[plane][i],
+                       iowrite32_native(nv04_display(dev)->saved_vga_font[plane][i],
                                                        iovram + i * 4);
                }
        }
  void
  nouveau_hw_save_vga_fonts(struct drm_device *dev, bool save)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        uint8_t misc, gr4, gr5, gr6, seq2, seq4;
        bool graphicsmode;
        unsigned plane;
        if (graphicsmode) /* graphics mode => framebuffer => no need to save */
                return;
  
-       NV_INFO(dev, "%sing VGA fonts\n", save ? "Sav" : "Restor");
+       NV_INFO(drm, "%sing VGA fonts\n", save ? "Sav" : "Restor");
  
        /* map first 64KiB of VRAM, holds VGA fonts etc */
        iovram = ioremap(pci_resource_start(dev->pdev, 1), 65536);
        if (!iovram) {
-               NV_ERROR(dev, "Failed to map VRAM, "
+               NV_ERROR(drm, "Failed to map VRAM, "
                                        "cannot save/restore VGA fonts.\n");
                return;
        }
@@@ -649,25 -389,25 +389,25 @@@ static voi
  nv_save_state_ramdac(struct drm_device *dev, int head,
                     struct nv04_mode_state *state)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nv04_crtc_reg *regp = &state->crtc_reg[head];
        int i;
  
-       if (dev_priv->card_type >= NV_10)
+       if (nv_device(drm->device)->card_type >= NV_10)
                regp->nv10_cursync = NVReadRAMDAC(dev, head, NV_RAMDAC_NV10_CURSYNC);
  
        nouveau_hw_get_pllvals(dev, head ? PLL_VPLL1 : PLL_VPLL0, &regp->pllvals);
        state->pllsel = NVReadRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT);
        if (nv_two_heads(dev))
                state->sel_clk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK);
-       if (dev_priv->chipset == 0x11)
+       if (nv_device(drm->device)->chipset == 0x11)
                regp->dither = NVReadRAMDAC(dev, head, NV_RAMDAC_DITHER_NV11);
  
        regp->ramdac_gen_ctrl = NVReadRAMDAC(dev, head, NV_PRAMDAC_GENERAL_CONTROL);
  
        if (nv_gf4_disp_arch(dev))
                regp->ramdac_630 = NVReadRAMDAC(dev, head, NV_PRAMDAC_630);
-       if (dev_priv->chipset >= 0x30)
+       if (nv_device(drm->device)->chipset >= 0x30)
                regp->ramdac_634 = NVReadRAMDAC(dev, head, NV_PRAMDAC_634);
  
        regp->tv_setup = NVReadRAMDAC(dev, head, NV_PRAMDAC_TV_SETUP);
        if (nv_gf4_disp_arch(dev))
                regp->ramdac_8c0 = NVReadRAMDAC(dev, head, NV_PRAMDAC_8C0);
  
-       if (dev_priv->card_type == NV_40) {
+       if (nv_device(drm->device)->card_type == NV_40) {
                regp->ramdac_a20 = NVReadRAMDAC(dev, head, NV_PRAMDAC_A20);
                regp->ramdac_a24 = NVReadRAMDAC(dev, head, NV_PRAMDAC_A24);
                regp->ramdac_a34 = NVReadRAMDAC(dev, head, NV_PRAMDAC_A34);
@@@ -724,26 -464,27 +464,27 @@@ static voi
  nv_load_state_ramdac(struct drm_device *dev, int head,
                     struct nv04_mode_state *state)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_clock *clk = nouveau_clock(drm->device);
        struct nv04_crtc_reg *regp = &state->crtc_reg[head];
        uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF;
        int i;
  
-       if (dev_priv->card_type >= NV_10)
+       if (nv_device(drm->device)->card_type >= NV_10)
                NVWriteRAMDAC(dev, head, NV_RAMDAC_NV10_CURSYNC, regp->nv10_cursync);
  
-       nouveau_hw_setpll(dev, pllreg, &regp->pllvals);
+       clk->pll_prog(clk, pllreg, &regp->pllvals);
        NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel);
        if (nv_two_heads(dev))
                NVWriteRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK, state->sel_clk);
-       if (dev_priv->chipset == 0x11)
+       if (nv_device(drm->device)->chipset == 0x11)
                NVWriteRAMDAC(dev, head, NV_RAMDAC_DITHER_NV11, regp->dither);
  
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_GENERAL_CONTROL, regp->ramdac_gen_ctrl);
  
        if (nv_gf4_disp_arch(dev))
                NVWriteRAMDAC(dev, head, NV_PRAMDAC_630, regp->ramdac_630);
-       if (dev_priv->chipset >= 0x30)
+       if (nv_device(drm->device)->chipset >= 0x30)
                NVWriteRAMDAC(dev, head, NV_PRAMDAC_634, regp->ramdac_634);
  
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_TV_SETUP, regp->tv_setup);
        if (nv_gf4_disp_arch(dev))
                NVWriteRAMDAC(dev, head, NV_PRAMDAC_8C0, regp->ramdac_8c0);
  
-       if (dev_priv->card_type == NV_40) {
+       if (nv_device(drm->device)->card_type == NV_40) {
                NVWriteRAMDAC(dev, head, NV_PRAMDAC_A20, regp->ramdac_a20);
                NVWriteRAMDAC(dev, head, NV_PRAMDAC_A24, regp->ramdac_a24);
                NVWriteRAMDAC(dev, head, NV_PRAMDAC_A34, regp->ramdac_a34);
@@@ -845,7 -586,7 +586,7 @@@ static voi
  nv_save_state_ext(struct drm_device *dev, int head,
                  struct nv04_mode_state *state)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nv04_crtc_reg *regp = &state->crtc_reg[head];
        int i;
  
        rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
        rd_cio_state(dev, head, regp, NV_CIO_CRE_21);
  
-       if (dev_priv->card_type >= NV_20)
+       if (nv_device(drm->device)->card_type >= NV_20)
                rd_cio_state(dev, head, regp, NV_CIO_CRE_47);
  
-       if (dev_priv->card_type >= NV_30)
+       if (nv_device(drm->device)->card_type >= NV_30)
                rd_cio_state(dev, head, regp, 0x9f);
  
        rd_cio_state(dev, head, regp, NV_CIO_CRE_49);
        rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR2_INDEX);
        rd_cio_state(dev, head, regp, NV_CIO_CRE_ILACE__INDEX);
  
-       if (dev_priv->card_type >= NV_10) {
+       if (nv_device(drm->device)->card_type >= NV_10) {
                regp->crtc_830 = NVReadCRTC(dev, head, NV_PCRTC_830);
                regp->crtc_834 = NVReadCRTC(dev, head, NV_PCRTC_834);
  
-               if (dev_priv->card_type >= NV_30)
+               if (nv_device(drm->device)->card_type >= NV_30)
                        regp->gpio_ext = NVReadCRTC(dev, head, NV_PCRTC_GPIO_EXT);
  
-               if (dev_priv->card_type == NV_40)
+               if (nv_device(drm->device)->card_type == NV_40)
                        regp->crtc_850 = NVReadCRTC(dev, head, NV_PCRTC_850);
  
                if (nv_two_heads(dev))
  
        rd_cio_state(dev, head, regp, NV_CIO_CRE_SCRATCH3__INDEX);
        rd_cio_state(dev, head, regp, NV_CIO_CRE_SCRATCH4__INDEX);
-       if (dev_priv->card_type >= NV_10) {
+       if (nv_device(drm->device)->card_type >= NV_10) {
                rd_cio_state(dev, head, regp, NV_CIO_CRE_EBR_INDEX);
                rd_cio_state(dev, head, regp, NV_CIO_CRE_CSB);
                rd_cio_state(dev, head, regp, NV_CIO_CRE_4B);
@@@ -920,12 -661,14 +661,14 @@@ static voi
  nv_load_state_ext(struct drm_device *dev, int head,
                  struct nv04_mode_state *state)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nv_device(drm->device);
+       struct nouveau_timer *ptimer = nouveau_timer(device);
        struct nv04_crtc_reg *regp = &state->crtc_reg[head];
        uint32_t reg900;
        int i;
  
-       if (dev_priv->card_type >= NV_10) {
+       if (nv_device(drm->device)->card_type >= NV_10) {
                if (nv_two_heads(dev))
                        /* setting ENGINE_CTRL (EC) *must* come before
                         * CIO_CRE_LCD, as writing CRE_LCD sets bits 16 & 17 in
                         */
                        NVWriteCRTC(dev, head, NV_PCRTC_ENGINE_CTRL, regp->crtc_eng_ctrl);
  
-               nvWriteVIDEO(dev, NV_PVIDEO_STOP, 1);
-               nvWriteVIDEO(dev, NV_PVIDEO_INTR_EN, 0);
-               nvWriteVIDEO(dev, NV_PVIDEO_OFFSET_BUFF(0), 0);
-               nvWriteVIDEO(dev, NV_PVIDEO_OFFSET_BUFF(1), 0);
-               nvWriteVIDEO(dev, NV_PVIDEO_LIMIT(0), dev_priv->fb_available_size - 1);
-               nvWriteVIDEO(dev, NV_PVIDEO_LIMIT(1), dev_priv->fb_available_size - 1);
-               nvWriteVIDEO(dev, NV_PVIDEO_UVPLANE_LIMIT(0), dev_priv->fb_available_size - 1);
-               nvWriteVIDEO(dev, NV_PVIDEO_UVPLANE_LIMIT(1), dev_priv->fb_available_size - 1);
-               nvWriteMC(dev, NV_PBUS_POWERCTRL_2, 0);
+               nv_wr32(device, NV_PVIDEO_STOP, 1);
+               nv_wr32(device, NV_PVIDEO_INTR_EN, 0);
+               nv_wr32(device, NV_PVIDEO_OFFSET_BUFF(0), 0);
+               nv_wr32(device, NV_PVIDEO_OFFSET_BUFF(1), 0);
+               nv_wr32(device, NV_PVIDEO_LIMIT(0), 0); //drm->fb_available_size - 1);
+               nv_wr32(device, NV_PVIDEO_LIMIT(1), 0); //drm->fb_available_size - 1);
+               nv_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(0), 0); //drm->fb_available_size - 1);
+               nv_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(1), 0); //drm->fb_available_size - 1);
+               nv_wr32(device, NV_PBUS_POWERCTRL_2, 0);
  
                NVWriteCRTC(dev, head, NV_PCRTC_CURSOR_CONFIG, regp->cursor_cfg);
                NVWriteCRTC(dev, head, NV_PCRTC_830, regp->crtc_830);
                NVWriteCRTC(dev, head, NV_PCRTC_834, regp->crtc_834);
  
-               if (dev_priv->card_type >= NV_30)
+               if (nv_device(drm->device)->card_type >= NV_30)
                        NVWriteCRTC(dev, head, NV_PCRTC_GPIO_EXT, regp->gpio_ext);
  
-               if (dev_priv->card_type == NV_40) {
+               if (nv_device(drm->device)->card_type == NV_40) {
                        NVWriteCRTC(dev, head, NV_PCRTC_850, regp->crtc_850);
  
                        reg900 = NVReadRAMDAC(dev, head, NV_PRAMDAC_900);
        wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
        wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
  
-       if (dev_priv->card_type >= NV_20)
+       if (nv_device(drm->device)->card_type >= NV_20)
                wr_cio_state(dev, head, regp, NV_CIO_CRE_47);
  
-       if (dev_priv->card_type >= NV_30)
+       if (nv_device(drm->device)->card_type >= NV_30)
                wr_cio_state(dev, head, regp, 0x9f);
  
        wr_cio_state(dev, head, regp, NV_CIO_CRE_49);
        wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
        wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX);
        wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR2_INDEX);
-       if (dev_priv->card_type == NV_40)
+       if (nv_device(drm->device)->card_type == NV_40)
                nv_fix_nv40_hw_cursor(dev, head);
        wr_cio_state(dev, head, regp, NV_CIO_CRE_ILACE__INDEX);
  
        wr_cio_state(dev, head, regp, NV_CIO_CRE_SCRATCH3__INDEX);
        wr_cio_state(dev, head, regp, NV_CIO_CRE_SCRATCH4__INDEX);
-       if (dev_priv->card_type >= NV_10) {
+       if (nv_device(drm->device)->card_type >= NV_10) {
                wr_cio_state(dev, head, regp, NV_CIO_CRE_EBR_INDEX);
                wr_cio_state(dev, head, regp, NV_CIO_CRE_CSB);
                wr_cio_state(dev, head, regp, NV_CIO_CRE_4B);
        }
        /* NV11 and NV20 stop at 0x52. */
        if (nv_gf4_disp_arch(dev)) {
-               if (dev_priv->card_type == NV_10) {
+               if (nv_device(drm->device)->card_type == NV_10) {
                        /* Not waiting for vertical retrace before modifying
                           CRE_53/CRE_54 causes lockups. */
-                       nouveau_wait_eq(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8);
-                       nouveau_wait_eq(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0);
+                       nouveau_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8);
+                       nouveau_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0);
                }
  
                wr_cio_state(dev, head, regp, NV_CIO_CRE_42);
@@@ -1024,14 -767,15 +767,15 @@@ static voi
  nv_save_state_palette(struct drm_device *dev, int head,
                      struct nv04_mode_state *state)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        int head_offset = head * NV_PRMDIO_SIZE, i;
  
-       nv_wr08(dev, NV_PRMDIO_PIXEL_MASK + head_offset,
+       nv_wr08(device, NV_PRMDIO_PIXEL_MASK + head_offset,
                                NV_PRMDIO_PIXEL_MASK_MASK);
-       nv_wr08(dev, NV_PRMDIO_READ_MODE_ADDRESS + head_offset, 0x0);
+       nv_wr08(device, NV_PRMDIO_READ_MODE_ADDRESS + head_offset, 0x0);
  
        for (i = 0; i < 768; i++) {
-               state->crtc_reg[head].DAC[i] = nv_rd08(dev,
+               state->crtc_reg[head].DAC[i] = nv_rd08(device,
                                NV_PRMDIO_PALETTE_DATA + head_offset);
        }
  
@@@ -1042,14 -786,15 +786,15 @@@ voi
  nouveau_hw_load_state_palette(struct drm_device *dev, int head,
                              struct nv04_mode_state *state)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        int head_offset = head * NV_PRMDIO_SIZE, i;
  
-       nv_wr08(dev, NV_PRMDIO_PIXEL_MASK + head_offset,
+       nv_wr08(device, NV_PRMDIO_PIXEL_MASK + head_offset,
                                NV_PRMDIO_PIXEL_MASK_MASK);
-       nv_wr08(dev, NV_PRMDIO_WRITE_MODE_ADDRESS + head_offset, 0x0);
+       nv_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS + head_offset, 0x0);
  
        for (i = 0; i < 768; i++) {
-               nv_wr08(dev, NV_PRMDIO_PALETTE_DATA + head_offset,
+               nv_wr08(device, NV_PRMDIO_PALETTE_DATA + head_offset,
                                state->crtc_reg[head].DAC[i]);
        }
  
  void nouveau_hw_save_state(struct drm_device *dev, int head,
                           struct nv04_mode_state *state)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
-       if (dev_priv->chipset == 0x11)
+       if (nv_device(drm->device)->chipset == 0x11)
                /* NB: no attempt is made to restore the bad pll later on */
                nouveau_hw_fix_bad_vpll(dev, head);
        nv_save_state_ramdac(dev, head, state);
  #ifndef __NOUVEAU_HW_H__
  #define __NOUVEAU_HW_H__
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
- #include "nouveau_drv.h"
+ #include "nv04_display.h"
+ #include <subdev/bios/pll.h>
  
  #define MASK(field) ( \
        (0xffffffff >> (31 - ((1 ? field) - (0 ? field)))) << (0 ? field))
@@@ -38,12 -40,10 +40,10 @@@ void NVWriteVgaGr(struct drm_device *, 
  uint8_t NVReadVgaGr(struct drm_device *, int head, uint8_t index);
  void NVSetOwner(struct drm_device *, int owner);
  void NVBlankScreen(struct drm_device *, int head, bool blank);
- void nouveau_hw_setpll(struct drm_device *, uint32_t reg1,
-                      struct nouveau_pll_vals *pv);
- int nouveau_hw_get_pllvals(struct drm_device *, enum pll_types plltype,
+ int nouveau_hw_get_pllvals(struct drm_device *, enum nvbios_pll_type plltype,
                           struct nouveau_pll_vals *pllvals);
  int nouveau_hw_pllvals_to_clk(struct nouveau_pll_vals *pllvals);
- int nouveau_hw_get_clock(struct drm_device *, enum pll_types plltype);
+ int nouveau_hw_get_clock(struct drm_device *, enum nvbios_pll_type plltype);
  void nouveau_hw_save_vga_fonts(struct drm_device *, bool save);
  void nouveau_hw_save_state(struct drm_device *, int head,
                           struct nv04_mode_state *state);
@@@ -55,115 -55,51 +55,51 @@@ void nouveau_hw_load_state_palette(stru
  /* nouveau_calc.c */
  extern void nouveau_calc_arb(struct drm_device *, int vclk, int bpp,
                             int *burst, int *lwm);
- extern int nouveau_calc_pll_mnp(struct drm_device *, struct pll_lims *pll_lim,
-                               int clk, struct nouveau_pll_vals *pv);
- static inline uint32_t
- nvReadMC(struct drm_device *dev, uint32_t reg)
- {
-       uint32_t val = nv_rd32(dev, reg);
-       NV_REG_DEBUG(MC, dev, "reg %08x val %08x\n", reg, val);
-       return val;
- }
- static inline void
- nvWriteMC(struct drm_device *dev, uint32_t reg, uint32_t val)
- {
-       NV_REG_DEBUG(MC, dev, "reg %08x val %08x\n", reg, val);
-       nv_wr32(dev, reg, val);
- }
- static inline uint32_t
- nvReadVIDEO(struct drm_device *dev, uint32_t reg)
- {
-       uint32_t val = nv_rd32(dev, reg);
-       NV_REG_DEBUG(VIDEO, dev, "reg %08x val %08x\n", reg, val);
-       return val;
- }
- static inline void
- nvWriteVIDEO(struct drm_device *dev, uint32_t reg, uint32_t val)
- {
-       NV_REG_DEBUG(VIDEO, dev, "reg %08x val %08x\n", reg, val);
-       nv_wr32(dev, reg, val);
- }
- static inline uint32_t
- nvReadFB(struct drm_device *dev, uint32_t reg)
- {
-       uint32_t val = nv_rd32(dev, reg);
-       NV_REG_DEBUG(FB, dev, "reg %08x val %08x\n", reg, val);
-       return val;
- }
- static inline void
- nvWriteFB(struct drm_device *dev, uint32_t reg, uint32_t val)
- {
-       NV_REG_DEBUG(FB, dev, "reg %08x val %08x\n", reg, val);
-       nv_wr32(dev, reg, val);
- }
- static inline uint32_t
- nvReadEXTDEV(struct drm_device *dev, uint32_t reg)
- {
-       uint32_t val = nv_rd32(dev, reg);
-       NV_REG_DEBUG(EXTDEV, dev, "reg %08x val %08x\n", reg, val);
-       return val;
- }
- static inline void
- nvWriteEXTDEV(struct drm_device *dev, uint32_t reg, uint32_t val)
- {
-       NV_REG_DEBUG(EXTDEV, dev, "reg %08x val %08x\n", reg, val);
-       nv_wr32(dev, reg, val);
- }
  
  static inline uint32_t NVReadCRTC(struct drm_device *dev,
                                        int head, uint32_t reg)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        uint32_t val;
        if (head)
                reg += NV_PCRTC0_SIZE;
-       val = nv_rd32(dev, reg);
-       NV_REG_DEBUG(CRTC, dev, "head %d reg %08x val %08x\n", head, reg, val);
+       val = nv_rd32(device, reg);
        return val;
  }
  
  static inline void NVWriteCRTC(struct drm_device *dev,
                                        int head, uint32_t reg, uint32_t val)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        if (head)
                reg += NV_PCRTC0_SIZE;
-       NV_REG_DEBUG(CRTC, dev, "head %d reg %08x val %08x\n", head, reg, val);
-       nv_wr32(dev, reg, val);
+       nv_wr32(device, reg, val);
  }
  
  static inline uint32_t NVReadRAMDAC(struct drm_device *dev,
                                        int head, uint32_t reg)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        uint32_t val;
        if (head)
                reg += NV_PRAMDAC0_SIZE;
-       val = nv_rd32(dev, reg);
-       NV_REG_DEBUG(RAMDAC, dev, "head %d reg %08x val %08x\n",
-                                                       head, reg, val);
+       val = nv_rd32(device, reg);
        return val;
  }
  
  static inline void NVWriteRAMDAC(struct drm_device *dev,
                                        int head, uint32_t reg, uint32_t val)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        if (head)
                reg += NV_PRAMDAC0_SIZE;
-       NV_REG_DEBUG(RAMDAC, dev, "head %d reg %08x val %08x\n",
-                                                       head, reg, val);
-       nv_wr32(dev, reg, val);
+       nv_wr32(device, reg, val);
  }
  
  static inline uint8_t nv_read_tmds(struct drm_device *dev,
                                        int or, int dl, uint8_t address)
  {
-       int ramdac = (or & OUTPUT_C) >> 2;
+       int ramdac = (or & DCB_OUTPUT_C) >> 2;
  
        NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8,
        NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE | address);
@@@ -174,7 -110,7 +110,7 @@@ static inline void nv_write_tmds(struc
                                        int or, int dl, uint8_t address,
                                        uint8_t data)
  {
-       int ramdac = (or & OUTPUT_C) >> 2;
+       int ramdac = (or & DCB_OUTPUT_C) >> 2;
  
        NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA + dl * 8, data);
        NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8, address);
  static inline void NVWriteVgaCrtc(struct drm_device *dev,
                                        int head, uint8_t index, uint8_t value)
  {
-       NV_REG_DEBUG(VGACRTC, dev, "head %d index 0x%02x data 0x%02x\n",
-                                                       head, index, value);
-       nv_wr08(dev, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
-       nv_wr08(dev, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE, value);
+       struct nouveau_device *device = nouveau_dev(dev);
+       nv_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
+       nv_wr08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE, value);
  }
  
  static inline uint8_t NVReadVgaCrtc(struct drm_device *dev,
                                        int head, uint8_t index)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        uint8_t val;
-       nv_wr08(dev, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
-       val = nv_rd08(dev, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE);
-       NV_REG_DEBUG(VGACRTC, dev, "head %d index 0x%02x data 0x%02x\n",
-                                                       head, index, val);
+       nv_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
+       val = nv_rd08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE);
        return val;
  }
  
@@@ -230,75 -164,74 +164,74 @@@ static inline uint8_t NVReadVgaCrtc5758
  static inline uint8_t NVReadPRMVIO(struct drm_device *dev,
                                        int head, uint32_t reg)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        uint8_t val;
  
        /* Only NV4x have two pvio ranges; other twoHeads cards MUST call
         * NVSetOwner for the relevant head to be programmed */
-       if (head && dev_priv->card_type == NV_40)
+       if (head && nv_device(drm->device)->card_type == NV_40)
                reg += NV_PRMVIO_SIZE;
  
-       val = nv_rd08(dev, reg);
-       NV_REG_DEBUG(RMVIO, dev, "head %d reg %08x val %02x\n", head, reg, val);
+       val = nv_rd08(device, reg);
        return val;
  }
  
  static inline void NVWritePRMVIO(struct drm_device *dev,
                                        int head, uint32_t reg, uint8_t value)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
        /* Only NV4x have two pvio ranges; other twoHeads cards MUST call
         * NVSetOwner for the relevant head to be programmed */
-       if (head && dev_priv->card_type == NV_40)
+       if (head && nv_device(drm->device)->card_type == NV_40)
                reg += NV_PRMVIO_SIZE;
  
-       NV_REG_DEBUG(RMVIO, dev, "head %d reg %08x val %02x\n",
-                                               head, reg, value);
-       nv_wr08(dev, reg, value);
+       nv_wr08(device, reg, value);
  }
  
  static inline void NVSetEnablePalette(struct drm_device *dev, int head, bool enable)
  {
-       nv_rd08(dev, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
-       nv_wr08(dev, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, enable ? 0 : 0x20);
+       struct nouveau_device *device = nouveau_dev(dev);
+       nv_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
+       nv_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, enable ? 0 : 0x20);
  }
  
  static inline bool NVGetEnablePalette(struct drm_device *dev, int head)
  {
-       nv_rd08(dev, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
-       return !(nv_rd08(dev, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE) & 0x20);
+       struct nouveau_device *device = nouveau_dev(dev);
+       nv_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
+       return !(nv_rd08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE) & 0x20);
  }
  
  static inline void NVWriteVgaAttr(struct drm_device *dev,
                                        int head, uint8_t index, uint8_t value)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        if (NVGetEnablePalette(dev, head))
                index &= ~0x20;
        else
                index |= 0x20;
  
-       nv_rd08(dev, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
-       NV_REG_DEBUG(VGAATTR, dev, "head %d index 0x%02x data 0x%02x\n",
-                                                       head, index, value);
-       nv_wr08(dev, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
-       nv_wr08(dev, NV_PRMCIO_AR__WRITE + head * NV_PRMCIO_SIZE, value);
+       nv_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
+       nv_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
+       nv_wr08(device, NV_PRMCIO_AR__WRITE + head * NV_PRMCIO_SIZE, value);
  }
  
  static inline uint8_t NVReadVgaAttr(struct drm_device *dev,
                                        int head, uint8_t index)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        uint8_t val;
        if (NVGetEnablePalette(dev, head))
                index &= ~0x20;
        else
                index |= 0x20;
  
-       nv_rd08(dev, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
-       nv_wr08(dev, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
-       val = nv_rd08(dev, NV_PRMCIO_AR__READ + head * NV_PRMCIO_SIZE);
-       NV_REG_DEBUG(VGAATTR, dev, "head %d index 0x%02x data 0x%02x\n",
-                                                       head, index, val);
+       nv_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
+       nv_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
+       val = nv_rd08(device, NV_PRMCIO_AR__READ + head * NV_PRMCIO_SIZE);
        return val;
  }
  
@@@ -325,10 -258,11 +258,11 @@@ static inline void NVVgaProtect(struct 
  static inline bool
  nv_heads_tied(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
-       if (dev_priv->chipset == 0x11)
-               return !!(nvReadMC(dev, NV_PBUS_DEBUG_1) & (1 << 28));
+       if (nv_device(drm->device)->chipset == 0x11)
+               return !!(nv_rd32(device, NV_PBUS_DEBUG_1) & (1 << 28));
  
        return NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44) & 0x4;
  }
@@@ -377,13 -311,13 +311,13 @@@ nv_lock_vga_crtc_shadow(struct drm_devi
  static inline bool
  NVLockVgaCrtcs(struct drm_device *dev, bool lock)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        bool waslocked = !NVReadVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX);
  
        NVWriteVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX,
                       lock ? NV_CIO_SR_LOCK_VALUE : NV_CIO_SR_UNLOCK_RW_VALUE);
        /* NV11 has independently lockable extended crtcs, except when tied */
-       if (dev_priv->chipset == 0x11 && !nv_heads_tied(dev))
+       if (nv_device(drm->device)->chipset == 0x11 && !nv_heads_tied(dev))
                NVWriteVgaCrtc(dev, 1, NV_CIO_SR_LOCK_INDEX,
                               lock ? NV_CIO_SR_LOCK_VALUE :
                                      NV_CIO_SR_UNLOCK_RW_VALUE);
  
  static inline int nv_cursor_width(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
-       return dev_priv->card_type >= NV_10 ? NV10_CURSOR_SIZE : NV04_CURSOR_SIZE;
+       return nv_device(drm->device)->card_type >= NV_10 ? NV10_CURSOR_SIZE : NV04_CURSOR_SIZE;
  }
  
  static inline void
@@@ -418,11 -352,11 +352,11 @@@ nv_fix_nv40_hw_cursor(struct drm_devic
  static inline void
  nv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
        NVWriteCRTC(dev, head, NV_PCRTC_START, offset);
  
-       if (dev_priv->card_type == NV_04) {
+       if (nv_device(drm->device)->card_type == NV_04) {
                /*
                 * Hilarious, the 24th bit doesn't want to stick to
                 * PCRTC_START...
  static inline void
  nv_show_cursor(struct drm_device *dev, int head, bool show)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        uint8_t *curctl1 =
-               &dev_priv->mode_reg.crtc_reg[head].CRTC[NV_CIO_CRE_HCUR_ADDR1_INDEX];
+               &nv04_display(dev)->mode_reg.crtc_reg[head].CRTC[NV_CIO_CRE_HCUR_ADDR1_INDEX];
  
        if (show)
                *curctl1 |= MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE);
                *curctl1 &= ~MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE);
        NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HCUR_ADDR1_INDEX, *curctl1);
  
-       if (dev_priv->card_type == NV_40)
+       if (nv_device(drm->device)->card_type == NV_40)
                nv_fix_nv40_hw_cursor(dev, head);
  }
  
  static inline uint32_t
  nv_pitch_align(struct drm_device *dev, uint32_t width, int bpp)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        int mask;
  
        if (bpp == 15)
                bpp = 8;
  
        /* Alignment requirements taken from the Haiku driver */
-       if (dev_priv->card_type == NV_04)
+       if (nv_device(drm->device)->card_type == NV_04)
                mask = 128 / bpp - 1;
        else
                mask = 512 / bpp - 1;
  
  #include <linux/compat.h>
  
 -#include "drmP.h"
 -#include "drm.h"
 +#include <drm/drmP.h>
  
- #include "nouveau_drv.h"
+ #include "nouveau_ioctl.h"
  
  /**
   * Called whenever a 32-bit process running under a 64-bit kernel
   * Authors: Ben Skeggs
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
  
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_reg.h"
  #include "nouveau_pm.h"
  
  static u8 *
  nouveau_perf_table(struct drm_device *dev, u8 *ver)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
        struct bit_entry P;
  
        if (!bit_table(dev, 'P', &P) && P.version && P.version <= 2) {
@@@ -87,7 -88,7 +88,7 @@@ u8 
  nouveau_perf_rammap(struct drm_device *dev, u32 freq,
                    u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct bit_entry P;
        u8 *perf, i = 0;
  
                return NULL;
        }
  
-       if (dev_priv->chipset == 0x49 ||
-           dev_priv->chipset == 0x4b)
+       if (nv_device(drm->device)->chipset == 0x49 ||
+           nv_device(drm->device)->chipset == 0x4b)
                freq /= 2;
  
        while ((perf = nouveau_perf_entry(dev, i++, ver, hdr, cnt, len))) {
  u8 *
  nouveau_perf_ramcfg(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
        u8 strap, hdr, cnt;
        u8 *rammap;
  
-       strap = (nv_rd32(dev, 0x101000) & 0x0000003c) >> 2;
+       strap = (nv_rd32(device, 0x101000) & 0x0000003c) >> 2;
        if (bios->ram_restrict_tbl_ptr)
                strap = bios->data[bios->ram_restrict_tbl_ptr + strap];
  
  u8 *
  nouveau_perf_timing(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
        struct bit_entry P;
        u8 *perf, *timing = NULL;
        u8 i = 0, hdr, cnt;
  static void
  legacy_perf_init(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nvbios *bios = &drm->vbios;
+       struct nouveau_pm *pm = nouveau_pm(dev);
        char *perf, *entry, *bmp = &bios->data[bios->offset];
        int headerlen, use_straps;
  
        if (bmp[5] < 0x5 || bmp[6] < 0x14) {
-               NV_DEBUG(dev, "BMP version too old for perf\n");
+               NV_DEBUG(drm, "BMP version too old for perf\n");
                return;
        }
  
        perf = ROMPTR(dev, bmp[0x73]);
        if (!perf) {
-               NV_DEBUG(dev, "No memclock table pointer found.\n");
+               NV_DEBUG(drm, "No memclock table pointer found.\n");
                return;
        }
  
                headerlen = (use_straps ? 8 : 2);
                break;
        default:
-               NV_WARN(dev, "Unknown memclock table version %x.\n", perf[0]);
+               NV_WARN(drm, "Unknown memclock table version %x.\n", perf[0]);
                return;
        }
  
        entry = perf + headerlen;
        if (use_straps)
-               entry += (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x3c) >> 1;
+               entry += (nv_rd32(device, NV_PEXTDEV_BOOT_0) & 0x3c) >> 1;
  
        sprintf(pm->perflvl[0].name, "performance_level_0");
        pm->perflvl[0].memory = ROM16(entry[0]) * 20;
  static void
  nouveau_perf_voltage(struct drm_device *dev, struct nouveau_pm_level *perflvl)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct bit_entry P;
        u8 *vmap;
        int id;
        /* boards using voltage table version <0x40 store the voltage
         * level directly in the perflvl entry as a multiple of 10mV
         */
-       if (dev_priv->engine.pm.voltage.version < 0x40) {
+       if (drm->pm->voltage.version < 0x40) {
                perflvl->volt_min = id * 10000;
                perflvl->volt_max = perflvl->volt_min;
                return;
         * vbios table containing a min/max voltage value for the perflvl
         */
        if (bit_table(dev, 'P', &P) || P.version != 2 || P.length < 34) {
-               NV_DEBUG(dev, "where's our volt map table ptr? %d %d\n",
+               NV_DEBUG(drm, "where's our volt map table ptr? %d %d\n",
                         P.version, P.length);
                return;
        }
  
        vmap = ROMPTR(dev, P.data[32]);
        if (!vmap) {
-               NV_DEBUG(dev, "volt map table pointer invalid\n");
+               NV_DEBUG(drm, "volt map table pointer invalid\n");
                return;
        }
  
  void
  nouveau_perf_init(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_pm *pm = nouveau_pm(dev);
+       struct nvbios *bios = &drm->vbios;
        u8 *perf, ver, hdr, cnt, len;
        int ret, vid, i = -1;
  
        }
  
        perf = nouveau_perf_table(dev, &ver);
-       if (ver >= 0x20 && ver < 0x40)
-               pm->fan.pwm_divisor = ROM16(perf[6]);
  
        while ((perf = nouveau_perf_entry(dev, ++i, &ver, &hdr, &cnt, &len))) {
                struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
                        perflvl->shader = ROM16(perf[6]) * 1000;
                        perflvl->core = perflvl->shader;
                        perflvl->core += (signed char)perf[8] * 1000;
-                       if (dev_priv->chipset == 0x49 ||
-                           dev_priv->chipset == 0x4b)
+                       if (nv_device(drm->device)->chipset == 0x49 ||
+                           nv_device(drm->device)->chipset == 0x4b)
                                perflvl->memory = ROM16(perf[11]) * 1000;
                        else
                                perflvl->memory = ROM16(perf[11]) * 2000;
  #define subent(n) ((ROM16(perf[hdr + (n) * len]) & 0xfff) * 1000)
                        perflvl->fanspeed = 0; /*XXX*/
                        perflvl->volt_min = perf[2];
-                       if (dev_priv->card_type == NV_50) {
+                       if (nv_device(drm->device)->card_type == NV_50) {
                                perflvl->core   = subent(0);
                                perflvl->shader = subent(1);
                                perflvl->memory = subent(2);
                if (pm->voltage.supported && perflvl->volt_min) {
                        vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min);
                        if (vid < 0) {
-                               NV_DEBUG(dev, "perflvl %d, bad vid\n", i);
+                               NV_DEBUG(drm, "perflvl %d, bad vid\n", i);
                                continue;
                        }
                }
                ret = nouveau_mem_timing_calc(dev, perflvl->memory,
                                                  &perflvl->timing);
                if (ret) {
-                       NV_DEBUG(dev, "perflvl %d, bad timing: %d\n", i, ret);
+                       NV_DEBUG(drm, "perflvl %d, bad timing: %d\n", i, ret);
                        continue;
                }
  
   * Authors: Ben Skeggs
   */
  
- #include <drm/drmP.h>
- #include "nouveau_drv.h"
- #include "nouveau_pm.h"
- #include "nouveau_gpio.h"
  #ifdef CONFIG_ACPI
  #include <linux/acpi.h>
  #endif
  #include <linux/hwmon.h>
  #include <linux/hwmon-sysfs.h>
  
- static int
- nouveau_pwmfan_get(struct drm_device *dev)
- {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
-       struct gpio_func gpio;
-       u32 divs, duty;
-       int ret;
 -#include "drmP.h"
++#include <drm/drmP.h>
  
-       if (!pm->pwm_get)
-               return -ENODEV;
+ #include "nouveau_drm.h"
+ #include "nouveau_pm.h"
  
-       ret = nouveau_gpio_find(dev, 0, DCB_GPIO_PWM_FAN, 0xff, &gpio);
-       if (ret == 0) {
-               ret = pm->pwm_get(dev, gpio.line, &divs, &duty);
-               if (ret == 0 && divs) {
-                       divs = max(divs, duty);
-                       if (dev_priv->card_type <= NV_40 || (gpio.log[0] & 1))
-                               duty = divs - duty;
-                       return (duty * 100) / divs;
-               }
+ #include <subdev/gpio.h>
+ #include <subdev/timer.h>
+ #include <subdev/therm.h>
  
-               return nouveau_gpio_func_get(dev, gpio.func) * 100;
-       }
+ MODULE_PARM_DESC(perflvl, "Performance level (default: boot)");
+ static char *nouveau_perflvl;
+ module_param_named(perflvl, nouveau_perflvl, charp, 0400);
  
-       return -ENODEV;
- }
- static int
- nouveau_pwmfan_set(struct drm_device *dev, int percent)
- {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
-       struct gpio_func gpio;
-       u32 divs, duty;
-       int ret;
-       if (!pm->pwm_set)
-               return -ENODEV;
-       ret = nouveau_gpio_find(dev, 0, DCB_GPIO_PWM_FAN, 0xff, &gpio);
-       if (ret == 0) {
-               divs = pm->fan.pwm_divisor;
-               if (pm->fan.pwm_freq) {
-                       /*XXX: PNVIO clock more than likely... */
-                       divs = 135000 / pm->fan.pwm_freq;
-                       if (dev_priv->chipset < 0xa3)
-                               divs /= 4;
-               }
-               duty = ((divs * percent) + 99) / 100;
-               if (dev_priv->card_type <= NV_40 || (gpio.log[0] & 1))
-                       duty = divs - duty;
-               ret = pm->pwm_set(dev, gpio.line, divs, duty);
-               if (!ret)
-                       pm->fan.percent = percent;
-               return ret;
-       }
-       return -ENODEV;
- }
+ MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)");
+ static int nouveau_perflvl_wr;
+ module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400);
  
  static int
  nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl,
                       struct nouveau_pm_level *a, struct nouveau_pm_level *b)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_pm *pm = nouveau_pm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm);
        int ret;
  
        /*XXX: not on all boards, we should control based on temperature
         *     on recent boards..  or maybe on some other factor we don't
         *     know about?
         */
-       if (a->fanspeed && b->fanspeed && b->fanspeed > a->fanspeed) {
-               ret = nouveau_pwmfan_set(dev, perflvl->fanspeed);
+       if (therm && therm->fan_set &&
+               a->fanspeed && b->fanspeed && b->fanspeed > a->fanspeed) {
+               ret = therm->fan_set(therm, perflvl->fanspeed);
                if (ret && ret != -ENODEV) {
-                       NV_ERROR(dev, "fanspeed set failed: %d\n", ret);
+                       NV_ERROR(drm, "fanspeed set failed: %d\n", ret);
                        return ret;
                }
        }
                if (perflvl->volt_min && b->volt_min > a->volt_min) {
                        ret = pm->voltage_set(dev, perflvl->volt_min);
                        if (ret) {
-                               NV_ERROR(dev, "voltage set failed: %d\n", ret);
+                               NV_ERROR(drm, "voltage set failed: %d\n", ret);
                                return ret;
                        }
                }
  static int
  nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm *pm = nouveau_pm(dev);
        void *state;
        int ret;
  
@@@ -171,8 -120,9 +120,9 @@@ error
  void
  nouveau_pm_trigger(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_timer *ptimer = nouveau_timer(drm->device);
+       struct nouveau_pm *pm = nouveau_pm(dev);
        struct nouveau_pm_profile *profile = NULL;
        struct nouveau_pm_level *perflvl = NULL;
        int ret;
  
        /* change perflvl, if necessary */
        if (perflvl != pm->cur) {
-               struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
-               u64 time0 = ptimer->read(dev);
+               u64 time0 = ptimer->read(ptimer);
  
-               NV_INFO(dev, "setting performance level: %d", perflvl->id);
+               NV_INFO(drm, "setting performance level: %d", perflvl->id);
                ret = nouveau_pm_perflvl_set(dev, perflvl);
                if (ret)
-                       NV_INFO(dev, "> reclocking failed: %d\n\n", ret);
+                       NV_INFO(drm, "> reclocking failed: %d\n\n", ret);
  
-               NV_INFO(dev, "> reclocking took %lluns\n\n",
-                            ptimer->read(dev) - time0);
+               NV_INFO(drm, "> reclocking took %lluns\n\n",
+                            ptimer->read(ptimer) - time0);
        }
  }
  
  static struct nouveau_pm_profile *
  profile_find(struct drm_device *dev, const char *string)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm *pm = nouveau_pm(dev);
        struct nouveau_pm_profile *profile;
  
        list_for_each_entry(profile, &pm->profiles, head) {
  static int
  nouveau_pm_profile_set(struct drm_device *dev, const char *profile)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm *pm = nouveau_pm(dev);
        struct nouveau_pm_profile *ac = NULL, *dc = NULL;
        char string[16], *cur = string, *ptr;
  
@@@ -279,8 -226,9 +226,9 @@@ const struct nouveau_pm_profile_func no
  static int
  nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_pm *pm = nouveau_pm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
        int ret;
  
        memset(perflvl, 0, sizeof(*perflvl));
                }
        }
  
-       ret = nouveau_pwmfan_get(dev);
-       if (ret > 0)
-               perflvl->fanspeed = ret;
+       if (therm && therm->fan_get) {
+               ret = therm->fan_get(therm);
+               if (ret >= 0)
+                       perflvl->fanspeed = ret;
+       }
  
        nouveau_mem_timing_read(dev, &perflvl->timing);
        return 0;
@@@ -362,8 -312,7 +312,7 @@@ static ssize_
  nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf)
  {
        struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm *pm = nouveau_pm(dev);
        struct nouveau_pm_level cur;
        int len = PAGE_SIZE, ret;
        char *ptr = buf;
@@@ -398,8 -347,8 +347,8 @@@ static DEVICE_ATTR(performance_level, S
  static int
  nouveau_sysfs_init(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_pm *pm = nouveau_pm(dev);
        struct device *d = &dev->pdev->dev;
        int ret, i;
  
  
                ret = device_create_file(d, &perflvl->dev_attr);
                if (ret) {
-                       NV_ERROR(dev, "failed pervlvl %d sysfs: %d\n",
+                       NV_ERROR(drm, "failed pervlvl %d sysfs: %d\n",
                                 perflvl->id, i);
                        perflvl->dev_attr.attr.name = NULL;
                        nouveau_pm_fini(dev);
  static void
  nouveau_sysfs_fini(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm *pm = nouveau_pm(dev);
        struct device *d = &dev->pdev->dev;
        int i;
  
@@@ -453,10 -401,10 +401,10 @@@ static ssize_
  nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
  {
        struct drm_device *dev = dev_get_drvdata(d);
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
  
-       return snprintf(buf, PAGE_SIZE, "%d\n", pm->temp_get(dev)*1000);
+       return snprintf(buf, PAGE_SIZE, "%d\n", therm->temp_get(therm) * 1000);
  }
  static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp,
                                                  NULL, 0);
@@@ -465,28 -413,25 +413,25 @@@ static ssize_
  nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf)
  {
        struct drm_device *dev = dev_get_drvdata(d);
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
-       struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
  
-       return snprintf(buf, PAGE_SIZE, "%d\n", temp->down_clock*1000);
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+              therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK) * 1000);
  }
  static ssize_t
  nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
                                                const char *buf, size_t count)
  {
        struct drm_device *dev = dev_get_drvdata(d);
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
-       struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
        long value;
  
        if (kstrtol(buf, 10, &value) == -EINVAL)
                return count;
  
-       temp->down_clock = value/1000;
-       nouveau_temp_safety_checks(dev);
+       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK, value / 1000);
  
        return count;
  }
@@@ -499,11 -444,11 +444,11 @@@ nouveau_hwmon_critical_temp(struct devi
                                                        char *buf)
  {
        struct drm_device *dev = dev_get_drvdata(d);
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
-       struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
  
-       return snprintf(buf, PAGE_SIZE, "%d\n", temp->critical*1000);
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+              therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL) * 1000);
  }
  static ssize_t
  nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
                                                                size_t count)
  {
        struct drm_device *dev = dev_get_drvdata(d);
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
-       struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
        long value;
  
        if (kstrtol(buf, 10, &value) == -EINVAL)
                return count;
  
-       temp->critical = value/1000;
-       nouveau_temp_safety_checks(dev);
+       therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL, value / 1000);
  
        return count;
  }
@@@ -553,47 -495,62 +495,62 @@@ nouveau_hwmon_show_fan0_input(struct de
                              char *buf)
  {
        struct drm_device *dev = dev_get_drvdata(d);
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
-       struct gpio_func gpio;
-       u32 cycles, cur, prev;
-       u64 start;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       return snprintf(buf, PAGE_SIZE, "%d\n", therm->fan_sense(therm));
+ }
+ static SENSOR_DEVICE_ATTR(fan0_input, S_IRUGO, nouveau_hwmon_show_fan0_input,
+                         NULL, 0);
+  static ssize_t
+ nouveau_hwmon_get_pwm1_enable(struct device *d,
+                          struct device_attribute *a, char *buf)
+ {
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
        int ret;
  
-       ret = nouveau_gpio_find(dev, 0, DCB_GPIO_FAN_SENSE, 0xff, &gpio);
-       if (ret)
+       ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MODE);
+       if (ret < 0)
                return ret;
  
-       /* Monitor the GPIO input 0x3b for 250ms.
-        * When the fan spins, it changes the value of GPIO FAN_SENSE.
-        * We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation.
-        */
-       start = ptimer->read(dev);
-       prev = nouveau_gpio_sense(dev, 0, gpio.line);
-       cycles = 0;
-       do {
-               cur = nouveau_gpio_sense(dev, 0, gpio.line);
-               if (prev != cur) {
-                       cycles++;
-                       prev = cur;
-               }
+       return sprintf(buf, "%i\n", ret);
+ }
  
-               usleep_range(500, 1000); /* supports 0 < rpm < 7500 */
-       } while (ptimer->read(dev) - start < 250000000);
+ static ssize_t
+ nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a,
+                          const char *buf, size_t count)
+ {
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       long value;
+       int ret;
+       if (strict_strtol(buf, 10, &value) == -EINVAL)
+               return -EINVAL;
  
-       /* interpolate to get rpm */
-       return sprintf(buf, "%i\n", cycles / 4 * 4 * 60);
+       ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MODE, value);
+       if (ret)
+               return ret;
+       else
+               return count;
  }
- static SENSOR_DEVICE_ATTR(fan0_input, S_IRUGO, nouveau_hwmon_show_fan0_input,
-                         NULL, 0);
+ static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+                         nouveau_hwmon_get_pwm1_enable,
+                         nouveau_hwmon_set_pwm1_enable, 0);
  
  static ssize_t
- nouveau_hwmon_get_pwm0(struct device *d, struct device_attribute *a, char *buf)
+ nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf)
  {
        struct drm_device *dev = dev_get_drvdata(d);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
        int ret;
  
-       ret = nouveau_pwmfan_get(dev);
+       ret = therm->fan_get(therm);
        if (ret < 0)
                return ret;
  
  }
  
  static ssize_t
- nouveau_hwmon_set_pwm0(struct device *d, struct device_attribute *a,
+ nouveau_hwmon_set_pwm1(struct device *d, struct device_attribute *a,
                       const char *buf, size_t count)
  {
        struct drm_device *dev = dev_get_drvdata(d);
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
        int ret = -ENODEV;
        long value;
  
        if (kstrtol(buf, 10, &value) == -EINVAL)
                return -EINVAL;
  
-       if (value < pm->fan.min_duty)
-               value = pm->fan.min_duty;
-       if (value > pm->fan.max_duty)
-               value = pm->fan.max_duty;
-       ret = nouveau_pwmfan_set(dev, value);
+       ret = therm->fan_set(therm, value);
        if (ret)
                return ret;
  
        return count;
  }
  
- static SENSOR_DEVICE_ATTR(pwm0, S_IRUGO | S_IWUSR,
-                         nouveau_hwmon_get_pwm0,
-                         nouveau_hwmon_set_pwm0, 0);
+ static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR,
+                         nouveau_hwmon_get_pwm1,
+                         nouveau_hwmon_set_pwm1, 0);
  
  static ssize_t
- nouveau_hwmon_get_pwm0_min(struct device *d,
+ nouveau_hwmon_get_pwm1_min(struct device *d,
                           struct device_attribute *a, char *buf)
  {
        struct drm_device *dev = dev_get_drvdata(d);
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       int ret;
+       ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY);
+       if (ret < 0)
+               return ret;
  
-       return sprintf(buf, "%i\n", pm->fan.min_duty);
+       return sprintf(buf, "%i\n", ret);
  }
  
  static ssize_t
- nouveau_hwmon_set_pwm0_min(struct device *d, struct device_attribute *a,
+ nouveau_hwmon_set_pwm1_min(struct device *d, struct device_attribute *a,
                           const char *buf, size_t count)
  {
        struct drm_device *dev = dev_get_drvdata(d);
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
        long value;
+       int ret;
  
        if (kstrtol(buf, 10, &value) == -EINVAL)
                return -EINVAL;
  
-       if (value < 0)
-               value = 0;
-       if (pm->fan.max_duty - value < 10)
-               value = pm->fan.max_duty - 10;
-       if (value < 10)
-               pm->fan.min_duty = 10;
-       else
-               pm->fan.min_duty = value;
+       ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY, value);
+       if (ret < 0)
+               return ret;
  
        return count;
  }
  
- static SENSOR_DEVICE_ATTR(pwm0_min, S_IRUGO | S_IWUSR,
-                         nouveau_hwmon_get_pwm0_min,
-                         nouveau_hwmon_set_pwm0_min, 0);
+ static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO | S_IWUSR,
+                         nouveau_hwmon_get_pwm1_min,
+                         nouveau_hwmon_set_pwm1_min, 0);
  
  static ssize_t
- nouveau_hwmon_get_pwm0_max(struct device *d,
+ nouveau_hwmon_get_pwm1_max(struct device *d,
                           struct device_attribute *a, char *buf)
  {
        struct drm_device *dev = dev_get_drvdata(d);
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
+       int ret;
+       ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY);
+       if (ret < 0)
+               return ret;
  
-       return sprintf(buf, "%i\n", pm->fan.max_duty);
+       return sprintf(buf, "%i\n", ret);
  }
  
  static ssize_t
- nouveau_hwmon_set_pwm0_max(struct device *d, struct device_attribute *a,
+ nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a,
                           const char *buf, size_t count)
  {
        struct drm_device *dev = dev_get_drvdata(d);
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
        long value;
+       int ret;
  
        if (kstrtol(buf, 10, &value) == -EINVAL)
                return -EINVAL;
  
-       if (value < 0)
-               value = 0;
-       if (value - pm->fan.min_duty < 10)
-               value = pm->fan.min_duty + 10;
-       if (value > 100)
-               pm->fan.max_duty = 100;
-       else
-               pm->fan.max_duty = value;
+       ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY, value);
+       if (ret < 0)
+               return ret;
  
        return count;
  }
  
- static SENSOR_DEVICE_ATTR(pwm0_max, S_IRUGO | S_IWUSR,
-                         nouveau_hwmon_get_pwm0_max,
-                         nouveau_hwmon_set_pwm0_max, 0);
+ static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR,
+                         nouveau_hwmon_get_pwm1_max,
+                         nouveau_hwmon_set_pwm1_max, 0);
  
  static struct attribute *hwmon_attributes[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
@@@ -727,9 -677,10 +677,10 @@@ static struct attribute *hwmon_fan_rpm_
        NULL
  };
  static struct attribute *hwmon_pwm_fan_attributes[] = {
-       &sensor_dev_attr_pwm0.dev_attr.attr,
-       &sensor_dev_attr_pwm0_min.dev_attr.attr,
-       &sensor_dev_attr_pwm0_max.dev_attr.attr,
+       &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm1.dev_attr.attr,
+       &sensor_dev_attr_pwm1_min.dev_attr.attr,
+       &sensor_dev_attr_pwm1_max.dev_attr.attr,
        NULL
  };
  
@@@ -747,20 -698,22 +698,22 @@@ static const struct attribute_group hwm
  static int
  nouveau_hwmon_init(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm *pm = nouveau_pm(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
  #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
        struct device *hwmon_dev;
        int ret = 0;
  
-       if (!pm->temp_get)
+       if (!therm || !therm->temp_get || !therm->attr_get ||
+               !therm->attr_set || therm->temp_get(therm) < 0)
                return -ENODEV;
  
        hwmon_dev = hwmon_device_register(&dev->pdev->dev);
        if (IS_ERR(hwmon_dev)) {
                ret = PTR_ERR(hwmon_dev);
-               NV_ERROR(dev,
-                       "Unable to register hwmon device: %d\n", ret);
+               NV_ERROR(drm, "Unable to register hwmon device: %d\n", ret);
                return ret;
        }
        dev_set_drvdata(hwmon_dev, dev);
        /*XXX: incorrect, need better detection for this, some boards have
         *     the gpio entries for pwm fan control even when there's no
         *     actual fan connected to it... therm table? */
-       if (nouveau_pwmfan_get(dev) >= 0) {
+       if (therm->fan_get && therm->fan_get(therm) >= 0) {
                ret = sysfs_create_group(&dev->pdev->dev.kobj,
                                         &hwmon_pwm_fan_attrgroup);
                if (ret)
        }
  
        /* if the card can read the fan rpm */
-       if (nouveau_gpio_func_valid(dev, DCB_GPIO_FAN_SENSE)) {
+       if (therm->fan_sense(therm) >= 0) {
                ret = sysfs_create_group(&dev->pdev->dev.kobj,
                                         &hwmon_fan_rpm_attrgroup);
                if (ret)
        return 0;
  
  error:
-       NV_ERROR(dev, "Unable to create some hwmon sysfs files: %d\n", ret);
+       NV_ERROR(drm, "Unable to create some hwmon sysfs files: %d\n", ret);
        hwmon_device_unregister(hwmon_dev);
        pm->hwmon = NULL;
        return ret;
@@@ -810,8 -763,7 +763,7 @@@ static voi
  nouveau_hwmon_fini(struct drm_device *dev)
  {
  #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm *pm = nouveau_pm(dev);
  
        if (pm->hwmon) {
                sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_attrgroup);
  static int
  nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data)
  {
-       struct drm_nouveau_private *dev_priv =
-               container_of(nb, struct drm_nouveau_private, engine.pm.acpi_nb);
-       struct drm_device *dev = dev_priv->dev;
+       struct nouveau_pm *pm = container_of(nb, struct nouveau_pm, acpi_nb);
+       struct nouveau_drm *drm = nouveau_drm(pm->dev);
        struct acpi_bus_event *entry = (struct acpi_bus_event *)data;
  
        if (strcmp(entry->device_class, "ac_adapter") == 0) {
                bool ac = power_supply_is_system_supplied();
  
-               NV_DEBUG(dev, "power supply changed: %s\n", ac ? "AC" : "DC");
-               nouveau_pm_trigger(dev);
+               NV_DEBUG(drm, "power supply changed: %s\n", ac ? "AC" : "DC");
+               nouveau_pm_trigger(pm->dev);
        }
  
        return NOTIFY_OK;
  int
  nouveau_pm_init(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_pm *pm;
        char info[256];
        int ret, i;
  
+       pm = drm->pm = kzalloc(sizeof(*pm), GFP_KERNEL);
+       if (!pm)
+               return -ENOMEM;
+       pm->dev = dev;
+       if (device->card_type < NV_40) {
+               pm->clocks_get = nv04_pm_clocks_get;
+               pm->clocks_pre = nv04_pm_clocks_pre;
+               pm->clocks_set = nv04_pm_clocks_set;
+               if (nouveau_gpio(drm->device)) {
+                       pm->voltage_get = nouveau_voltage_gpio_get;
+                       pm->voltage_set = nouveau_voltage_gpio_set;
+               }
+       } else
+       if (device->card_type < NV_50) {
+               pm->clocks_get = nv40_pm_clocks_get;
+               pm->clocks_pre = nv40_pm_clocks_pre;
+               pm->clocks_set = nv40_pm_clocks_set;
+               pm->voltage_get = nouveau_voltage_gpio_get;
+               pm->voltage_set = nouveau_voltage_gpio_set;
+       } else
+       if (device->card_type < NV_C0) {
+               if (device->chipset <  0xa3 ||
+                   device->chipset == 0xaa ||
+                   device->chipset == 0xac) {
+                       pm->clocks_get = nv50_pm_clocks_get;
+                       pm->clocks_pre = nv50_pm_clocks_pre;
+                       pm->clocks_set = nv50_pm_clocks_set;
+               } else {
+                       pm->clocks_get = nva3_pm_clocks_get;
+                       pm->clocks_pre = nva3_pm_clocks_pre;
+                       pm->clocks_set = nva3_pm_clocks_set;
+               }
+               pm->voltage_get = nouveau_voltage_gpio_get;
+               pm->voltage_set = nouveau_voltage_gpio_set;
+       } else
+       if (device->card_type < NV_E0) {
+               pm->clocks_get = nvc0_pm_clocks_get;
+               pm->clocks_pre = nvc0_pm_clocks_pre;
+               pm->clocks_set = nvc0_pm_clocks_set;
+               pm->voltage_get = nouveau_voltage_gpio_get;
+               pm->voltage_set = nouveau_voltage_gpio_set;
+       }
        /* parse aux tables from vbios */
        nouveau_volt_init(dev);
-       nouveau_temp_init(dev);
+       INIT_LIST_HEAD(&pm->profiles);
  
        /* determine current ("boot") performance level */
        ret = nouveau_pm_perflvl_get(dev, &pm->boot);
        if (ret) {
-               NV_ERROR(dev, "failed to determine boot perflvl\n");
+               NV_ERROR(drm, "failed to determine boot perflvl\n");
                return ret;
        }
  
        strncpy(pm->boot.profile.name, "boot", 4);
        pm->boot.profile.func = &nouveau_pm_static_profile_func;
  
-       INIT_LIST_HEAD(&pm->profiles);
        list_add(&pm->boot.profile.head, &pm->profiles);
  
        pm->profile_ac = &pm->boot.profile;
        nouveau_perf_init(dev);
  
        /* display available performance levels */
-       NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
+       NV_INFO(drm, "%d available performance level(s)\n", pm->nr_perflvl);
        for (i = 0; i < pm->nr_perflvl; i++) {
                nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info));
-               NV_INFO(dev, "%d:%s", pm->perflvl[i].id, info);
+               NV_INFO(drm, "%d:%s", pm->perflvl[i].id, info);
        }
  
        nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
-       NV_INFO(dev, "c:%s", info);
+       NV_INFO(drm, "c:%s", info);
  
        /* switch performance levels now if requested */
        if (nouveau_perflvl != NULL)
                nouveau_pm_profile_set(dev, nouveau_perflvl);
  
-       /* determine the current fan speed */
-       pm->fan.percent = nouveau_pwmfan_get(dev);
        nouveau_sysfs_init(dev);
        nouveau_hwmon_init(dev);
  #if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
  void
  nouveau_pm_fini(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm *pm = nouveau_pm(dev);
        struct nouveau_pm_profile *profile, *tmp;
  
        list_for_each_entry_safe(profile, tmp, &pm->profiles, head) {
        if (pm->cur != &pm->boot)
                nouveau_pm_perflvl_set(dev, &pm->boot);
  
-       nouveau_temp_fini(dev);
        nouveau_perf_fini(dev);
        nouveau_volt_fini(dev);
  
  #endif
        nouveau_hwmon_fini(dev);
        nouveau_sysfs_fini(dev);
+       nouveau_drm(dev)->pm = NULL;
+       kfree(pm);
  }
  
  void
  nouveau_pm_resume(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm *pm = nouveau_pm(dev);
        struct nouveau_pm_level *perflvl;
  
        if (!pm->cur || pm->cur == &pm->boot)
        perflvl = pm->cur;
        pm->cur = &pm->boot;
        nouveau_pm_perflvl_set(dev, perflvl);
-       nouveau_pwmfan_set(dev, pm->fan.percent);
  }
   * Authors: Dave Airlie
   */
  
- #include <drm/drmP.h>
+ #include <linux/dma-buf.h>
  
- #include "nouveau_drv.h"
- #include <drm/nouveau_drm.h>
- #include "nouveau_dma.h"
 -#include "drmP.h"
 -#include "drm.h"
++#include <drm/drmP.h>
  
- #include <linux/dma-buf.h>
+ #include "nouveau_drm.h"
+ #include "nouveau_gem.h"
  
  static struct sg_table *nouveau_gem_map_dma_buf(struct dma_buf_attachment *attachment,
                                          enum dma_data_direction dir)
index 0000000,7bf7d13..6f0ac64
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,99 +1,99 @@@
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
+ #include <linux/vgaarb.h>
+ #include <linux/vga_switcheroo.h>
++#include <drm/drmP.h>
++#include <drm/drm_crtc_helper.h>
+ #include "nouveau_drm.h"
+ #include "nouveau_acpi.h"
+ #include "nouveau_fbcon.h"
+ #include "nouveau_vga.h"
+ static unsigned int
+ nouveau_vga_set_decode(void *priv, bool state)
+ {
+       struct nouveau_device *device = nouveau_dev(priv);
+       if (device->chipset >= 0x40)
+               nv_wr32(device, 0x088054, state);
+       else
+               nv_wr32(device, 0x001854, 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 void
+ nouveau_switcheroo_set_state(struct pci_dev *pdev,
+                            enum vga_switcheroo_state state)
+ {
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
+       if (state == VGA_SWITCHEROO_ON) {
+               printk(KERN_ERR "VGA switcheroo: switched nouveau on\n");
+               dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
+               nouveau_drm_resume(pdev);
+               drm_kms_helper_poll_enable(dev);
+               dev->switch_power_state = DRM_SWITCH_POWER_ON;
+       } else {
+               printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");
+               dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
+               drm_kms_helper_poll_disable(dev);
+               nouveau_switcheroo_optimus_dsm();
+               nouveau_drm_suspend(pdev, pmm);
+               dev->switch_power_state = DRM_SWITCH_POWER_OFF;
+       }
+ }
+ static void
+ nouveau_switcheroo_reprobe(struct pci_dev *pdev)
+ {
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       nouveau_fbcon_output_poll_changed(dev);
+ }
+ static bool
+ nouveau_switcheroo_can_switch(struct pci_dev *pdev)
+ {
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       bool can_switch;
+       spin_lock(&dev->count_lock);
+       can_switch = (dev->open_count == 0);
+       spin_unlock(&dev->count_lock);
+       return can_switch;
+ }
+ static const struct vga_switcheroo_client_ops
+ nouveau_switcheroo_ops = {
+       .set_gpu_state = nouveau_switcheroo_set_state,
+       .reprobe = nouveau_switcheroo_reprobe,
+       .can_switch = nouveau_switcheroo_can_switch,
+ };
+ void
+ nouveau_vga_init(struct nouveau_drm *drm)
+ {
+       struct drm_device *dev = drm->dev;
+       vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
+       vga_switcheroo_register_client(dev->pdev, &nouveau_switcheroo_ops);
+ }
+ void
+ nouveau_vga_fini(struct nouveau_drm *drm)
+ {
+       struct drm_device *dev = drm->dev;
+       vga_switcheroo_unregister_client(dev->pdev);
+       vga_client_register(dev->pdev, NULL, NULL, NULL);
+ }
+ void
+ nouveau_vga_lastclose(struct drm_device *dev)
+ {
+       vga_switcheroo_process_delayed_switch();
+ }
   * Authors: Ben Skeggs
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
  
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
  #include "nouveau_pm.h"
- #include "nouveau_gpio.h"
  
- static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 };
+ #include <subdev/bios/gpio.h>
+ #include <subdev/gpio.h>
+ static const enum dcb_gpio_func_name vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 };
  static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]);
  
  int
  nouveau_voltage_gpio_get(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+       struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_gpio *gpio = nouveau_gpio(device);
        u8 vid = 0;
        int i;
  
@@@ -43,7 -46,7 +46,7 @@@
                if (!(volt->vid_mask & (1 << i)))
                        continue;
  
-               vid |= nouveau_gpio_func_get(dev, vidtag[i]) << i;
+               vid |= gpio->get(gpio, 0, vidtag[i], 0xff) << i;
        }
  
        return nouveau_volt_lvl_lookup(dev, vid);
@@@ -52,8 -55,9 +55,9 @@@
  int
  nouveau_voltage_gpio_set(struct drm_device *dev, int voltage)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_gpio *gpio = nouveau_gpio(device);
+       struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage;
        int vid, i;
  
        vid = nouveau_volt_vid_lookup(dev, voltage);
@@@ -64,7 -68,7 +68,7 @@@
                if (!(volt->vid_mask & (1 << i)))
                        continue;
  
-               nouveau_gpio_func_set(dev, vidtag[i], !!(vid & (1 << i)));
+               gpio->set(gpio, 0, vidtag[i], 0xff, !!(vid & (1 << i)));
        }
  
        return 0;
@@@ -73,8 -77,7 +77,7 @@@
  int
  nouveau_volt_vid_lookup(struct drm_device *dev, int voltage)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+       struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage;
        int i;
  
        for (i = 0; i < volt->nr_level; i++) {
@@@ -88,8 -91,7 +91,7 @@@
  int
  nouveau_volt_lvl_lookup(struct drm_device *dev, int vid)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+       struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage;
        int i;
  
        for (i = 0; i < volt->nr_level; i++) {
  void
  nouveau_volt_init(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
+       struct nouveau_pm *pm = nouveau_pm(dev);
        struct nouveau_pm_voltage *voltage = &pm->voltage;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nvbios *bios = &drm->vbios;
+       struct dcb_gpio_func func;
        struct bit_entry P;
        u8 *volt = NULL, *entry;
        int i, headerlen, recordlen, entries, vidmask, vidshift;
                if (P.version == 2)
                        volt = ROMPTR(dev, P.data[12]);
                else {
-                       NV_WARN(dev, "unknown volt for BIT P %d\n", P.version);
+                       NV_WARN(drm, "unknown volt for BIT P %d\n", P.version);
                }
        } else {
                if (bios->data[bios->offset + 6] < 0x27) {
-                       NV_DEBUG(dev, "BMP version too old for voltage\n");
+                       NV_DEBUG(drm, "BMP version too old for voltage\n");
                        return;
                }
  
        }
  
        if (!volt) {
-               NV_DEBUG(dev, "voltage table pointer invalid\n");
+               NV_DEBUG(drm, "voltage table pointer invalid\n");
                return;
        }
  
                vidshift  = 0;
                break;
        default:
-               NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]);
+               NV_WARN(drm, "voltage table 0x%02x unknown\n", volt[0]);
                return;
        }
  
        i = 0;
        while (vidmask) {
                if (i > nr_vidtag) {
-                       NV_DEBUG(dev, "vid bit %d unknown\n", i);
+                       NV_DEBUG(drm, "vid bit %d unknown\n", i);
                        return;
                }
  
-               if (!nouveau_gpio_func_valid(dev, vidtag[i])) {
-                       NV_DEBUG(dev, "vid bit %d has no gpio tag\n", i);
+               if (gpio && gpio->find(gpio, 0, vidtag[i], 0xff, &func)) {
+                       NV_DEBUG(drm, "vid bit %d has no gpio tag\n", i);
                        return;
                }
  
  void
  nouveau_volt_fini(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+       struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage;
  
        kfree(volt->level);
  }
   * DEALINGS IN THE SOFTWARE.
   */
  
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
  
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_reg.h"
+ #include "nouveau_bo.h"
+ #include "nouveau_gem.h"
  #include "nouveau_encoder.h"
  #include "nouveau_connector.h"
  #include "nouveau_crtc.h"
- #include "nouveau_fb.h"
  #include "nouveau_hw.h"
  #include "nvreg.h"
  #include "nouveau_fbcon.h"
+ #include "nv04_display.h"
+ #include <subdev/bios/pll.h>
+ #include <subdev/clock.h>
  
  static int
  nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
@@@ -49,8 -55,8 +55,8 @@@ crtc_wr_cio_state(struct drm_crtc *crtc
  static void nv_crtc_set_digital_vibrance(struct drm_crtc *crtc, int level)
  {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-       struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
-       struct nv04_crtc_reg *regp = &dev_priv->mode_reg.crtc_reg[nv_crtc->index];
+       struct drm_device *dev = crtc->dev;
+       struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index];
  
        regp->CRTC[NV_CIO_CRE_CSB] = nv_crtc->saturation = level;
        if (nv_crtc->saturation && nv_gf4_disp_arch(crtc->dev)) {
@@@ -64,8 -70,8 +70,8 @@@
  static void nv_crtc_set_image_sharpening(struct drm_crtc *crtc, int level)
  {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-       struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
-       struct nv04_crtc_reg *regp = &dev_priv->mode_reg.crtc_reg[nv_crtc->index];
+       struct drm_device *dev = crtc->dev;
+       struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index];
  
        nv_crtc->sharpness = level;
        if (level < 0)  /* blur is in hw range 0x3f -> 0x20 */
  static void nv_crtc_calc_state_ext(struct drm_crtc *crtc, struct drm_display_mode * mode, int dot_clock)
  {
        struct drm_device *dev = crtc->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_bios *bios = nouveau_bios(drm->device);
+       struct nouveau_clock *clk = nouveau_clock(drm->device);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-       struct nv04_mode_state *state = &dev_priv->mode_reg;
+       struct nv04_mode_state *state = &nv04_display(dev)->mode_reg;
        struct nv04_crtc_reg *regp = &state->crtc_reg[nv_crtc->index];
        struct nouveau_pll_vals *pv = &regp->pllvals;
-       struct pll_lims pll_lim;
+       struct nvbios_pll pll_lim;
  
-       if (get_pll_limits(dev, nv_crtc->index ? PLL_VPLL1 : PLL_VPLL0, &pll_lim))
+       if (nvbios_pll_parse(bios, nv_crtc->index ? PLL_VPLL1 : PLL_VPLL0,
+                           &pll_lim))
                return;
  
        /* NM2 == 0 is used to determine single stage mode on two stage plls */
         * has yet been observed in allowing the use a single stage pll on all
         * nv43 however.  the behaviour of single stage use is untested on nv40
         */
-       if (dev_priv->chipset > 0x40 && dot_clock <= (pll_lim.vco1.maxfreq / 2))
+       if (nv_device(drm->device)->chipset > 0x40 && dot_clock <= (pll_lim.vco1.max_freq / 2))
                memset(&pll_lim.vco2, 0, sizeof(pll_lim.vco2));
  
-       if (!nouveau_calc_pll_mnp(dev, &pll_lim, dot_clock, pv))
+       if (!clk->pll_calc(clk, &pll_lim, dot_clock, pv))
                return;
  
        state->pllsel &= PLLSEL_VPLL1_MASK | PLLSEL_VPLL2_MASK | PLLSEL_TV_MASK;
  
        /* The blob uses this always, so let's do the same */
-       if (dev_priv->card_type == NV_40)
+       if (nv_device(drm->device)->card_type == NV_40)
                state->pllsel |= NV_PRAMDAC_PLL_COEFF_SELECT_USE_VPLL2_TRUE;
        /* again nv40 and some nv43 act more like nv3x as described above */
-       if (dev_priv->chipset < 0x41)
+       if (nv_device(drm->device)->chipset < 0x41)
                state->pllsel |= NV_PRAMDAC_PLL_COEFF_SELECT_SOURCE_PROG_MPLL |
                                 NV_PRAMDAC_PLL_COEFF_SELECT_SOURCE_PROG_NVPLL;
        state->pllsel |= nv_crtc->index ? PLLSEL_VPLL2_MASK : PLLSEL_VPLL1_MASK;
  
        if (pv->NM2)
-               NV_DEBUG_KMS(dev, "vpll: n1 %d n2 %d m1 %d m2 %d log2p %d\n",
+               NV_DEBUG(drm, "vpll: n1 %d n2 %d m1 %d m2 %d log2p %d\n",
                         pv->N1, pv->N2, pv->M1, pv->M2, pv->log2P);
        else
-               NV_DEBUG_KMS(dev, "vpll: n %d m %d log2p %d\n",
+               NV_DEBUG(drm, "vpll: n %d m %d log2p %d\n",
                         pv->N1, pv->M1, pv->log2P);
  
        nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.offset);
@@@ -158,10 -168,11 +168,11 @@@ nv_crtc_dpms(struct drm_crtc *crtc, in
  {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct drm_device *dev = crtc->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        unsigned char seq1 = 0, crtc17 = 0;
        unsigned char crtc1A;
  
-       NV_DEBUG_KMS(dev, "Setting dpms mode %d on CRTC %d\n", mode,
+       NV_DEBUG(drm, "Setting dpms mode %d on CRTC %d\n", mode,
                                                        nv_crtc->index);
  
        if (nv_crtc->last_dpms == mode) /* Don't do unnecessary mode changes. */
@@@ -225,9 -236,8 +236,8 @@@ static voi
  nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode)
  {
        struct drm_device *dev = crtc->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-       struct nv04_crtc_reg *regp = &dev_priv->mode_reg.crtc_reg[nv_crtc->index];
+       struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index];
        struct drm_framebuffer *fb = crtc->fb;
  
        /* Calculate our timings */
                struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
  
                if (encoder->crtc == crtc &&
-                   (nv_encoder->dcb->type == OUTPUT_LVDS ||
-                    nv_encoder->dcb->type == OUTPUT_TMDS))
+                   (nv_encoder->dcb->type == DCB_OUTPUT_LVDS ||
+                    nv_encoder->dcb->type == DCB_OUTPUT_TMDS))
                        fp_output = true;
        }
  
                horizEnd = horizTotal - 2;
                horizBlankEnd = horizTotal + 4;
  #if 0
-               if (dev->overlayAdaptor && dev_priv->card_type >= NV_10)
+               if (dev->overlayAdaptor && nv_device(drm->device)->card_type >= NV_10)
                        /* This reportedly works around some video overlay bandwidth problems */
                        horizTotal += 2;
  #endif
@@@ -452,10 -462,10 +462,10 @@@ static voi
  nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
  {
        struct drm_device *dev = crtc->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-       struct nv04_crtc_reg *regp = &dev_priv->mode_reg.crtc_reg[nv_crtc->index];
-       struct nv04_crtc_reg *savep = &dev_priv->saved_reg.crtc_reg[nv_crtc->index];
+       struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index];
+       struct nv04_crtc_reg *savep = &nv04_display(dev)->saved_reg.crtc_reg[nv_crtc->index];
        struct drm_encoder *encoder;
        bool lvds_output = false, tmds_output = false, tv_output = false,
                off_chip_digital = false;
                if (encoder->crtc != crtc)
                        continue;
  
-               if (nv_encoder->dcb->type == OUTPUT_LVDS)
+               if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS)
                        digital = lvds_output = true;
-               if (nv_encoder->dcb->type == OUTPUT_TV)
+               if (nv_encoder->dcb->type == DCB_OUTPUT_TV)
                        tv_output = true;
-               if (nv_encoder->dcb->type == OUTPUT_TMDS)
+               if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS)
                        digital = tmds_output = true;
                if (nv_encoder->dcb->location != DCB_LOC_ON_CHIP && digital)
                        off_chip_digital = true;
        regp->cursor_cfg = NV_PCRTC_CURSOR_CONFIG_CUR_LINES_64 |
                             NV_PCRTC_CURSOR_CONFIG_CUR_PIXELS_64 |
                             NV_PCRTC_CURSOR_CONFIG_ADDRESS_SPACE_PNVM;
-       if (dev_priv->chipset >= 0x11)
+       if (nv_device(drm->device)->chipset >= 0x11)
                regp->cursor_cfg |= NV_PCRTC_CURSOR_CONFIG_CUR_BPP_32;
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
                regp->cursor_cfg |= NV_PCRTC_CURSOR_CONFIG_DOUBLE_SCAN_ENABLE;
  
        /* The blob seems to take the current value from crtc 0, add 4 to that
         * and reuse the old value for crtc 1 */
-       regp->CRTC[NV_CIO_CRE_TVOUT_LATENCY] = dev_priv->saved_reg.crtc_reg[0].CRTC[NV_CIO_CRE_TVOUT_LATENCY];
+       regp->CRTC[NV_CIO_CRE_TVOUT_LATENCY] = nv04_display(dev)->saved_reg.crtc_reg[0].CRTC[NV_CIO_CRE_TVOUT_LATENCY];
        if (!nv_crtc->index)
                regp->CRTC[NV_CIO_CRE_TVOUT_LATENCY] += 4;
  
         * 1 << 30 on 0x60.830), for no apparent reason */
        regp->CRTC[NV_CIO_CRE_59] = off_chip_digital;
  
-       if (dev_priv->card_type >= NV_30)
+       if (nv_device(drm->device)->card_type >= NV_30)
                regp->CRTC[0x9f] = off_chip_digital ? 0x11 : 0x1;
  
        regp->crtc_830 = mode->crtc_vdisplay - 3;
        regp->crtc_834 = mode->crtc_vdisplay - 1;
  
-       if (dev_priv->card_type == NV_40)
+       if (nv_device(drm->device)->card_type == NV_40)
                /* This is what the blob does */
                regp->crtc_850 = NVReadCRTC(dev, 0, NV_PCRTC_850);
  
-       if (dev_priv->card_type >= NV_30)
+       if (nv_device(drm->device)->card_type >= NV_30)
                regp->gpio_ext = NVReadCRTC(dev, 0, NV_PCRTC_GPIO_EXT);
  
-       if (dev_priv->card_type >= NV_10)
+       if (nv_device(drm->device)->card_type >= NV_10)
                regp->crtc_cfg = NV10_PCRTC_CONFIG_START_ADDRESS_HSYNC;
        else
                regp->crtc_cfg = NV04_PCRTC_CONFIG_START_ADDRESS_HSYNC;
  
        /* Some misc regs */
-       if (dev_priv->card_type == NV_40) {
+       if (nv_device(drm->device)->card_type == NV_40) {
                regp->CRTC[NV_CIO_CRE_85] = 0xFF;
                regp->CRTC[NV_CIO_CRE_86] = 0x1;
        }
  
        /* Generic PRAMDAC regs */
  
-       if (dev_priv->card_type >= NV_10)
+       if (nv_device(drm->device)->card_type >= NV_10)
                /* Only bit that bios and blob set. */
                regp->nv10_cursync = (1 << 25);
  
                                NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON;
        if (crtc->fb->depth == 16)
                regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
-       if (dev_priv->chipset >= 0x11)
+       if (nv_device(drm->device)->chipset >= 0x11)
                regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_PIPE_LONG;
  
        regp->ramdac_630 = 0; /* turn off green mode (tv test pattern?) */
@@@ -611,9 -621,9 +621,9 @@@ nv_crtc_mode_set(struct drm_crtc *crtc
  {
        struct drm_device *dev = crtc->dev;
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
-       NV_DEBUG_KMS(dev, "CTRC mode on CRTC %d:\n", nv_crtc->index);
+       NV_DEBUG(drm, "CTRC mode on CRTC %d:\n", nv_crtc->index);
        drm_mode_debug_printmodeline(adjusted_mode);
  
        /* unlock must come after turning off FP_TG_CONTROL in output_prepare */
  
        nv_crtc_mode_set_vga(crtc, adjusted_mode);
        /* calculated in nv04_dfp_prepare, nv40 needs it written before calculating PLLs */
-       if (dev_priv->card_type == NV_40)
-               NVWriteRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK, dev_priv->mode_reg.sel_clk);
+       if (nv_device(drm->device)->card_type == NV_40)
+               NVWriteRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK, nv04_display(dev)->mode_reg.sel_clk);
        nv_crtc_mode_set_regs(crtc, adjusted_mode);
        nv_crtc_calc_state_ext(crtc, mode, adjusted_mode->clock);
        return 0;
  static void nv_crtc_save(struct drm_crtc *crtc)
  {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-       struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
-       struct nv04_mode_state *state = &dev_priv->mode_reg;
+       struct drm_device *dev = crtc->dev;
+       struct nv04_mode_state *state = &nv04_display(dev)->mode_reg;
        struct nv04_crtc_reg *crtc_state = &state->crtc_reg[nv_crtc->index];
-       struct nv04_mode_state *saved = &dev_priv->saved_reg;
+       struct nv04_mode_state *saved = &nv04_display(dev)->saved_reg;
        struct nv04_crtc_reg *crtc_saved = &saved->crtc_reg[nv_crtc->index];
  
        if (nv_two_heads(crtc->dev))
  static void nv_crtc_restore(struct drm_crtc *crtc)
  {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-       struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
+       struct drm_device *dev = crtc->dev;
        int head = nv_crtc->index;
-       uint8_t saved_cr21 = dev_priv->saved_reg.crtc_reg[head].CRTC[NV_CIO_CRE_21];
+       uint8_t saved_cr21 = nv04_display(dev)->saved_reg.crtc_reg[head].CRTC[NV_CIO_CRE_21];
  
        if (nv_two_heads(crtc->dev))
                NVSetOwner(crtc->dev, head);
  
-       nouveau_hw_load_state(crtc->dev, head, &dev_priv->saved_reg);
+       nouveau_hw_load_state(crtc->dev, head, &nv04_display(dev)->saved_reg);
        nv_lock_vga_crtc_shadow(crtc->dev, head, saved_cr21);
  
        nv_crtc->last_dpms = NV_DPMS_CLEARED;
  static void nv_crtc_prepare(struct drm_crtc *crtc)
  {
        struct drm_device *dev = crtc->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct drm_crtc_helper_funcs *funcs = crtc->helper_private;
  
  
        /* Some more preparation. */
        NVWriteCRTC(dev, nv_crtc->index, NV_PCRTC_CONFIG, NV_PCRTC_CONFIG_START_ADDRESS_NON_VGA);
-       if (dev_priv->card_type == NV_40) {
+       if (nv_device(drm->device)->card_type == NV_40) {
                uint32_t reg900 = NVReadRAMDAC(dev, nv_crtc->index, NV_PRAMDAC_900);
                NVWriteRAMDAC(dev, nv_crtc->index, NV_PRAMDAC_900, reg900 & ~0x10000);
        }
@@@ -692,10 -702,9 +702,9 @@@ static void nv_crtc_commit(struct drm_c
  {
        struct drm_device *dev = crtc->dev;
        struct drm_crtc_helper_funcs *funcs = crtc->helper_private;
-       struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
  
-       nouveau_hw_load_state(dev, nv_crtc->index, &dev_priv->mode_reg);
+       nouveau_hw_load_state(dev, nv_crtc->index, &nv04_display(dev)->mode_reg);
        nv04_crtc_mode_set_base(crtc, crtc->x, crtc->y, NULL);
  
  #ifdef __BIG_ENDIAN
@@@ -715,8 -724,6 +724,6 @@@ static void nv_crtc_destroy(struct drm_
  {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
  
-       NV_DEBUG_KMS(crtc->dev, "\n");
        if (!nv_crtc)
                return;
  
@@@ -732,18 -739,17 +739,17 @@@ nv_crtc_gamma_load(struct drm_crtc *crt
  {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct drm_device *dev = nv_crtc->base.dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct rgb { uint8_t r, g, b; } __attribute__((packed)) *rgbs;
        int i;
  
-       rgbs = (struct rgb *)dev_priv->mode_reg.crtc_reg[nv_crtc->index].DAC;
+       rgbs = (struct rgb *)nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index].DAC;
        for (i = 0; i < 256; i++) {
                rgbs[i].r = nv_crtc->lut.r[i] >> 8;
                rgbs[i].g = nv_crtc->lut.g[i] >> 8;
                rgbs[i].b = nv_crtc->lut.b[i] >> 8;
        }
  
-       nouveau_hw_load_state_palette(dev, nv_crtc->index, &dev_priv->mode_reg);
+       nouveau_hw_load_state_palette(dev, nv_crtc->index, &nv04_display(dev)->mode_reg);
  }
  
  static void
@@@ -779,18 -785,18 +785,18 @@@ nv04_crtc_do_mode_set_base(struct drm_c
  {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct drm_device *dev = crtc->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nv04_crtc_reg *regp = &dev_priv->mode_reg.crtc_reg[nv_crtc->index];
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index];
        struct drm_framebuffer *drm_fb;
        struct nouveau_framebuffer *fb;
        int arb_burst, arb_lwm;
        int ret;
  
-       NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
+       NV_DEBUG(drm, "index %d\n", nv_crtc->index);
  
        /* no fb bound */
        if (!atomic && !crtc->fb) {
-               NV_DEBUG_KMS(dev, "No FB bound\n");
+               NV_DEBUG(drm, "No FB bound\n");
                return 0;
        }
  
        crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FF_INDEX);
        crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FFLWM__INDEX);
  
-       if (dev_priv->card_type >= NV_20) {
+       if (nv_device(drm->device)->card_type >= NV_20) {
                regp->CRTC[NV_CIO_CRE_47] = arb_lwm >> 8;
                crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_47);
        }
@@@ -878,8 -884,8 +884,8 @@@ nv04_crtc_mode_set_base_atomic(struct d
                               struct drm_framebuffer *fb,
                               int x, int y, enum mode_set_atomic state)
  {
-       struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
-       struct drm_device *dev = dev_priv->dev;
+       struct nouveau_drm *drm = nouveau_drm(crtc->dev);
+       struct drm_device *dev = drm->dev;
  
        if (state == ENTER_ATOMIC_MODE_SET)
                nouveau_fbcon_save_disable_accel(dev);
@@@ -934,9 -940,9 +940,9 @@@ static void nv11_cursor_upload(struct d
  
  #ifdef __BIG_ENDIAN
                {
-                       struct drm_nouveau_private *dev_priv = dev->dev_private;
+                       struct nouveau_drm *drm = nouveau_drm(dev);
  
-                       if (dev_priv->chipset == 0x11) {
+                       if (nv_device(drm->device)->chipset == 0x11) {
                                pixel = ((pixel & 0x000000ff) << 24) |
                                        ((pixel & 0x0000ff00) << 8) |
                                        ((pixel & 0x00ff0000) >> 8) |
@@@ -953,8 -959,8 +959,8 @@@ static in
  nv04_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
                     uint32_t buffer_handle, uint32_t width, uint32_t height)
  {
-       struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
-       struct drm_device *dev = dev_priv->dev;
+       struct nouveau_drm *drm = nouveau_drm(crtc->dev);
+       struct drm_device *dev = drm->dev;
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct nouveau_bo *cursor = NULL;
        struct drm_gem_object *gem;
        if (ret)
                goto out;
  
-       if (dev_priv->chipset >= 0x11)
+       if (nv_device(drm->device)->chipset >= 0x11)
                nv11_cursor_upload(dev, cursor, nv_crtc->cursor.nvbo);
        else
                nv04_cursor_upload(dev, cursor, nv_crtc->cursor.nvbo);
@@@ -1,6 -1,7 +1,7 @@@
 -#include "drmP.h"
 -#include "drm_mode.h"
 +#include <drm/drmP.h>
++#include <drm/drm_mode.h>
+ #include "nouveau_drm.h"
  #include "nouveau_reg.h"
- #include "nouveau_drv.h"
  #include "nouveau_crtc.h"
  #include "nouveau_hw.h"
  
@@@ -37,8 -38,8 +38,8 @@@ static voi
  nv04_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
  {
        struct drm_device *dev = nv_crtc->base.dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nv04_crtc_reg *regp = &dev_priv->mode_reg.crtc_reg[nv_crtc->index];
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index];
        struct drm_crtc *crtc = &nv_crtc->base;
  
        regp->CRTC[NV_CIO_CRE_HCUR_ADDR0_INDEX] =
@@@ -54,7 -55,7 +55,7 @@@
        crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
        crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX);
        crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_HCUR_ADDR2_INDEX);
-       if (dev_priv->card_type == NV_40)
+       if (nv_device(drm->device)->card_type == NV_40)
                nv_fix_nv40_hw_cursor(dev, nv_crtc->index);
  }
  
   * DEALINGS IN THE SOFTWARE.
   */
  
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
  
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
  #include "nouveau_encoder.h"
  #include "nouveau_connector.h"
  #include "nouveau_crtc.h"
  #include "nouveau_hw.h"
- #include "nouveau_gpio.h"
  #include "nvreg.h"
  
+ #include <subdev/bios/gpio.h>
+ #include <subdev/gpio.h>
+ #include <subdev/timer.h>
  int nv04_dac_output_offset(struct drm_encoder *encoder)
  {
-       struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+       struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
        int offset = 0;
  
-       if (dcb->or & (8 | OUTPUT_C))
+       if (dcb->or & (8 | DCB_OUTPUT_C))
                offset += 0x68;
-       if (dcb->or & (8 | OUTPUT_B))
+       if (dcb->or & (8 | DCB_OUTPUT_B))
                offset += 0x2000;
  
        return offset;
@@@ -62,6 -65,8 +65,8 @@@
  
  static int sample_load_twice(struct drm_device *dev, bool sense[2])
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_timer *ptimer = nouveau_timer(device);
        int i;
  
        for (i = 0; i < 2; i++) {
                 * use a 10ms timeout (guards against crtc being inactive, in
                 * which case blank state would never change)
                 */
-               if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR,
-                                    0x00000001, 0x00000000))
+               if (!nouveau_timer_wait_eq(ptimer, 10000000,
+                                          NV_PRMCIO_INP0__COLOR,
+                                          0x00000001, 0x00000000))
                        return -EBUSY;
-               if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR,
-                                    0x00000001, 0x00000001))
+               if (!nouveau_timer_wait_eq(ptimer, 10000000,
+                                          NV_PRMCIO_INP0__COLOR,
+                                          0x00000001, 0x00000001))
                        return -EBUSY;
-               if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR,
-                                    0x00000001, 0x00000000))
+               if (!nouveau_timer_wait_eq(ptimer, 10000000,
+                                          NV_PRMCIO_INP0__COLOR,
+                                          0x00000001, 0x00000000))
                        return -EBUSY;
  
                udelay(100);
                /* when level triggers, sense is _LO_ */
-               sense_a = nv_rd08(dev, NV_PRMCIO_INP0) & 0x10;
+               sense_a = nv_rd08(device, NV_PRMCIO_INP0) & 0x10;
  
                /* take another reading until it agrees with sense_a... */
                do {
                        udelay(100);
-                       sense_b = nv_rd08(dev, NV_PRMCIO_INP0) & 0x10;
+                       sense_b = nv_rd08(device, NV_PRMCIO_INP0) & 0x10;
                        if (sense_a != sense_b) {
                                sense_b_prime =
-                                       nv_rd08(dev, NV_PRMCIO_INP0) & 0x10;
+                                       nv_rd08(device, NV_PRMCIO_INP0) & 0x10;
                                if (sense_b == sense_b_prime) {
                                        /* ... unless two consecutive subsequent
                                         * samples agree; sense_a is replaced */
@@@ -120,6 -128,8 +128,8 @@@ static enum drm_connector_status nv04_d
                                                 struct drm_connector *connector)
  {
        struct drm_device *dev = encoder->dev;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        uint8_t saved_seq1, saved_pi, saved_rpc1, saved_cr_mode;
        uint8_t saved_palette0[3], saved_palette_mask;
        uint32_t saved_rtest_ctrl, saved_rgen_ctrl;
        saved_rpc1 = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX);
        NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1 & ~0xc0);
  
-       nv_wr08(dev, NV_PRMDIO_READ_MODE_ADDRESS, 0x0);
+       nv_wr08(device, NV_PRMDIO_READ_MODE_ADDRESS, 0x0);
        for (i = 0; i < 3; i++)
-               saved_palette0[i] = nv_rd08(dev, NV_PRMDIO_PALETTE_DATA);
-       saved_palette_mask = nv_rd08(dev, NV_PRMDIO_PIXEL_MASK);
-       nv_wr08(dev, NV_PRMDIO_PIXEL_MASK, 0);
+               saved_palette0[i] = nv_rd08(device, NV_PRMDIO_PALETTE_DATA);
+       saved_palette_mask = nv_rd08(device, NV_PRMDIO_PIXEL_MASK);
+       nv_wr08(device, NV_PRMDIO_PIXEL_MASK, 0);
  
        saved_rgen_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL);
        NVWriteRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL,
        do {
                bool sense_pair[2];
  
-               nv_wr08(dev, NV_PRMDIO_WRITE_MODE_ADDRESS, 0);
-               nv_wr08(dev, NV_PRMDIO_PALETTE_DATA, 0);
-               nv_wr08(dev, NV_PRMDIO_PALETTE_DATA, 0);
+               nv_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS, 0);
+               nv_wr08(device, NV_PRMDIO_PALETTE_DATA, 0);
+               nv_wr08(device, NV_PRMDIO_PALETTE_DATA, 0);
                /* testing blue won't find monochrome monitors.  I don't care */
-               nv_wr08(dev, NV_PRMDIO_PALETTE_DATA, blue);
+               nv_wr08(device, NV_PRMDIO_PALETTE_DATA, blue);
  
                i = 0;
                /* take sample pairs until both samples in the pair agree */
        } while (++blue < 0x18 && sense);
  
  out:
-       nv_wr08(dev, NV_PRMDIO_PIXEL_MASK, saved_palette_mask);
+       nv_wr08(device, NV_PRMDIO_PIXEL_MASK, saved_palette_mask);
        NVWriteRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL, saved_rgen_ctrl);
-       nv_wr08(dev, NV_PRMDIO_WRITE_MODE_ADDRESS, 0);
+       nv_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS, 0);
        for (i = 0; i < 3; i++)
-               nv_wr08(dev, NV_PRMDIO_PALETTE_DATA, saved_palette0[i]);
+               nv_wr08(device, NV_PRMDIO_PALETTE_DATA, saved_palette0[i]);
        NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL, saved_rtest_ctrl);
        NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX, saved_pi);
        NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1);
        NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode);
  
        if (blue == 0x18) {
-               NV_INFO(dev, "Load detected on head A\n");
+               NV_INFO(drm, "Load detected on head A\n");
                return connector_status_connected;
        }
  
  uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_gpio *gpio = nouveau_gpio(device);
+       struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
        uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder);
        uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput,
-               saved_rtest_ctrl, saved_gpio0, saved_gpio1, temp, routput;
+               saved_rtest_ctrl, saved_gpio0 = 0, saved_gpio1 = 0, temp, routput;
        int head;
  
  #define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20)
-       if (dcb->type == OUTPUT_TV) {
+       if (dcb->type == DCB_OUTPUT_TV) {
                testval = RGB_TEST_DATA(0xa0, 0xa0, 0xa0);
  
-               if (dev_priv->vbios.tvdactestval)
-                       testval = dev_priv->vbios.tvdactestval;
+               if (drm->vbios.tvdactestval)
+                       testval = drm->vbios.tvdactestval;
        } else {
                testval = RGB_TEST_DATA(0x140, 0x140, 0x140); /* 0x94050140 */
  
-               if (dev_priv->vbios.dactestval)
-                       testval = dev_priv->vbios.dactestval;
+               if (drm->vbios.dactestval)
+                       testval = drm->vbios.dactestval;
        }
  
        saved_rtest_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
        NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset,
                      saved_rtest_ctrl & ~NV_PRAMDAC_TEST_CONTROL_PWRDWN_DAC_OFF);
  
-       saved_powerctrl_2 = nvReadMC(dev, NV_PBUS_POWERCTRL_2);
+       saved_powerctrl_2 = nv_rd32(device, NV_PBUS_POWERCTRL_2);
  
-       nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2 & 0xd7ffffff);
+       nv_wr32(device, NV_PBUS_POWERCTRL_2, saved_powerctrl_2 & 0xd7ffffff);
        if (regoffset == 0x68) {
-               saved_powerctrl_4 = nvReadMC(dev, NV_PBUS_POWERCTRL_4);
-               nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf);
+               saved_powerctrl_4 = nv_rd32(device, NV_PBUS_POWERCTRL_4);
+               nv_wr32(device, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf);
        }
  
-       saved_gpio1 = nouveau_gpio_func_get(dev, DCB_GPIO_TVDAC1);
-       saved_gpio0 = nouveau_gpio_func_get(dev, DCB_GPIO_TVDAC0);
-       nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV);
-       nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV);
+       if (gpio) {
+               saved_gpio1 = gpio->get(gpio, 0, DCB_GPIO_TVDAC1, 0xff);
+               saved_gpio0 = gpio->get(gpio, 0, DCB_GPIO_TVDAC0, 0xff);
+               gpio->set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, dcb->type == DCB_OUTPUT_TV);
+               gpio->set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, dcb->type == DCB_OUTPUT_TV);
+       }
  
        msleep(4);
  
        /* nv driver and nv31 use 0xfffffeee, nv34 and 6600 use 0xfffffece */
        routput = (saved_routput & 0xfffffece) | head << 8;
  
-       if (dev_priv->card_type >= NV_40) {
-               if (dcb->type == OUTPUT_TV)
+       if (nv_device(drm->device)->card_type >= NV_40) {
+               if (dcb->type == DCB_OUTPUT_TV)
                        routput |= 0x1a << 16;
                else
                        routput &= ~(0x1a << 16);
        NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, saved_routput);
        NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, saved_rtest_ctrl);
        if (regoffset == 0x68)
-               nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4);
-       nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2);
+               nv_wr32(device, NV_PBUS_POWERCTRL_4, saved_powerctrl_4);
+       nv_wr32(device, NV_PBUS_POWERCTRL_2, saved_powerctrl_2);
  
-       nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, saved_gpio1);
-       nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, saved_gpio0);
+       if (gpio) {
+               gpio->set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, saved_gpio1);
+               gpio->set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, saved_gpio0);
+       }
  
        return sample;
  }
  static enum drm_connector_status
  nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
  {
-       struct drm_device *dev = encoder->dev;
-       struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+       struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
  
        if (nv04_dac_in_use(encoder))
                return connector_status_disconnected;
  
        if (nv17_dac_sample_load(encoder) &
            NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) {
-               NV_INFO(dev, "Load detected on output %c\n",
+               NV_INFO(drm, "Load detected on output %c\n",
                        '@' + ffs(dcb->or));
                return connector_status_connected;
        } else {
@@@ -357,7 -372,7 +372,7 @@@ static void nv04_dac_mode_set(struct dr
                              struct drm_display_mode *adjusted_mode)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        int head = nouveau_crtc(encoder->crtc)->index;
  
        if (nv_gf4_disp_arch(dev)) {
                /* force any other vga encoders to bind to the other crtc */
                list_for_each_entry(rebind, &dev->mode_config.encoder_list, head) {
                        if (rebind == encoder
-                           || nouveau_encoder(rebind)->dcb->type != OUTPUT_ANALOG)
+                           || nouveau_encoder(rebind)->dcb->type != DCB_OUTPUT_ANALOG)
                                continue;
  
                        dac_offset = nv04_dac_output_offset(rebind);
        }
  
        /* This could use refinement for flatpanels, but it should work this way */
-       if (dev_priv->chipset < 0x44)
+       if (nv_device(drm->device)->chipset < 0x44)
                NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0xf0000000);
        else
                NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000);
  static void nv04_dac_commit(struct drm_encoder *encoder)
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-       struct drm_device *dev = encoder->dev;
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
        struct drm_encoder_helper_funcs *helper = encoder->helper_private;
  
        helper->dpms(encoder, DRM_MODE_DPMS_ON);
  
-       NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
+       NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n",
                drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
                nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
  }
  void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+       struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
  
        if (nv_gf4_disp_arch(dev)) {
-               uint32_t *dac_users = &dev_priv->dac_users[ffs(dcb->or) - 1];
+               uint32_t *dac_users = &nv04_display(dev)->dac_users[ffs(dcb->or) - 1];
                int dacclk_off = NV_PRAMDAC_DACCLK + nv04_dac_output_offset(encoder);
                uint32_t dacclk = NVReadRAMDAC(dev, 0, dacclk_off);
  
   * someone else. */
  bool nv04_dac_in_use(struct drm_encoder *encoder)
  {
-       struct drm_nouveau_private *dev_priv = encoder->dev->dev_private;
-       struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+       struct drm_device *dev = encoder->dev;
+       struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
  
        return nv_gf4_disp_arch(encoder->dev) &&
-               (dev_priv->dac_users[ffs(dcb->or) - 1] & ~(1 << dcb->index));
+               (nv04_display(dev)->dac_users[ffs(dcb->or) - 1] & ~(1 << dcb->index));
  }
  
  static void nv04_dac_dpms(struct drm_encoder *encoder, int mode)
  {
-       struct drm_device *dev = encoder->dev;
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
  
        if (nv_encoder->last_dpms == mode)
                return;
        nv_encoder->last_dpms = mode;
  
-       NV_INFO(dev, "Setting dpms mode %d on vga encoder (output %d)\n",
+       NV_INFO(drm, "Setting dpms mode %d on vga encoder (output %d)\n",
                     mode, nv_encoder->dcb->index);
  
        nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);
@@@ -479,8 -493,6 +493,6 @@@ static void nv04_dac_destroy(struct drm
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
  
-       NV_DEBUG_KMS(encoder->dev, "\n");
        drm_encoder_cleanup(encoder);
        kfree(nv_encoder);
  }
@@@ -512,7 -524,7 +524,7 @@@ static const struct drm_encoder_funcs n
  };
  
  int
- nv04_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
+ nv04_dac_create(struct drm_connector *connector, struct dcb_output *entry)
  {
        const struct drm_encoder_helper_funcs *helper;
        struct nouveau_encoder *nv_encoder = NULL;
   * DEALINGS IN THE SOFTWARE.
   */
  
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
  
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_reg.h"
  #include "nouveau_encoder.h"
  #include "nouveau_connector.h"
  #include "nouveau_crtc.h"
  #include "nouveau_hw.h"
  #include "nvreg.h"
  
 -#include "i2c/sil164.h"
 +#include <drm/i2c/sil164.h>
  
+ #include <subdev/i2c.h>
  #define FP_TG_CONTROL_ON  (NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS |      \
                           NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS |         \
                           NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS)
@@@ -49,20 -52,20 +52,20 @@@ static inline bool is_fpc_off(uint32_t 
                        FP_TG_CONTROL_OFF);
  }
  
- int nv04_dfp_get_bound_head(struct drm_device *dev, struct dcb_entry *dcbent)
+ int nv04_dfp_get_bound_head(struct drm_device *dev, struct dcb_output *dcbent)
  {
        /* special case of nv_read_tmds to find crtc associated with an output.
         * this does not give a correct answer for off-chip dvi, but there's no
         * use for such an answer anyway
         */
-       int ramdac = (dcbent->or & OUTPUT_C) >> 2;
+       int ramdac = (dcbent->or & DCB_OUTPUT_C) >> 2;
  
        NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL,
        NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE | 0x4);
        return ((NVReadRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA) & 0x8) >> 3) ^ ramdac;
  }
  
- void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_entry *dcbent,
+ void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_output *dcbent,
                        int head, bool dl)
  {
        /* The BIOS scripts don't do this for us, sadly
         * (for VT restore etc.)
         */
  
-       int ramdac = (dcbent->or & OUTPUT_C) >> 2;
+       int ramdac = (dcbent->or & DCB_OUTPUT_C) >> 2;
        uint8_t tmds04 = 0x80;
  
        if (head != ramdac)
                tmds04 = 0x88;
  
-       if (dcbent->type == OUTPUT_LVDS)
+       if (dcbent->type == DCB_OUTPUT_LVDS)
                tmds04 |= 0x01;
  
        nv_write_tmds(dev, dcbent->or, 0, 0x04, tmds04);
@@@ -89,8 -92,7 +92,7 @@@
  
  void nv04_dfp_disable(struct drm_device *dev, int head)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nv04_crtc_reg *crtcstate = dev_priv->mode_reg.crtc_reg;
+       struct nv04_crtc_reg *crtcstate = nv04_display(dev)->mode_reg.crtc_reg;
  
        if (NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL) &
            FP_TG_CONTROL_ON) {
  void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc;
        struct nouveau_crtc *nv_crtc;
        uint32_t *fpc;
  
        if (mode == DRM_MODE_DPMS_ON) {
                nv_crtc = nouveau_crtc(encoder->crtc);
-               fpc = &dev_priv->mode_reg.crtc_reg[nv_crtc->index].fp_control;
+               fpc = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index].fp_control;
  
                if (is_fpc_off(*fpc)) {
                        /* using saved value is ok, as (is_digital && dpms_on &&
        } else {
                list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                        nv_crtc = nouveau_crtc(crtc);
-                       fpc = &dev_priv->mode_reg.crtc_reg[nv_crtc->index].fp_control;
+                       fpc = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index].fp_control;
  
                        nv_crtc->fp_users &= ~(1 << nouveau_encoder(encoder)->dcb->index);
                        if (!is_fpc_off(*fpc) && !nv_crtc->fp_users) {
  static struct drm_encoder *get_tmds_slave(struct drm_encoder *encoder)
  {
        struct drm_device *dev = encoder->dev;
-       struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+       struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
        struct drm_encoder *slave;
  
-       if (dcb->type != OUTPUT_TMDS || dcb->location == DCB_LOC_ON_CHIP)
+       if (dcb->type != DCB_OUTPUT_TMDS || dcb->location == DCB_LOC_ON_CHIP)
                return NULL;
  
        /* Some BIOSes (e.g. the one in a Quadro FX1000) report several
         * let's do the same.
         */
        list_for_each_entry(slave, &dev->mode_config.encoder_list, head) {
-               struct dcb_entry *slave_dcb = nouveau_encoder(slave)->dcb;
+               struct dcb_output *slave_dcb = nouveau_encoder(slave)->dcb;
  
-               if (slave_dcb->type == OUTPUT_TMDS && get_slave_funcs(slave) &&
+               if (slave_dcb->type == DCB_OUTPUT_TMDS && get_slave_funcs(slave) &&
                    slave_dcb->tmdsconf.slave_addr == dcb->tmdsconf.slave_addr)
                        return slave;
        }
@@@ -202,9 -203,8 +203,8 @@@ static bool nv04_dfp_mode_fixup(struct 
  static void nv04_dfp_prepare_sel_clk(struct drm_device *dev,
                                     struct nouveau_encoder *nv_encoder, int head)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nv04_mode_state *state = &dev_priv->mode_reg;
-       uint32_t bits1618 = nv_encoder->dcb->or & OUTPUT_A ? 0x10000 : 0x40000;
+       struct nv04_mode_state *state = &nv04_display(dev)->mode_reg;
+       uint32_t bits1618 = nv_encoder->dcb->or & DCB_OUTPUT_A ? 0x10000 : 0x40000;
  
        if (nv_encoder->dcb->location != DCB_LOC_ON_CHIP)
                return;
         *      and which bit-pair to use, is unclear on nv40 (for earlier cards, the fp table
         *      entry has the necessary info)
         */
-       if (nv_encoder->dcb->type == OUTPUT_LVDS && dev_priv->saved_reg.sel_clk & 0xf0) {
-               int shift = (dev_priv->saved_reg.sel_clk & 0x50) ? 0 : 1;
+       if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS && nv04_display(dev)->saved_reg.sel_clk & 0xf0) {
+               int shift = (nv04_display(dev)->saved_reg.sel_clk & 0x50) ? 0 : 1;
  
                state->sel_clk &= ~0xf0;
                state->sel_clk |= (head ? 0x40 : 0x10) << shift;
@@@ -246,9 -246,8 +246,8 @@@ static void nv04_dfp_prepare(struct drm
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_encoder_helper_funcs *helper = encoder->helper_private;
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        int head = nouveau_crtc(encoder->crtc)->index;
-       struct nv04_crtc_reg *crtcstate = dev_priv->mode_reg.crtc_reg;
+       struct nv04_crtc_reg *crtcstate = nv04_display(dev)->mode_reg.crtc_reg;
        uint8_t *cr_lcd = &crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX];
        uint8_t *cr_lcd_oth = &crtcstate[head ^ 1].CRTC[NV_CIO_CRE_LCD__INDEX];
  
                        *cr_lcd |= head ? 0x0 : 0x8;
                else {
                        *cr_lcd |= (nv_encoder->dcb->or << 4) & 0x30;
-                       if (nv_encoder->dcb->type == OUTPUT_LVDS)
+                       if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS)
                                *cr_lcd |= 0x30;
                        if ((*cr_lcd & 0x30) == (*cr_lcd_oth & 0x30)) {
                                /* avoid being connected to both crtcs */
@@@ -282,17 -281,18 +281,18 @@@ static void nv04_dfp_mode_set(struct dr
                              struct drm_display_mode *adjusted_mode)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
-       struct nv04_crtc_reg *regp = &dev_priv->mode_reg.crtc_reg[nv_crtc->index];
-       struct nv04_crtc_reg *savep = &dev_priv->saved_reg.crtc_reg[nv_crtc->index];
+       struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index];
+       struct nv04_crtc_reg *savep = &nv04_display(dev)->saved_reg.crtc_reg[nv_crtc->index];
        struct nouveau_connector *nv_connector = nouveau_crtc_connector_get(nv_crtc);
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_display_mode *output_mode = &nv_encoder->mode;
        struct drm_connector *connector = &nv_connector->base;
        uint32_t mode_ratio, panel_ratio;
  
-       NV_DEBUG_KMS(dev, "Output mode on CRTC %d:\n", nv_crtc->index);
+       NV_DEBUG(drm, "Output mode on CRTC %d:\n", nv_crtc->index);
        drm_mode_debug_printmodeline(output_mode);
  
        /* Initialize the FP registers in this CRTC. */
        regp->fp_horiz_regs[FP_TOTAL] = output_mode->htotal - 1;
        if (!nv_gf4_disp_arch(dev) ||
            (output_mode->hsync_start - output_mode->hdisplay) >=
-                                       dev_priv->vbios.digital_min_front_porch)
+                                       drm->vbios.digital_min_front_porch)
                regp->fp_horiz_regs[FP_CRTC] = output_mode->hdisplay;
        else
-               regp->fp_horiz_regs[FP_CRTC] = output_mode->hsync_start - dev_priv->vbios.digital_min_front_porch - 1;
+               regp->fp_horiz_regs[FP_CRTC] = output_mode->hsync_start - drm->vbios.digital_min_front_porch - 1;
        regp->fp_horiz_regs[FP_SYNC_START] = output_mode->hsync_start - 1;
        regp->fp_horiz_regs[FP_SYNC_END] = output_mode->hsync_end - 1;
        regp->fp_horiz_regs[FP_VALID_START] = output_mode->hskew;
                regp->fp_control |= NV_PRAMDAC_FP_TG_CONTROL_MODE_NATIVE;
        else /* gpu needs to scale */
                regp->fp_control |= NV_PRAMDAC_FP_TG_CONTROL_MODE_SCALE;
-       if (nvReadEXTDEV(dev, NV_PEXTDEV_BOOT_0) & NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT)
+       if (nv_rd32(device, NV_PEXTDEV_BOOT_0) & NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT)
                regp->fp_control |= NV_PRAMDAC_FP_TG_CONTROL_WIDTH_12;
        if (nv_encoder->dcb->location != DCB_LOC_ON_CHIP &&
            output_mode->clock > 165000)
                regp->fp_control |= (2 << 24);
-       if (nv_encoder->dcb->type == OUTPUT_LVDS) {
+       if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS) {
                bool duallink = false, dummy;
                if (nv_connector->edid &&
                    nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) {
        if ((nv_connector->dithering_mode == DITHERING_MODE_ON) ||
            (nv_connector->dithering_mode == DITHERING_MODE_AUTO &&
             encoder->crtc->fb->depth > connector->display_info.bpc * 3)) {
-               if (dev_priv->chipset == 0x11)
+               if (nv_device(drm->device)->chipset == 0x11)
                        regp->dither = savep->dither | 0x00010000;
                else {
                        int i;
                        }
                }
        } else {
-               if (dev_priv->chipset != 0x11) {
+               if (nv_device(drm->device)->chipset != 0x11) {
                        /* reset them */
                        int i;
                        for (i = 0; i < 3; i++) {
  static void nv04_dfp_commit(struct drm_encoder *encoder)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct drm_encoder_helper_funcs *helper = encoder->helper_private;
        struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-       struct dcb_entry *dcbe = nv_encoder->dcb;
+       struct dcb_output *dcbe = nv_encoder->dcb;
        int head = nouveau_crtc(encoder->crtc)->index;
        struct drm_encoder *slave_encoder;
  
-       if (dcbe->type == OUTPUT_TMDS)
+       if (dcbe->type == DCB_OUTPUT_TMDS)
                run_tmds_table(dev, dcbe, head, nv_encoder->mode.clock);
-       else if (dcbe->type == OUTPUT_LVDS)
+       else if (dcbe->type == DCB_OUTPUT_LVDS)
                call_lvds_script(dev, dcbe, head, LVDS_RESET, nv_encoder->mode.clock);
  
        /* update fp_control state for any changes made by scripts,
         * so correct value is written at DPMS on */
-       dev_priv->mode_reg.crtc_reg[head].fp_control =
+       nv04_display(dev)->mode_reg.crtc_reg[head].fp_control =
                NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL);
  
        /* This could use refinement for flatpanels, but it should work this way */
-       if (dev_priv->chipset < 0x44)
+       if (nv_device(drm->device)->chipset < 0x44)
                NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0xf0000000);
        else
                NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000);
  
        helper->dpms(encoder, DRM_MODE_DPMS_ON);
  
-       NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
+       NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n",
                drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
                nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
  }
@@@ -485,6 -485,7 +485,7 @@@ static void nv04_dfp_update_backlight(s
  {
  #ifdef __powerpc__
        struct drm_device *dev = encoder->dev;
+       struct nouveau_device *device = nouveau_dev(dev);
  
        /* BIOS scripts usually take care of the backlight, thanks
         * Apple for your consistency.
        if (dev->pci_device == 0x0179 || dev->pci_device == 0x0189 ||
            dev->pci_device == 0x0329) {
                if (mode == DRM_MODE_DPMS_ON) {
-                       nv_mask(dev, NV_PBUS_DEBUG_DUALHEAD_CTL, 0, 1 << 31);
-                       nv_mask(dev, NV_PCRTC_GPIO_EXT, 3, 1);
+                       nv_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 0, 1 << 31);
+                       nv_mask(device, NV_PCRTC_GPIO_EXT, 3, 1);
                } else {
-                       nv_mask(dev, NV_PBUS_DEBUG_DUALHEAD_CTL, 1 << 31, 0);
-                       nv_mask(dev, NV_PCRTC_GPIO_EXT, 3, 0);
+                       nv_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 1 << 31, 0);
+                       nv_mask(device, NV_PCRTC_GPIO_EXT, 3, 0);
                }
        }
  #endif
@@@ -511,7 -512,7 +512,7 @@@ static void nv04_lvds_dpms(struct drm_e
  {
        struct drm_device *dev = encoder->dev;
        struct drm_crtc *crtc = encoder->crtc;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        bool was_powersaving = is_powersaving_dpms(nv_encoder->last_dpms);
  
                return;
        nv_encoder->last_dpms = mode;
  
-       NV_INFO(dev, "Setting dpms mode %d on lvds encoder (output %d)\n",
+       NV_INFO(drm, "Setting dpms mode %d on lvds encoder (output %d)\n",
                     mode, nv_encoder->dcb->index);
  
        if (was_powersaving && is_powersaving_dpms(mode))
        if (mode == DRM_MODE_DPMS_ON)
                nv04_dfp_prepare_sel_clk(dev, nv_encoder, nouveau_crtc(crtc)->index);
        else {
-               dev_priv->mode_reg.sel_clk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK);
-               dev_priv->mode_reg.sel_clk &= ~0xf0;
+               nv04_display(dev)->mode_reg.sel_clk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK);
+               nv04_display(dev)->mode_reg.sel_clk &= ~0xf0;
        }
-       NVWriteRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK, dev_priv->mode_reg.sel_clk);
+       NVWriteRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK, nv04_display(dev)->mode_reg.sel_clk);
  }
  
  static void nv04_tmds_dpms(struct drm_encoder *encoder, int mode)
  {
-       struct drm_device *dev = encoder->dev;
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
  
        if (nv_encoder->last_dpms == mode)
                return;
        nv_encoder->last_dpms = mode;
  
-       NV_INFO(dev, "Setting dpms mode %d on tmds encoder (output %d)\n",
+       NV_INFO(drm, "Setting dpms mode %d on tmds encoder (output %d)\n",
                     mode, nv_encoder->dcb->index);
  
        nv04_dfp_update_backlight(encoder, mode);
@@@ -585,10 -586,9 +586,9 @@@ static void nv04_dfp_restore(struct drm
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        int head = nv_encoder->restore.head;
  
-       if (nv_encoder->dcb->type == OUTPUT_LVDS) {
+       if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS) {
                struct nouveau_connector *connector =
                        nouveau_encoder_connector_get(nv_encoder);
  
                                         LVDS_PANEL_ON,
                                         connector->native_mode->clock);
  
-       } else if (nv_encoder->dcb->type == OUTPUT_TMDS) {
+       } else if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS) {
                int clock = nouveau_hw_pllvals_to_clk
-                                       (&dev_priv->saved_reg.crtc_reg[head].pllvals);
+                                       (&nv04_display(dev)->saved_reg.crtc_reg[head].pllvals);
  
                run_tmds_table(dev, nv_encoder->dcb, head, clock);
        }
@@@ -611,8 -611,6 +611,6 @@@ static void nv04_dfp_destroy(struct drm
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
  
-       NV_DEBUG_KMS(encoder->dev, "\n");
        if (get_slave_funcs(encoder))
                get_slave_funcs(encoder)->destroy(encoder);
  
  static void nv04_tmds_slave_init(struct drm_encoder *encoder)
  {
        struct drm_device *dev = encoder->dev;
-       struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
-       struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, 2);
+       struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
+       struct nouveau_i2c_port *port = i2c->find(i2c, 2);
        struct i2c_board_info info[] = {
                {
                        .type = "sil164",
        };
        int type;
  
-       if (!nv_gf4_disp_arch(dev) || !i2c ||
+       if (!nv_gf4_disp_arch(dev) || !port ||
            get_tmds_slave(encoder))
                return;
  
-       type = nouveau_i2c_identify(dev, "TMDS transmitter", info, NULL, 2);
+       type = i2c->identify(i2c, 2, "TMDS transmitter", info, NULL);
        if (type < 0)
                return;
  
        drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
-                            &i2c->adapter, &info[type]);
+                            &port->adapter, &info[type]);
  }
  
  static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = {
@@@ -676,7 -676,7 +676,7 @@@ static const struct drm_encoder_funcs n
  };
  
  int
- nv04_dfp_create(struct drm_connector *connector, struct dcb_entry *entry)
+ nv04_dfp_create(struct drm_connector *connector, struct dcb_output *entry)
  {
        const struct drm_encoder_helper_funcs *helper;
        struct nouveau_encoder *nv_encoder = NULL;
        int type;
  
        switch (entry->type) {
-       case OUTPUT_TMDS:
+       case DCB_OUTPUT_TMDS:
                type = DRM_MODE_ENCODER_TMDS;
                helper = &nv04_tmds_helper_funcs;
                break;
-       case OUTPUT_LVDS:
+       case DCB_OUTPUT_LVDS:
                type = DRM_MODE_ENCODER_LVDS;
                helper = &nv04_lvds_helper_funcs;
                break;
        encoder->possible_crtcs = entry->heads;
        encoder->possible_clones = 0;
  
-       if (entry->type == OUTPUT_TMDS &&
+       if (entry->type == DCB_OUTPUT_TMDS &&
            entry->location != DCB_LOC_ON_CHIP)
                nv04_tmds_slave_init(encoder);
  
   * Author: Ben Skeggs
   */
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
  
- #include "nouveau_drv.h"
- #include "nouveau_fb.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_reg.h"
  #include "nouveau_hw.h"
  #include "nouveau_encoder.h"
  #include "nouveau_connector.h"
  
- static void nv04_vblank_crtc0_isr(struct drm_device *);
- static void nv04_vblank_crtc1_isr(struct drm_device *);
- static void
- nv04_display_store_initial_head_owner(struct drm_device *dev)
- {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       if (dev_priv->chipset != 0x11) {
-               dev_priv->crtc_owner = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44);
-               return;
-       }
-       /* reading CR44 is broken on nv11, so we attempt to infer it */
-       if (nvReadMC(dev, NV_PBUS_DEBUG_1) & (1 << 28)) /* heads tied, restore both */
-               dev_priv->crtc_owner = 0x4;
-       else {
-               uint8_t slaved_on_A, slaved_on_B;
-               bool tvA = false;
-               bool tvB = false;
-               slaved_on_B = NVReadVgaCrtc(dev, 1, NV_CIO_CRE_PIXEL_INDEX) &
-                                                                       0x80;
-               if (slaved_on_B)
-                       tvB = !(NVReadVgaCrtc(dev, 1, NV_CIO_CRE_LCD__INDEX) &
-                                       MASK(NV_CIO_CRE_LCD_LCD_SELECT));
-               slaved_on_A = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX) &
-                                                                       0x80;
-               if (slaved_on_A)
-                       tvA = !(NVReadVgaCrtc(dev, 0, NV_CIO_CRE_LCD__INDEX) &
-                                       MASK(NV_CIO_CRE_LCD_LCD_SELECT));
-               if (slaved_on_A && !tvA)
-                       dev_priv->crtc_owner = 0x0;
-               else if (slaved_on_B && !tvB)
-                       dev_priv->crtc_owner = 0x3;
-               else if (slaved_on_A)
-                       dev_priv->crtc_owner = 0x0;
-               else if (slaved_on_B)
-                       dev_priv->crtc_owner = 0x3;
-               else
-                       dev_priv->crtc_owner = 0x0;
-       }
- }
  int
  nv04_display_early_init(struct drm_device *dev)
  {
-       /* Make the I2C buses accessible. */
-       if (!nv_gf4_disp_arch(dev)) {
-               uint32_t pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE);
-               if (!(pmc_enable & 1))
-                       nv_wr32(dev, NV03_PMC_ENABLE, pmc_enable | 1);
-       }
-       /* Unlock the VGA CRTCs. */
-       NVLockVgaCrtcs(dev, false);
-       /* Make sure the CRTCs aren't in slaved mode. */
-       if (nv_two_heads(dev)) {
-               nv04_display_store_initial_head_owner(dev);
-               NVSetOwner(dev, 0);
-       }
        /* ensure vblank interrupts are off, they can't be enabled until
         * drm_vblank has been initialised
         */
  void
  nv04_display_late_takedown(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       if (nv_two_heads(dev))
-               NVSetOwner(dev, dev_priv->crtc_owner);
-       NVLockVgaCrtcs(dev, true);
  }
  
  int
  nv04_display_create(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct dcb_table *dcb = &dev_priv->vbios.dcb;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct dcb_table *dcb = &drm->vbios.dcb;
        struct drm_connector *connector, *ct;
        struct drm_encoder *encoder;
        struct drm_crtc *crtc;
+       struct nv04_display *disp;
        int i, ret;
  
-       NV_DEBUG_KMS(dev, "\n");
+       NV_DEBUG(drm, "\n");
+       disp = kzalloc(sizeof(*disp), GFP_KERNEL);
+       if (!disp)
+               return -ENOMEM;
+       nouveau_display(dev)->priv = disp;
+       nouveau_display(dev)->dtor = nv04_display_destroy;
+       nouveau_display(dev)->init = nv04_display_init;
+       nouveau_display(dev)->fini = nv04_display_fini;
  
        nouveau_hw_save_vga_fonts(dev, 1);
  
                nv04_crtc_create(dev, 1);
  
        for (i = 0; i < dcb->entries; i++) {
-               struct dcb_entry *dcbent = &dcb->entry[i];
+               struct dcb_output *dcbent = &dcb->entry[i];
  
                connector = nouveau_connector_create(dev, dcbent->connector);
                if (IS_ERR(connector))
                        continue;
  
                switch (dcbent->type) {
-               case OUTPUT_ANALOG:
+               case DCB_OUTPUT_ANALOG:
                        ret = nv04_dac_create(connector, dcbent);
                        break;
-               case OUTPUT_LVDS:
-               case OUTPUT_TMDS:
+               case DCB_OUTPUT_LVDS:
+               case DCB_OUTPUT_TMDS:
                        ret = nv04_dfp_create(connector, dcbent);
                        break;
-               case OUTPUT_TV:
+               case DCB_OUTPUT_TV:
                        if (dcbent->location == DCB_LOC_ON_CHIP)
                                ret = nv17_tv_create(connector, dcbent);
                        else
                                ret = nv04_tv_create(connector, dcbent);
                        break;
                default:
-                       NV_WARN(dev, "DCB type %d not known\n", dcbent->type);
+                       NV_WARN(drm, "DCB type %d not known\n", dcbent->type);
                        continue;
                }
  
        list_for_each_entry_safe(connector, ct,
                                 &dev->mode_config.connector_list, head) {
                if (!connector->encoder_ids[0]) {
-                       NV_WARN(dev, "%s has no encoders, removing\n",
+                       NV_WARN(drm, "%s has no encoders, removing\n",
                                drm_get_connector_name(connector));
                        connector->funcs->destroy(connector);
                }
                func->save(encoder);
        }
  
-       nouveau_irq_register(dev, 24, nv04_vblank_crtc0_isr);
-       nouveau_irq_register(dev, 25, nv04_vblank_crtc1_isr);
        return 0;
  }
  
  void
  nv04_display_destroy(struct drm_device *dev)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nv04_display *disp = nv04_display(dev);
        struct drm_encoder *encoder;
        struct drm_crtc *crtc;
  
-       NV_DEBUG_KMS(dev, "\n");
-       nouveau_irq_unregister(dev, 24);
-       nouveau_irq_unregister(dev, 25);
+       NV_DEBUG(drm, "\n");
  
        /* Turn every CRTC off. */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                crtc->funcs->restore(crtc);
  
        nouveau_hw_save_vga_fonts(dev, 0);
+       nouveau_display(dev)->priv = NULL;
+       kfree(disp);
  }
  
  int
@@@ -257,17 -199,3 +198,3 @@@ nv04_display_fini(struct drm_device *de
        if (nv_two_heads(dev))
                NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0);
  }
- static void
- nv04_vblank_crtc0_isr(struct drm_device *dev)
- {
-       nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK);
-       drm_handle_vblank(dev, 0);
- }
- static void
- nv04_vblank_crtc1_isr(struct drm_device *dev)
- {
-       nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK);
-       drm_handle_vblank(dev, 1);
- }
   * Authors: Ben Skeggs
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_reg.h"
  #include "nouveau_hw.h"
  #include "nouveau_pm.h"
  
+ #include <subdev/bios/pll.h>
+ #include <subdev/clock.h>
+ #include <subdev/timer.h>
  int
  nv04_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
  {
@@@ -46,7 -51,7 +51,7 @@@
  }
  
  struct nv04_pm_clock {
-       struct pll_lims pll;
+       struct nvbios_pll pll;
        struct nouveau_pll_vals calc;
  };
  
@@@ -58,13 -63,16 +63,16 @@@ struct nv04_pm_state 
  static int
  calc_pll(struct drm_device *dev, u32 id, int khz, struct nv04_pm_clock *clk)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_bios *bios = nouveau_bios(device);
+       struct nouveau_clock *pclk = nouveau_clock(device);
        int ret;
  
-       ret = get_pll_limits(dev, id, &clk->pll);
+       ret = nvbios_pll_parse(bios, id, &clk->pll);
        if (ret)
                return ret;
  
-       ret = nouveau_calc_pll_mnp(dev, &clk->pll, khz, &clk->calc);
+       ret = pclk->pll_calc(pclk, &clk->pll, khz, &clk->calc);
        if (!ret)
                return -EINVAL;
  
@@@ -100,37 -108,38 +108,38 @@@ error
  static void
  prog_pll(struct drm_device *dev, struct nv04_pm_clock *clk)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_clock *pclk = nouveau_clock(device);
        u32 reg = clk->pll.reg;
  
        /* thank the insane nouveau_hw_setpll() interface for this */
-       if (dev_priv->card_type >= NV_40)
+       if (device->card_type >= NV_40)
                reg += 4;
  
-       nouveau_hw_setpll(dev, reg, &clk->calc);
+       pclk->pll_prog(pclk, reg, &clk->calc);
  }
  
  int
  nv04_pm_clocks_set(struct drm_device *dev, void *pre_state)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_timer *ptimer = nouveau_timer(device);
        struct nv04_pm_state *state = pre_state;
  
        prog_pll(dev, &state->core);
  
        if (state->memory.pll.reg) {
                prog_pll(dev, &state->memory);
-               if (dev_priv->card_type < NV_30) {
-                       if (dev_priv->card_type == NV_20)
-                               nv_mask(dev, 0x1002c4, 0, 1 << 20);
+               if (device->card_type < NV_30) {
+                       if (device->card_type == NV_20)
+                               nv_mask(device, 0x1002c4, 0, 1 << 20);
  
                        /* Reset the DLLs */
-                       nv_mask(dev, 0x1002c0, 0, 1 << 8);
+                       nv_mask(device, 0x1002c0, 0, 1 << 8);
                }
        }
  
-       ptimer->init(dev);
+       nv_ofuncs(ptimer)->init(nv_object(ptimer));
  
        kfree(state);
        return 0;
   *
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_reg.h"
  #include "nouveau_encoder.h"
  #include "nouveau_connector.h"
  #include "nouveau_crtc.h"
  #include "nouveau_hw.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drm_crtc_helper.h>
  
 -#include "i2c/ch7006.h"
 +#include <drm/i2c/ch7006.h>
  
+ #include <subdev/i2c.h>
  static struct i2c_board_info nv04_tv_encoder_info[] = {
        {
                I2C_BOARD_INFO("ch7006", 0x75),
  
  int nv04_tv_identify(struct drm_device *dev, int i2c_index)
  {
-       return nouveau_i2c_identify(dev, "TV encoder", nv04_tv_encoder_info,
-                                   NULL, i2c_index);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
+       return i2c->identify(i2c, i2c_index, "TV encoder",
+                            nv04_tv_encoder_info, NULL);
  }
  
  
  static void nv04_tv_dpms(struct drm_encoder *encoder, int mode)
  {
        struct drm_device *dev = encoder->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nv04_mode_state *state = &dev_priv->mode_reg;
+       struct nv04_mode_state *state = &nv04_display(dev)->mode_reg;
        uint8_t crtc1A;
  
-       NV_INFO(dev, "Setting dpms mode %d on TV encoder (output %d)\n",
+       NV_INFO(drm, "Setting dpms mode %d on TV encoder (output %d)\n",
                mode, nv_encoder->dcb->index);
  
        state->pllsel &= ~(PLLSEL_TV_CRTC1_MASK | PLLSEL_TV_CRTC2_MASK);
  
  static void nv04_tv_bind(struct drm_device *dev, int head, bool bind)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nv04_crtc_reg *state = &dev_priv->mode_reg.crtc_reg[head];
+       struct nv04_crtc_reg *state = &nv04_display(dev)->mode_reg.crtc_reg[head];
  
        state->tv_setup = 0;
  
@@@ -133,9 -138,8 +138,8 @@@ static void nv04_tv_mode_set(struct drm
                             struct drm_display_mode *adjusted_mode)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
-       struct nv04_crtc_reg *regp = &dev_priv->mode_reg.crtc_reg[nv_crtc->index];
+       struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index];
  
        regp->tv_htotal = adjusted_mode->htotal;
        regp->tv_vtotal = adjusted_mode->vtotal;
@@@ -157,12 -161,13 +161,13 @@@ static void nv04_tv_commit(struct drm_e
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_device *dev = encoder->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
        struct drm_encoder_helper_funcs *helper = encoder->helper_private;
  
        helper->dpms(encoder, DRM_MODE_DPMS_ON);
  
-       NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
+       NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n",
                      drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index,
                      '@' + ffs(nv_encoder->dcb->or));
  }
@@@ -181,15 -186,16 +186,16 @@@ static const struct drm_encoder_funcs n
  };
  
  int
- nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
+ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry)
  {
        struct nouveau_encoder *nv_encoder;
        struct drm_encoder *encoder;
        struct drm_device *dev = connector->dev;
        struct drm_encoder_helper_funcs *hfuncs;
        struct drm_encoder_slave_funcs *sfuncs;
-       struct nouveau_i2c_chan *i2c =
-               nouveau_i2c_find(dev, entry->i2c_index);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
+       struct nouveau_i2c_port *port = i2c->find(i2c, entry->i2c_index);
        int type, ret;
  
        /* Ensure that we can talk to this encoder */
  
        /* Run the slave-specific initialization */
        ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
-                                  &i2c->adapter, &nv04_tv_encoder_info[type]);
+                                  &port->adapter, &nv04_tv_encoder_info[type]);
        if (ret < 0)
                goto fail_cleanup;
  
   *
   */
  
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_reg.h"
  #include "nouveau_encoder.h"
  #include "nouveau_connector.h"
  #include "nouveau_crtc.h"
- #include "nouveau_gpio.h"
  #include "nouveau_hw.h"
  #include "nv17_tv.h"
  
+ #include <core/device.h>
+ #include <subdev/bios/gpio.h>
+ #include <subdev/gpio.h>
+ MODULE_PARM_DESC(tv_norm, "Default TV norm.\n"
+                "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n"
+                "\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n"
+                "\t\tDefault: PAL\n"
+                "\t\t*NOTE* Ignored for cards with external TV encoders.");
+ static char *nouveau_tv_norm;
+ module_param_named(tv_norm, nouveau_tv_norm, charp, 0400);
  static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
        uint32_t testval, regoffset = nv04_dac_output_offset(encoder);
        uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end,
                fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c;
  
  #define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20)
        testval = RGB_TEST_DATA(0x82, 0xeb, 0x82);
-       if (dev_priv->vbios.tvdactestval)
-               testval = dev_priv->vbios.tvdactestval;
+       if (drm->vbios.tvdactestval)
+               testval = drm->vbios.tvdactestval;
  
        dacclk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset);
        head = (dacclk & 0x100) >> 8;
  
        /* Save the previous state. */
-       gpio1 = nouveau_gpio_func_get(dev, DCB_GPIO_TVDAC1);
-       gpio0 = nouveau_gpio_func_get(dev, DCB_GPIO_TVDAC0);
+       gpio1 = gpio->get(gpio, 0, DCB_GPIO_TVDAC1, 0xff);
+       gpio0 = gpio->get(gpio, 0, DCB_GPIO_TVDAC0, 0xff);
        fp_htotal = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL);
        fp_hsync_start = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START);
        fp_hsync_end = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END);
@@@ -65,8 -79,8 +79,8 @@@
        ctv_6c = NVReadRAMDAC(dev, head, 0x680c6c);
  
        /* Prepare the DAC for load detection.  */
-       nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, true);
-       nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, true);
+       gpio->set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, true);
+       gpio->set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, true);
  
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343);
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047);
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end);
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start);
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal);
-       nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, gpio1);
-       nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, gpio0);
+       gpio->set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, gpio1);
+       gpio->set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, gpio0);
  
        return sample;
  }
  static bool
  get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_object *device = drm->device;
        /* Zotac FX5200 */
-       if (nv_match_device(dev, 0x0322, 0x19da, 0x1035) ||
-           nv_match_device(dev, 0x0322, 0x19da, 0x2035)) {
+       if (nv_device_match(device, 0x0322, 0x19da, 0x1035) ||
+           nv_device_match(device, 0x0322, 0x19da, 0x2035)) {
                *pin_mask = 0xc;
                return false;
        }
  
        /* MSI nForce2 IGP */
-       if (nv_match_device(dev, 0x01f0, 0x1462, 0x5710)) {
+       if (nv_device_match(device, 0x01f0, 0x1462, 0x5710)) {
                *pin_mask = 0xc;
                return false;
        }
@@@ -140,18 -157,18 +157,18 @@@ static enum drm_connector_statu
  nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct drm_mode_config *conf = &dev->mode_config;
        struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
-       struct dcb_entry *dcb = tv_enc->base.dcb;
+       struct dcb_output *dcb = tv_enc->base.dcb;
        bool reliable = get_tv_detect_quirks(dev, &tv_enc->pin_mask);
  
        if (nv04_dac_in_use(encoder))
                return connector_status_disconnected;
  
        if (reliable) {
-               if (dev_priv->chipset == 0x42 ||
-                   dev_priv->chipset == 0x43)
+               if (nv_device(drm->device)->chipset == 0x42 ||
+                   nv_device(drm->device)->chipset == 0x43)
                        tv_enc->pin_mask =
                                nv42_tv_sample_load(encoder) >> 28 & 0xe;
                else
        if (!reliable) {
                return connector_status_unknown;
        } else if (tv_enc->subconnector) {
-               NV_INFO(dev, "Load detected on output %c\n",
+               NV_INFO(drm, "Load detected on output %c\n",
                        '@' + ffs(dcb->or));
                return connector_status_connected;
        } else {
@@@ -357,6 -374,8 +374,8 @@@ static bool nv17_tv_mode_fixup(struct d
  static void  nv17_tv_dpms(struct drm_encoder *encoder, int mode)
  {
        struct drm_device *dev = encoder->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
        struct nv17_tv_state *regs = &to_tv_enc(encoder)->state;
        struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
  
                return;
        nouveau_encoder(encoder)->last_dpms = mode;
  
-       NV_INFO(dev, "Setting dpms mode %d on TV encoder (output %d)\n",
+       NV_INFO(drm, "Setting dpms mode %d on TV encoder (output %d)\n",
                 mode, nouveau_encoder(encoder)->dcb->index);
  
        regs->ptv_200 &= ~1;
  
        nv_load_ptv(dev, regs, 200);
  
-       nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON);
-       nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON);
+       gpio->set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, mode == DRM_MODE_DPMS_ON);
+       gpio->set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, mode == DRM_MODE_DPMS_ON);
  
        nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);
  }
  static void nv17_tv_prepare(struct drm_encoder *encoder)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct drm_encoder_helper_funcs *helper = encoder->helper_private;
        struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
        int head = nouveau_crtc(encoder->crtc)->index;
-       uint8_t *cr_lcd = &dev_priv->mode_reg.crtc_reg[head].CRTC[
+       uint8_t *cr_lcd = &nv04_display(dev)->mode_reg.crtc_reg[head].CRTC[
                                                        NV_CIO_CRE_LCD__INDEX];
        uint32_t dacclk_off = NV_PRAMDAC_DACCLK +
                                        nv04_dac_output_offset(encoder);
                struct drm_encoder *enc;
  
                list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
-                       struct dcb_entry *dcb = nouveau_encoder(enc)->dcb;
+                       struct dcb_output *dcb = nouveau_encoder(enc)->dcb;
  
-                       if ((dcb->type == OUTPUT_TMDS ||
-                            dcb->type == OUTPUT_LVDS) &&
+                       if ((dcb->type == DCB_OUTPUT_TMDS ||
+                            dcb->type == DCB_OUTPUT_LVDS) &&
                             !enc->crtc &&
                             nv04_dfp_get_bound_head(dev, dcb) == head) {
                                nv04_dfp_bind_head(dev, dcb, head ^ 1,
-                                               dev_priv->vbios.fp.dual_link);
+                                               drm->vbios.fp.dual_link);
                        }
                }
  
        /* Set the DACCLK register */
        dacclk = (NVReadRAMDAC(dev, 0, dacclk_off) & ~0x30) | 0x1;
  
-       if (dev_priv->card_type == NV_40)
+       if (nv_device(drm->device)->card_type == NV_40)
                dacclk |= 0x1a << 16;
  
        if (tv_norm->kind == CTV_ENC_MODE) {
@@@ -453,9 -472,9 +472,9 @@@ static void nv17_tv_mode_set(struct drm
                             struct drm_display_mode *adjusted_mode)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        int head = nouveau_crtc(encoder->crtc)->index;
-       struct nv04_crtc_reg *regs = &dev_priv->mode_reg.crtc_reg[head];
+       struct nv04_crtc_reg *regs = &nv04_display(dev)->mode_reg.crtc_reg[head];
        struct nv17_tv_state *tv_regs = &to_tv_enc(encoder)->state;
        struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
        int i;
                        tv_regs->ptv_614 = 0x13;
                }
  
-               if (dev_priv->card_type >= NV_30) {
+               if (nv_device(drm->device)->card_type >= NV_30) {
                        tv_regs->ptv_500 = 0xe8e0;
                        tv_regs->ptv_504 = 0x1710;
                        tv_regs->ptv_604 = 0x0;
  static void nv17_tv_commit(struct drm_encoder *encoder)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_encoder_helper_funcs *helper = encoder->helper_private;
        nv17_tv_state_load(dev, &to_tv_enc(encoder)->state);
  
        /* This could use refinement for flatpanels, but it should work */
-       if (dev_priv->chipset < 0x44)
+       if (nv_device(drm->device)->chipset < 0x44)
                NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL +
                                        nv04_dac_output_offset(encoder),
                                        0xf0000000);
  
        helper->dpms(encoder, DRM_MODE_DPMS_ON);
  
-       NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
+       NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n",
                drm_get_connector_name(
                        &nouveau_encoder_connector_get(nv_encoder)->base),
                nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
@@@ -630,9 -649,10 +649,10 @@@ static int nv17_tv_create_resources(str
                                    struct drm_connector *connector)
  {
        struct drm_device *dev = encoder->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct drm_mode_config *conf = &dev->mode_config;
        struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
-       struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+       struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
        int num_tv_norms = dcb->tvconf.has_component_output ? NUM_TV_NORMS :
                                                        NUM_LD_TV_NORMS;
        int i;
                }
  
                if (i == num_tv_norms)
-                       NV_WARN(dev, "Invalid TV norm setting \"%s\"\n",
+                       NV_WARN(drm, "Invalid TV norm setting \"%s\"\n",
                                nouveau_tv_norm);
        }
  
@@@ -759,8 -779,6 +779,6 @@@ static void nv17_tv_destroy(struct drm_
  {
        struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
  
-       NV_DEBUG_KMS(encoder->dev, "\n");
        drm_encoder_cleanup(encoder);
        kfree(tv_enc);
  }
@@@ -788,7 -806,7 +806,7 @@@ static struct drm_encoder_funcs nv17_tv
  };
  
  int
- nv17_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
+ nv17_tv_create(struct drm_connector *connector, struct dcb_output *entry)
  {
        struct drm_device *dev = connector->dev;
        struct drm_encoder *encoder;
@@@ -24,9 -24,9 +24,9 @@@
   *
   */
  
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
  #include "nouveau_encoder.h"
  #include "nouveau_crtc.h"
  #include "nouveau_hw.h"
@@@ -543,10 -543,9 +543,9 @@@ void nv17_tv_update_rescaler(struct drm
  void nv17_ctv_update_rescaler(struct drm_encoder *encoder)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
        int head = nouveau_crtc(encoder->crtc)->index;
-       struct nv04_crtc_reg *regs = &dev_priv->mode_reg.crtc_reg[head];
+       struct nv04_crtc_reg *regs = &nv04_display(dev)->mode_reg.crtc_reg[head];
        struct drm_display_mode *crtc_mode = &encoder->crtc->mode;
        struct drm_display_mode *output_mode =
                &get_tv_norm(encoder)->ctv_enc_mode.mode;
   * Authors: Ben Skeggs
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
  #include "nouveau_bios.h"
  #include "nouveau_pm.h"
  #include "nouveau_hw.h"
- #include "nouveau_fifo.h"
+ #include <subdev/bios/pll.h>
+ #include <subdev/clock.h>
+ #include <subdev/timer.h>
+ #include <engine/fifo.h>
  
  #define min2(a,b) ((a) < (b) ? (a) : (b))
  
  static u32
  read_pll_1(struct drm_device *dev, u32 reg)
  {
-       u32 ctrl = nv_rd32(dev, reg + 0x00);
+       struct nouveau_device *device = nouveau_dev(dev);
+       u32 ctrl = nv_rd32(device, reg + 0x00);
        int P = (ctrl & 0x00070000) >> 16;
        int N = (ctrl & 0x0000ff00) >> 8;
        int M = (ctrl & 0x000000ff) >> 0;
@@@ -49,8 -55,9 +55,9 @@@
  static u32
  read_pll_2(struct drm_device *dev, u32 reg)
  {
-       u32 ctrl = nv_rd32(dev, reg + 0x00);
-       u32 coef = nv_rd32(dev, reg + 0x04);
+       struct nouveau_device *device = nouveau_dev(dev);
+       u32 ctrl = nv_rd32(device, reg + 0x00);
+       u32 coef = nv_rd32(device, reg + 0x04);
        int N2 = (coef & 0xff000000) >> 24;
        int M2 = (coef & 0x00ff0000) >> 16;
        int N1 = (coef & 0x0000ff00) >> 8;
@@@ -89,7 -96,8 +96,8 @@@ read_clk(struct drm_device *dev, u32 sr
  int
  nv40_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
  {
-       u32 ctrl = nv_rd32(dev, 0x00c040);
+       struct nouveau_device *device = nouveau_dev(dev);
+       u32 ctrl = nv_rd32(device, 0x00c040);
  
        perflvl->core   = read_clk(dev, (ctrl & 0x00000003) >> 0);
        perflvl->shader = read_clk(dev, (ctrl & 0x00000030) >> 4);
@@@ -107,27 -115,30 +115,30 @@@ struct nv40_pm_state 
  };
  
  static int
- nv40_calc_pll(struct drm_device *dev, u32 reg, struct pll_lims *pll,
+ nv40_calc_pll(struct drm_device *dev, u32 reg, struct nvbios_pll *pll,
              u32 clk, int *N1, int *M1, int *N2, int *M2, int *log2P)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_bios *bios = nouveau_bios(device);
+       struct nouveau_clock *pclk = nouveau_clock(device);
        struct nouveau_pll_vals coef;
        int ret;
  
-       ret = get_pll_limits(dev, reg, pll);
+       ret = nvbios_pll_parse(bios, reg, pll);
        if (ret)
                return ret;
  
-       if (clk < pll->vco1.maxfreq)
-               pll->vco2.maxfreq = 0;
+       if (clk < pll->vco1.max_freq)
+               pll->vco2.max_freq = 0;
  
-       ret = nouveau_calc_pll_mnp(dev, pll, clk, &coef);
+       pclk->pll_calc(pclk, pll, clk, &coef);
        if (ret == 0)
                return -ERANGE;
  
        *N1 = coef.N1;
        *M1 = coef.M1;
        if (N2 && M2) {
-               if (pll->vco2.maxfreq) {
+               if (pll->vco2.max_freq) {
                        *N2 = coef.N2;
                        *M2 = coef.M2;
                } else {
@@@ -143,7 -154,7 +154,7 @@@ void 
  nv40_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
  {
        struct nv40_pm_state *info;
-       struct pll_lims pll;
+       struct nvbios_pll pll;
        int N1, N2, M1, M2, log2P;
        int ret;
  
                goto out;
  
        info->mpll_ctrl  = 0x80000000 | (log2P << 16);
-       info->mpll_ctrl |= min2(pll.log2p_bias + log2P, pll.max_log2p) << 20;
+       info->mpll_ctrl |= min2(pll.bias_p + log2P, pll.max_p) << 20;
        if (N2 == M2) {
                info->mpll_ctrl |= 0x00000100;
                info->mpll_coef  = (N1 << 8) | M1;
@@@ -212,12 -223,13 +223,13 @@@ static boo
  nv40_pm_gr_idle(void *data)
  {
        struct drm_device *dev = data;
+       struct nouveau_device *device = nouveau_dev(dev);
  
-       if ((nv_rd32(dev, 0x400760) & 0x000000f0) >> 4 !=
-           (nv_rd32(dev, 0x400760) & 0x0000000f))
+       if ((nv_rd32(device, 0x400760) & 0x000000f0) >> 4 !=
+           (nv_rd32(device, 0x400760) & 0x0000000f))
                return false;
  
-       if (nv_rd32(dev, 0x400700))
+       if (nv_rd32(device, 0x400700))
                return false;
  
        return true;
  int
  nv40_pm_clocks_set(struct drm_device *dev, void *pre_state)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_fifo *pfifo = nouveau_fifo(device);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nv40_pm_state *info = pre_state;
        unsigned long flags;
        struct bit_entry M;
  
        /* determine which CRTCs are active, fetch VGA_SR1 for each */
        for (i = 0; i < 2; i++) {
-               u32 vbl = nv_rd32(dev, 0x600808 + (i * 0x2000));
+               u32 vbl = nv_rd32(device, 0x600808 + (i * 0x2000));
                u32 cnt = 0;
                do {
-                       if (vbl != nv_rd32(dev, 0x600808 + (i * 0x2000))) {
-                               nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01);
-                               sr1[i] = nv_rd08(dev, 0x0c03c5 + (i * 0x2000));
+                       if (vbl != nv_rd32(device, 0x600808 + (i * 0x2000))) {
+                               nv_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01);
+                               sr1[i] = nv_rd08(device, 0x0c03c5 + (i * 0x2000));
                                if (!(sr1[i] & 0x20))
                                        crtc_mask |= (1 << i);
                                break;
        }
  
        /* halt and idle engines */
-       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
-       if (!nv_wait(dev, 0x002500, 0x00000010, 0x00000000))
-               goto resume;
-       nv_mask(dev, 0x003220, 0x00000001, 0x00000000);
-       if (!nv_wait(dev, 0x003220, 0x00000010, 0x00000000))
-               goto resume;
-       nv_mask(dev, 0x003200, 0x00000001, 0x00000000);
-       nv04_fifo_cache_pull(dev, false);
+       pfifo->pause(pfifo, &flags);
  
-       if (!nv_wait_cb(dev, nv40_pm_gr_idle, dev))
+       if (!nv_wait_cb(device, nv40_pm_gr_idle, dev))
                goto resume;
  
        ret = 0;
  
        /* set engine clocks */
-       nv_mask(dev, 0x00c040, 0x00000333, 0x00000000);
-       nv_wr32(dev, 0x004004, info->npll_coef);
-       nv_mask(dev, 0x004000, 0xc0070100, info->npll_ctrl);
-       nv_mask(dev, 0x004008, 0xc007ffff, info->spll);
+       nv_mask(device, 0x00c040, 0x00000333, 0x00000000);
+       nv_wr32(device, 0x004004, info->npll_coef);
+       nv_mask(device, 0x004000, 0xc0070100, info->npll_ctrl);
+       nv_mask(device, 0x004008, 0xc007ffff, info->spll);
        mdelay(5);
-       nv_mask(dev, 0x00c040, 0x00000333, info->ctrl);
+       nv_mask(device, 0x00c040, 0x00000333, info->ctrl);
  
        if (!info->mpll_ctrl)
                goto resume;
        for (i = 0; i < 2; i++) {
                if (!(crtc_mask & (1 << i)))
                        continue;
-               nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000);
-               nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
-               nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01);
-               nv_wr08(dev, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20);
+               nv_wait(device, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000);
+               nv_wait(device, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
+               nv_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01);
+               nv_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20);
        }
  
        /* prepare ram for reclocking */
-       nv_wr32(dev, 0x1002d4, 0x00000001); /* precharge */
-       nv_wr32(dev, 0x1002d0, 0x00000001); /* refresh */
-       nv_wr32(dev, 0x1002d0, 0x00000001); /* refresh */
-       nv_mask(dev, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */
-       nv_wr32(dev, 0x1002dc, 0x00000001); /* enable self-refresh */
+       nv_wr32(device, 0x1002d4, 0x00000001); /* precharge */
+       nv_wr32(device, 0x1002d0, 0x00000001); /* refresh */
+       nv_wr32(device, 0x1002d0, 0x00000001); /* refresh */
+       nv_mask(device, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */
+       nv_wr32(device, 0x1002dc, 0x00000001); /* enable self-refresh */
  
        /* change the PLL of each memory partition */
-       nv_mask(dev, 0x00c040, 0x0000c000, 0x00000000);
-       switch (dev_priv->chipset) {
+       nv_mask(device, 0x00c040, 0x0000c000, 0x00000000);
+       switch (nv_device(drm->device)->chipset) {
        case 0x40:
        case 0x45:
        case 0x41:
        case 0x42:
        case 0x47:
-               nv_mask(dev, 0x004044, 0xc0771100, info->mpll_ctrl);
-               nv_mask(dev, 0x00402c, 0xc0771100, info->mpll_ctrl);
-               nv_wr32(dev, 0x004048, info->mpll_coef);
-               nv_wr32(dev, 0x004030, info->mpll_coef);
+               nv_mask(device, 0x004044, 0xc0771100, info->mpll_ctrl);
+               nv_mask(device, 0x00402c, 0xc0771100, info->mpll_ctrl);
+               nv_wr32(device, 0x004048, info->mpll_coef);
+               nv_wr32(device, 0x004030, info->mpll_coef);
        case 0x43:
        case 0x49:
        case 0x4b:
-               nv_mask(dev, 0x004038, 0xc0771100, info->mpll_ctrl);
-               nv_wr32(dev, 0x00403c, info->mpll_coef);
+               nv_mask(device, 0x004038, 0xc0771100, info->mpll_ctrl);
+               nv_wr32(device, 0x00403c, info->mpll_coef);
        default:
-               nv_mask(dev, 0x004020, 0xc0771100, info->mpll_ctrl);
-               nv_wr32(dev, 0x004024, info->mpll_coef);
+               nv_mask(device, 0x004020, 0xc0771100, info->mpll_ctrl);
+               nv_wr32(device, 0x004024, info->mpll_coef);
                break;
        }
        udelay(100);
-       nv_mask(dev, 0x00c040, 0x0000c000, 0x0000c000);
+       nv_mask(device, 0x00c040, 0x0000c000, 0x0000c000);
  
        /* re-enable normal operation of memory controller */
-       nv_wr32(dev, 0x1002dc, 0x00000000);
-       nv_mask(dev, 0x100210, 0x80000000, 0x80000000);
+       nv_wr32(device, 0x1002dc, 0x00000000);
+       nv_mask(device, 0x100210, 0x80000000, 0x80000000);
        udelay(100);
  
        /* execute memory reset script from vbios */
        if (!bit_table(dev, 'M', &M))
-               nouveau_bios_init_exec(dev, ROM16(M.data[0]));
+               nouveau_bios_run_init_table(dev, ROM16(M.data[0]), NULL, 0);
  
        /* make sure we're in vblank (hopefully the same one as before), and
         * then re-enable crtc memory access
        for (i = 0; i < 2; i++) {
                if (!(crtc_mask & (1 << i)))
                        continue;
-               nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
-               nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01);
-               nv_wr08(dev, 0x0c03c5 + (i * 0x2000), sr1[i]);
+               nv_wait(device, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
+               nv_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01);
+               nv_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i]);
        }
  
        /* resume engines */
  resume:
-       nv_wr32(dev, 0x003250, 0x00000001);
-       nv_mask(dev, 0x003220, 0x00000001, 0x00000001);
-       nv_wr32(dev, 0x003200, 0x00000001);
-       nv_wr32(dev, 0x002500, 0x00000001);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+       pfifo->start(pfifo, &flags);
        kfree(info);
        return ret;
  }
- int
- nv40_pm_pwm_get(struct drm_device *dev, int line, u32 *divs, u32 *duty)
- {
-       if (line == 2) {
-               u32 reg = nv_rd32(dev, 0x0010f0);
-               if (reg & 0x80000000) {
-                       *duty = (reg & 0x7fff0000) >> 16;
-                       *divs = (reg & 0x00007fff);
-                       return 0;
-               }
-       } else
-       if (line == 9) {
-               u32 reg = nv_rd32(dev, 0x0015f4);
-               if (reg & 0x80000000) {
-                       *divs = nv_rd32(dev, 0x0015f8);
-                       *duty = (reg & 0x7fffffff);
-                       return 0;
-               }
-       } else {
-               NV_ERROR(dev, "unknown pwm ctrl for gpio %d\n", line);
-               return -ENODEV;
-       }
-       return -EINVAL;
- }
- int
- nv40_pm_pwm_set(struct drm_device *dev, int line, u32 divs, u32 duty)
- {
-       if (line == 2) {
-               nv_wr32(dev, 0x0010f0, 0x80000000 | (duty << 16) | divs);
-       } else
-       if (line == 9) {
-               nv_wr32(dev, 0x0015f8, divs);
-               nv_wr32(dev, 0x0015f4, duty | 0x80000000);
-       } else {
-               NV_ERROR(dev, "unknown pwm ctrl for gpio %d\n", line);
-               return -ENODEV;
-       }
-       return 0;
- }
   *
   */
  
 -#include "drmP.h"
 -#include "drm_mode.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
  
- #define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
  #include "nouveau_reg.h"
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_dma.h"
+ #include "nouveau_gem.h"
  #include "nouveau_hw.h"
  #include "nouveau_encoder.h"
  #include "nouveau_crtc.h"
- #include "nouveau_fb.h"
  #include "nouveau_connector.h"
  #include "nv50_display.h"
  
+ #include <subdev/clock.h>
  static void
  nv50_crtc_lut_load(struct drm_crtc *crtc)
  {
+       struct nouveau_drm *drm = nouveau_drm(crtc->dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
        int i;
  
-       NV_DEBUG_KMS(crtc->dev, "\n");
+       NV_DEBUG(drm, "\n");
  
        for (i = 0; i < 256; i++) {
                writew(nv_crtc->lut.r[i] >> 2, lut + 8*i + 0);
@@@ -63,25 -67,25 +66,25 @@@ in
  nv50_crtc_blank(struct nouveau_crtc *nv_crtc, bool blanked)
  {
        struct drm_device *dev = nv_crtc->base.dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_channel *evo = nv50_display(dev)->master;
        int index = nv_crtc->index, ret;
  
-       NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
-       NV_DEBUG_KMS(dev, "%s\n", blanked ? "blanked" : "unblanked");
+       NV_DEBUG(drm, "index %d\n", nv_crtc->index);
+       NV_DEBUG(drm, "%s\n", blanked ? "blanked" : "unblanked");
  
        if (blanked) {
                nv_crtc->cursor.hide(nv_crtc, false);
  
-               ret = RING_SPACE(evo, dev_priv->chipset != 0x50 ? 7 : 5);
+               ret = RING_SPACE(evo, nv_device(drm->device)->chipset != 0x50 ? 7 : 5);
                if (ret) {
-                       NV_ERROR(dev, "no space while blanking crtc\n");
+                       NV_ERROR(drm, "no space while blanking crtc\n");
                        return ret;
                }
                BEGIN_NV04(evo, 0, NV50_EVO_CRTC(index, CLUT_MODE), 2);
                OUT_RING(evo, NV50_EVO_CRTC_CLUT_MODE_BLANK);
                OUT_RING(evo, 0);
-               if (dev_priv->chipset != 0x50) {
+               if (nv_device(drm->device)->chipset != 0x50) {
                        BEGIN_NV04(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1);
                        OUT_RING(evo, NV84_EVO_CRTC_CLUT_DMA_HANDLE_NONE);
                }
@@@ -94,9 -98,9 +97,9 @@@
                else
                        nv_crtc->cursor.hide(nv_crtc, false);
  
-               ret = RING_SPACE(evo, dev_priv->chipset != 0x50 ? 10 : 8);
+               ret = RING_SPACE(evo, nv_device(drm->device)->chipset != 0x50 ? 10 : 8);
                if (ret) {
-                       NV_ERROR(dev, "no space while unblanking crtc\n");
+                       NV_ERROR(drm, "no space while unblanking crtc\n");
                        return ret;
                }
                BEGIN_NV04(evo, 0, NV50_EVO_CRTC(index, CLUT_MODE), 2);
                                NV50_EVO_CRTC_CLUT_MODE_OFF :
                                NV50_EVO_CRTC_CLUT_MODE_ON);
                OUT_RING(evo, nv_crtc->lut.nvbo->bo.offset >> 8);
-               if (dev_priv->chipset != 0x50) {
+               if (nv_device(drm->device)->chipset != 0x50) {
                        BEGIN_NV04(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1);
                        OUT_RING(evo, NvEvoVRAM);
                }
                OUT_RING(evo, nv_crtc->fb.offset >> 8);
                OUT_RING(evo, 0);
                BEGIN_NV04(evo, 0, NV50_EVO_CRTC(index, FB_DMA), 1);
-               if (dev_priv->chipset != 0x50)
+               if (nv_device(drm->device)->chipset != 0x50)
                        if (nv_crtc->fb.tile_flags == 0x7a00 ||
                            nv_crtc->fb.tile_flags == 0xfe00)
                                OUT_RING(evo, NvEvoFB32);
@@@ -173,17 -177,18 +176,18 @@@ static in
  nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update)
  {
        struct drm_device *dev = nv_crtc->base.dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_channel *evo = nv50_display(dev)->master;
        int ret;
        int adj;
        u32 hue, vib;
  
-       NV_DEBUG_KMS(dev, "vibrance = %i, hue = %i\n",
+       NV_DEBUG(drm, "vibrance = %i, hue = %i\n",
                     nv_crtc->color_vibrance, nv_crtc->vibrant_hue);
  
        ret = RING_SPACE(evo, 2 + (update ? 2 : 0));
        if (ret) {
-               NV_ERROR(dev, "no space while setting color vibrance\n");
+               NV_ERROR(drm, "no space while setting color vibrance\n");
                return ret;
        }
  
@@@ -228,17 -233,18 +232,18 @@@ nv50_crtc_set_scale(struct nouveau_crt
        struct nouveau_connector *nv_connector;
        struct drm_crtc *crtc = &nv_crtc->base;
        struct drm_device *dev = crtc->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_channel *evo = nv50_display(dev)->master;
        struct drm_display_mode *umode = &crtc->mode;
        struct drm_display_mode *omode;
        int scaling_mode, ret;
        u32 ctrl = 0, oX, oY;
  
-       NV_DEBUG_KMS(dev, "\n");
+       NV_DEBUG(drm, "\n");
  
        nv_connector = nouveau_crtc_connector_get(nv_crtc);
        if (!nv_connector || !nv_connector->native_mode) {
-               NV_ERROR(dev, "no native mode, forcing panel scaling\n");
+               NV_ERROR(drm, "no native mode, forcing panel scaling\n");
                scaling_mode = DRM_MODE_SCALE_NONE;
        } else {
                scaling_mode = nv_connector->scaling_mode;
  int
  nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct pll_lims pll;
-       uint32_t reg1, reg2;
-       int ret, N1, M1, N2, M2, P;
-       ret = get_pll_limits(dev, PLL_VPLL0 + head, &pll);
-       if (ret)
-               return ret;
-       if (pll.vco2.maxfreq) {
-               ret = nv50_calc_pll(dev, &pll, pclk, &N1, &M1, &N2, &M2, &P);
-               if (ret <= 0)
-                       return 0;
-               NV_DEBUG(dev, "pclk %d out %d NM1 %d %d NM2 %d %d P %d\n",
-                        pclk, ret, N1, M1, N2, M2, P);
-               reg1 = nv_rd32(dev, pll.reg + 4) & 0xff00ff00;
-               reg2 = nv_rd32(dev, pll.reg + 8) & 0x8000ff00;
-               nv_wr32(dev, pll.reg + 0, 0x10000611);
-               nv_wr32(dev, pll.reg + 4, reg1 | (M1 << 16) | N1);
-               nv_wr32(dev, pll.reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
-       } else
-       if (dev_priv->chipset < NV_C0) {
-               ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P);
-               if (ret <= 0)
-                       return 0;
-               NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
-                        pclk, ret, N1, N2, M1, P);
-               reg1 = nv_rd32(dev, pll.reg + 4) & 0xffc00000;
-               nv_wr32(dev, pll.reg + 0, 0x50000610);
-               nv_wr32(dev, pll.reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
-               nv_wr32(dev, pll.reg + 8, N2);
-       } else {
-               ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P);
-               if (ret <= 0)
-                       return 0;
-               NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
-                        pclk, ret, N1, N2, M1, P);
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_clock *clk = nouveau_clock(device);
  
-               nv_mask(dev, pll.reg + 0x0c, 0x00000000, 0x00000100);
-               nv_wr32(dev, pll.reg + 0x04, (P << 16) | (N1 << 8) | M1);
-               nv_wr32(dev, pll.reg + 0x10, N2 << 16);
-       }
-       return 0;
+       return clk->pll_set(clk, PLL_VPLL0 + head, pclk);
  }
  
  static void
  nv50_crtc_destroy(struct drm_crtc *crtc)
  {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+       struct nouveau_drm *drm = nouveau_drm(crtc->dev);
  
-       NV_DEBUG_KMS(crtc->dev, "\n");
+       NV_DEBUG(drm, "\n");
  
        nouveau_bo_unmap(nv_crtc->lut.nvbo);
        nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
@@@ -473,13 -435,15 +434,15 @@@ nv50_crtc_gamma_set(struct drm_crtc *cr
  static void
  nv50_crtc_save(struct drm_crtc *crtc)
  {
-       NV_ERROR(crtc->dev, "!!\n");
+       struct nouveau_drm *drm = nouveau_drm(crtc->dev);
+       NV_ERROR(drm, "!!\n");
  }
  
  static void
  nv50_crtc_restore(struct drm_crtc *crtc)
  {
-       NV_ERROR(crtc->dev, "!!\n");
+       struct nouveau_drm *drm = nouveau_drm(crtc->dev);
+       NV_ERROR(drm, "!!\n");
  }
  
  static const struct drm_crtc_funcs nv50_crtc_funcs = {
@@@ -503,8 -467,9 +466,9 @@@ nv50_crtc_prepare(struct drm_crtc *crtc
  {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct drm_device *dev = crtc->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
-       NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
+       NV_DEBUG(drm, "index %d\n", nv_crtc->index);
  
        nv50_display_flip_stop(crtc);
        drm_vblank_pre_modeset(dev, nv_crtc->index);
@@@ -515,9 -480,10 +479,10 @@@ static voi
  nv50_crtc_commit(struct drm_crtc *crtc)
  {
        struct drm_device *dev = crtc->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
  
-       NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
+       NV_DEBUG(drm, "index %d\n", nv_crtc->index);
  
        nv50_crtc_blank(nv_crtc, false);
        drm_vblank_post_modeset(dev, nv_crtc->index);
@@@ -539,17 -505,17 +504,17 @@@ nv50_crtc_do_mode_set_base(struct drm_c
  {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct drm_device *dev = nv_crtc->base.dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_channel *evo = nv50_display(dev)->master;
        struct drm_framebuffer *drm_fb;
        struct nouveau_framebuffer *fb;
        int ret;
  
-       NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
+       NV_DEBUG(drm, "index %d\n", nv_crtc->index);
  
        /* no fb bound */
        if (!atomic && !crtc->fb) {
-               NV_DEBUG_KMS(dev, "No FB bound\n");
+               NV_DEBUG(drm, "No FB bound\n");
                return 0;
        }
  
        nv_crtc->fb.offset = fb->nvbo->bo.offset;
        nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo);
        nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8;
-       if (!nv_crtc->fb.blanked && dev_priv->chipset != 0x50) {
+       if (!nv_crtc->fb.blanked && nv_device(drm->device)->chipset != 0x50) {
                ret = RING_SPACE(evo, 2);
                if (ret)
                        return ret;
@@@ -737,10 -703,11 +702,11 @@@ static const struct drm_crtc_helper_fun
  int
  nv50_crtc_create(struct drm_device *dev, int index)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_crtc *nv_crtc = NULL;
        int ret, i;
  
-       NV_DEBUG_KMS(dev, "\n");
+       NV_DEBUG(drm, "\n");
  
        nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
        if (!nv_crtc)
   *
   */
  
 -#include "drmP.h"
 -#include "drm_mode.h"
 +#include <drm/drmP.h>
  
- #define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
- #include "nouveau_reg.h"
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_dma.h"
  #include "nouveau_crtc.h"
  #include "nv50_display.h"
  
@@@ -36,22 -36,22 +35,22 @@@ static voi
  nv50_cursor_show(struct nouveau_crtc *nv_crtc, bool update)
  {
        struct drm_device *dev = nv_crtc->base.dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_channel *evo = nv50_display(dev)->master;
        int ret;
  
-       NV_DEBUG_KMS(dev, "\n");
+       NV_DEBUG(drm, "\n");
  
        if (update && nv_crtc->cursor.visible)
                return;
  
-       ret = RING_SPACE(evo, (dev_priv->chipset != 0x50 ? 5 : 3) + update * 2);
+       ret = RING_SPACE(evo, (nv_device(drm->device)->chipset != 0x50 ? 5 : 3) + update * 2);
        if (ret) {
-               NV_ERROR(dev, "no space while unhiding cursor\n");
+               NV_ERROR(drm, "no space while unhiding cursor\n");
                return;
        }
  
-       if (dev_priv->chipset != 0x50) {
+       if (nv_device(drm->device)->chipset != 0x50) {
                BEGIN_NV04(evo, 0, NV84_EVO_CRTC(nv_crtc->index, CURSOR_DMA), 1);
                OUT_RING(evo, NvEvoVRAM);
        }
@@@ -71,24 -71,24 +70,24 @@@ static voi
  nv50_cursor_hide(struct nouveau_crtc *nv_crtc, bool update)
  {
        struct drm_device *dev = nv_crtc->base.dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_channel *evo = nv50_display(dev)->master;
        int ret;
  
-       NV_DEBUG_KMS(dev, "\n");
+       NV_DEBUG(drm, "\n");
  
        if (update && !nv_crtc->cursor.visible)
                return;
  
-       ret = RING_SPACE(evo, (dev_priv->chipset != 0x50 ? 5 : 3) + update * 2);
+       ret = RING_SPACE(evo, (nv_device(drm->device)->chipset != 0x50 ? 5 : 3) + update * 2);
        if (ret) {
-               NV_ERROR(dev, "no space while hiding cursor\n");
+               NV_ERROR(drm, "no space while hiding cursor\n");
                return;
        }
        BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CURSOR_CTRL), 2);
        OUT_RING(evo, NV50_EVO_CRTC_CURSOR_CTRL_HIDE);
        OUT_RING(evo, 0);
-       if (dev_priv->chipset != 0x50) {
+       if (nv_device(drm->device)->chipset != 0x50) {
                BEGIN_NV04(evo, 0, NV84_EVO_CRTC(nv_crtc->index, CURSOR_DMA), 1);
                OUT_RING(evo, NV84_EVO_CRTC_CURSOR_DMA_HANDLE_NONE);
        }
  static void
  nv50_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
  {
-       struct drm_device *dev = nv_crtc->base.dev;
+       struct nouveau_device *device = nouveau_dev(nv_crtc->base.dev);
  
        nv_crtc->cursor_saved_x = x; nv_crtc->cursor_saved_y = y;
-       nv_wr32(dev, NV50_PDISPLAY_CURSOR_USER_POS(nv_crtc->index),
+       nv_wr32(device, NV50_PDISPLAY_CURSOR_USER_POS(nv_crtc->index),
                ((y & 0xFFFF) << 16) | (x & 0xFFFF));
        /* Needed to make the cursor move. */
-       nv_wr32(dev, NV50_PDISPLAY_CURSOR_USER_POS_CTRL(nv_crtc->index), 0);
+       nv_wr32(device, NV50_PDISPLAY_CURSOR_USER_POS_CTRL(nv_crtc->index), 0);
  }
  
  static void
  nv50_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
  {
-       NV_DEBUG_KMS(nv_crtc->base.dev, "\n");
        if (offset == nv_crtc->cursor.offset)
                return;
  
   *
   */
  
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
  
  #define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
  #include "nouveau_reg.h"
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
  #include "nouveau_dma.h"
  #include "nouveau_encoder.h"
  #include "nouveau_connector.h"
  #include "nouveau_crtc.h"
  #include "nv50_display.h"
  
+ #include <subdev/timer.h>
  static void
  nv50_dac_disconnect(struct drm_encoder *encoder)
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_device *dev = encoder->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_channel *evo = nv50_display(dev)->master;
        int ret;
  
                return;
        nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true);
  
-       NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or);
+       NV_DEBUG(drm, "Disconnecting DAC %d\n", nv_encoder->or);
  
        ret = RING_SPACE(evo, 4);
        if (ret) {
-               NV_ERROR(dev, "no space while disconnecting DAC\n");
+               NV_ERROR(drm, "no space while disconnecting DAC\n");
                return;
        }
        BEGIN_NV04(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1);
@@@ -67,43 -70,43 +70,43 @@@ static enum drm_connector_statu
  nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-       struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(encoder->dev);
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
        enum drm_connector_status status = connector_status_disconnected;
        uint32_t dpms_state, load_pattern, load_state;
        int or = nv_encoder->or;
  
-       nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(or), 0x00000001);
-       dpms_state = nv_rd32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or));
+       nv_wr32(device, NV50_PDISPLAY_DAC_CLK_CTRL1(or), 0x00000001);
+       dpms_state = nv_rd32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or));
  
-       nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+       nv_wr32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
                0x00150000 | NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
-       if (!nv_wait(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+       if (!nv_wait(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
                     NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
-               NV_ERROR(dev, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
-               NV_ERROR(dev, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
-                         nv_rd32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or)));
+               NV_ERROR(drm, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
+               NV_ERROR(drm, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
+                         nv_rd32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or)));
                return status;
        }
  
        /* Use bios provided value if possible. */
-       if (dev_priv->vbios.dactestval) {
-               load_pattern = dev_priv->vbios.dactestval;
-               NV_DEBUG_KMS(dev, "Using bios provided load_pattern of %d\n",
+       if (drm->vbios.dactestval) {
+               load_pattern = drm->vbios.dactestval;
+               NV_DEBUG(drm, "Using bios provided load_pattern of %d\n",
                          load_pattern);
        } else {
                load_pattern = 340;
-               NV_DEBUG_KMS(dev, "Using default load_pattern of %d\n",
+               NV_DEBUG(drm, "Using default load_pattern of %d\n",
                         load_pattern);
        }
  
-       nv_wr32(dev, NV50_PDISPLAY_DAC_LOAD_CTRL(or),
+       nv_wr32(device, NV50_PDISPLAY_DAC_LOAD_CTRL(or),
                NV50_PDISPLAY_DAC_LOAD_CTRL_ACTIVE | load_pattern);
        mdelay(45); /* give it some time to process */
-       load_state = nv_rd32(dev, NV50_PDISPLAY_DAC_LOAD_CTRL(or));
+       load_state = nv_rd32(device, NV50_PDISPLAY_DAC_LOAD_CTRL(or));
  
-       nv_wr32(dev, NV50_PDISPLAY_DAC_LOAD_CTRL(or), 0);
-       nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or), dpms_state |
+       nv_wr32(device, NV50_PDISPLAY_DAC_LOAD_CTRL(or), 0);
+       nv_wr32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or), dpms_state |
                NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
  
        if ((load_state & NV50_PDISPLAY_DAC_LOAD_CTRL_PRESENT) ==
                status = connector_status_connected;
  
        if (status == connector_status_connected)
-               NV_DEBUG_KMS(dev, "Load was detected on output with or %d\n", or);
+               NV_DEBUG(drm, "Load was detected on output with or %d\n", or);
        else
-               NV_DEBUG_KMS(dev, "Load was not detected on output with or %d\n", or);
+               NV_DEBUG(drm, "Load was not detected on output with or %d\n", or);
  
        return status;
  }
  static void
  nv50_dac_dpms(struct drm_encoder *encoder, int mode)
  {
-       struct drm_device *dev = encoder->dev;
+       struct nouveau_device *device = nouveau_dev(encoder->dev);
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        uint32_t val;
        int or = nv_encoder->or;
  
-       NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
+       NV_DEBUG(drm, "or %d mode %d\n", or, mode);
  
        /* wait for it to be done */
-       if (!nv_wait(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+       if (!nv_wait(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
                     NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
-               NV_ERROR(dev, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
-               NV_ERROR(dev, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
-                        nv_rd32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or)));
+               NV_ERROR(drm, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
+               NV_ERROR(drm, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
+                        nv_rd32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or)));
                return;
        }
  
-       val = nv_rd32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or)) & ~0x7F;
+       val = nv_rd32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or)) & ~0x7F;
  
        if (mode != DRM_MODE_DPMS_ON)
                val |= NV50_PDISPLAY_DAC_DPMS_CTRL_BLANKED;
                break;
        }
  
-       nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or), val |
+       nv_wr32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or), val |
                NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
  }
  
  static void
  nv50_dac_save(struct drm_encoder *encoder)
  {
-       NV_ERROR(encoder->dev, "!!\n");
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+       NV_ERROR(drm, "!!\n");
  }
  
  static void
  nv50_dac_restore(struct drm_encoder *encoder)
  {
-       NV_ERROR(encoder->dev, "!!\n");
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+       NV_ERROR(drm, "!!\n");
  }
  
  static bool
@@@ -179,14 -185,15 +185,15 @@@ nv50_dac_mode_fixup(struct drm_encoder 
                    const struct drm_display_mode *mode,
                    struct drm_display_mode *adjusted_mode)
  {
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct nouveau_connector *connector;
  
-       NV_DEBUG_KMS(encoder->dev, "or %d\n", nv_encoder->or);
+       NV_DEBUG(drm, "or %d\n", nv_encoder->or);
  
        connector = nouveau_encoder_connector_get(nv_encoder);
        if (!connector) {
-               NV_ERROR(encoder->dev, "Encoder has no connector\n");
+               NV_ERROR(drm, "Encoder has no connector\n");
                return false;
        }
  
@@@ -207,13 -214,14 +214,14 @@@ nv50_dac_mode_set(struct drm_encoder *e
                  struct drm_display_mode *adjusted_mode)
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
        struct drm_device *dev = encoder->dev;
        struct nouveau_channel *evo = nv50_display(dev)->master;
        struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc);
        uint32_t mode_ctl = 0, mode_ctl2 = 0;
        int ret;
  
-       NV_DEBUG_KMS(dev, "or %d type %d crtc %d\n",
+       NV_DEBUG(drm, "or %d type %d crtc %d\n",
                     nv_encoder->or, nv_encoder->dcb->type, crtc->index);
  
        nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
                mode_ctl |= NV50_EVO_DAC_MODE_CTRL_CRTC0;
  
        /* Lacking a working tv-out, this is not a 100% sure. */
-       if (nv_encoder->dcb->type == OUTPUT_ANALOG)
+       if (nv_encoder->dcb->type == DCB_OUTPUT_ANALOG)
                mode_ctl |= 0x40;
        else
-       if (nv_encoder->dcb->type == OUTPUT_TV)
+       if (nv_encoder->dcb->type == DCB_OUTPUT_TV)
                mode_ctl |= 0x100;
  
        if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
  
        ret = RING_SPACE(evo, 3);
        if (ret) {
-               NV_ERROR(dev, "no space while connecting DAC\n");
+               NV_ERROR(drm, "no space while connecting DAC\n");
                return;
        }
        BEGIN_NV04(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2);
@@@ -271,11 -279,12 +279,12 @@@ static voi
  nv50_dac_destroy(struct drm_encoder *encoder)
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
  
        if (!encoder)
                return;
  
-       NV_DEBUG_KMS(encoder->dev, "\n");
+       NV_DEBUG(drm, "\n");
  
        drm_encoder_cleanup(encoder);
        kfree(nv_encoder);
@@@ -286,7 -295,7 +295,7 @@@ static const struct drm_encoder_funcs n
  };
  
  int
- nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
+ nv50_dac_create(struct drm_connector *connector, struct dcb_output *entry)
  {
        struct nouveau_encoder *nv_encoder;
        struct drm_encoder *encoder;
   *
   */
  
- #define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
+ #include "nouveau_drm.h"
+ #include "nouveau_dma.h"
  #include "nv50_display.h"
  #include "nouveau_crtc.h"
  #include "nouveau_encoder.h"
  #include "nouveau_connector.h"
- #include "nouveau_fb.h"
  #include "nouveau_fbcon.h"
- #include "nouveau_ramht.h"
- #include "nouveau_software.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drm_crtc_helper.h>
+ #include "nouveau_fence.h"
+ #include <core/gpuobj.h>
+ #include <subdev/timer.h>
  
- static void nv50_display_isr(struct drm_device *);
  static void nv50_display_bh(unsigned long);
  
  static inline int
  nv50_sor_nr(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
  
-       if (dev_priv->chipset  < 0x90 ||
-           dev_priv->chipset == 0x92 ||
-           dev_priv->chipset == 0xa0)
+       if (device->chipset  < 0x90 ||
+           device->chipset == 0x92 ||
+           device->chipset == 0xa0)
                return 2;
  
        return 4;
  u32
  nv50_display_active_crtcs(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
        u32 mask = 0;
        int i;
  
-       if (dev_priv->chipset  < 0x90 ||
-           dev_priv->chipset == 0x92 ||
-           dev_priv->chipset == 0xa0) {
+       if (device->chipset  < 0x90 ||
+           device->chipset == 0x92 ||
+           device->chipset == 0xa0) {
                for (i = 0; i < 2; i++)
-                       mask |= nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
+                       mask |= nv_rd32(device, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
        } else {
                for (i = 0; i < 4; i++)
-                       mask |= nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
+                       mask |= nv_rd32(device, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
        }
  
        for (i = 0; i < 3; i++)
-               mask |= nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
+               mask |= nv_rd32(device, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
  
        return mask & 3;
  }
  
- static int
- evo_icmd(struct drm_device *dev, int ch, u32 mthd, u32 data)
- {
-       int ret = 0;
-       nv_mask(dev, 0x610300 + (ch * 0x08), 0x00000001, 0x00000001);
-       nv_wr32(dev, 0x610304 + (ch * 0x08), data);
-       nv_wr32(dev, 0x610300 + (ch * 0x08), 0x80000001 | mthd);
-       if (!nv_wait(dev, 0x610300 + (ch * 0x08), 0x80000000, 0x00000000))
-               ret = -EBUSY;
-       if (ret || (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO))
-               NV_INFO(dev, "EvoPIO: %d 0x%04x 0x%08x\n", ch, mthd, data);
-       nv_mask(dev, 0x610300 + (ch * 0x08), 0x00000001, 0x00000000);
-       return ret;
- }
  int
  nv50_display_early_init(struct drm_device *dev)
  {
-       u32 ctrl = nv_rd32(dev, 0x610200);
-       int i;
-       /* check if master evo channel is already active, a good a sign as any
-        * that the display engine is in a weird state (hibernate/kexec), if
-        * it is, do our best to reset the display engine...
-        */
-       if ((ctrl & 0x00000003) == 0x00000003) {
-               NV_INFO(dev, "PDISP: EVO(0) 0x%08x, resetting...\n", ctrl);
-               /* deactivate both heads first, PDISP will disappear forever
-                * (well, until you power cycle) on some boards as soon as
-                * PMC_ENABLE is hit unless they are..
-                */
-               for (i = 0; i < 2; i++) {
-                       evo_icmd(dev, 0, 0x0880 + (i * 0x400), 0x05000000);
-                       evo_icmd(dev, 0, 0x089c + (i * 0x400), 0);
-                       evo_icmd(dev, 0, 0x0840 + (i * 0x400), 0);
-                       evo_icmd(dev, 0, 0x0844 + (i * 0x400), 0);
-                       evo_icmd(dev, 0, 0x085c + (i * 0x400), 0);
-                       evo_icmd(dev, 0, 0x0874 + (i * 0x400), 0);
-               }
-               evo_icmd(dev, 0, 0x0080, 0);
-               /* reset PDISP */
-               nv_mask(dev, 0x000200, 0x40000000, 0x00000000);
-               nv_mask(dev, 0x000200, 0x40000000, 0x40000000);
-       }
        return 0;
  }
  
@@@ -132,11 -90,8 +90,8 @@@ nv50_display_late_takedown(struct drm_d
  int
  nv50_display_sync(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
        struct nv50_display *disp = nv50_display(dev);
        struct nouveau_channel *evo = disp->master;
-       u64 start;
        int ret;
  
        ret = RING_SPACE(evo, 6);
                BEGIN_NV04(evo, 0, 0x0084, 1);
                OUT_RING  (evo, 0x00000000);
  
-               nv_wo32(disp->ntfy, 0x000, 0x00000000);
+               nv_wo32(disp->ramin, 0x2000, 0x00000000);
                FIRE_RING (evo);
  
-               start = ptimer->read(dev);
-               do {
-                       if (nv_ro32(disp->ntfy, 0x000))
-                               return 0;
-               } while (ptimer->read(dev) - start < 2000000000ULL);
+               if (nv_wait_ne(disp->ramin, 0x2000, 0xffffffff, 0x00000000))
+                       return 0;
        }
  
-       return -EBUSY;
+       return 0;
  }
  
  int
  nv50_display_init(struct drm_device *dev)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nouveau_dev(dev);
        struct nouveau_channel *evo;
        int ret, i;
        u32 val;
  
-       NV_DEBUG_KMS(dev, "\n");
+       NV_DEBUG(drm, "\n");
  
-       nv_wr32(dev, 0x00610184, nv_rd32(dev, 0x00614004));
+       nv_wr32(device, 0x00610184, nv_rd32(device, 0x00614004));
  
        /*
         * I think the 0x006101XX range is some kind of main control area
         */
        /* CRTC? */
        for (i = 0; i < 2; i++) {
-               val = nv_rd32(dev, 0x00616100 + (i * 0x800));
-               nv_wr32(dev, 0x00610190 + (i * 0x10), val);
-               val = nv_rd32(dev, 0x00616104 + (i * 0x800));
-               nv_wr32(dev, 0x00610194 + (i * 0x10), val);
-               val = nv_rd32(dev, 0x00616108 + (i * 0x800));
-               nv_wr32(dev, 0x00610198 + (i * 0x10), val);
-               val = nv_rd32(dev, 0x0061610c + (i * 0x800));
-               nv_wr32(dev, 0x0061019c + (i * 0x10), val);
+               val = nv_rd32(device, 0x00616100 + (i * 0x800));
+               nv_wr32(device, 0x00610190 + (i * 0x10), val);
+               val = nv_rd32(device, 0x00616104 + (i * 0x800));
+               nv_wr32(device, 0x00610194 + (i * 0x10), val);
+               val = nv_rd32(device, 0x00616108 + (i * 0x800));
+               nv_wr32(device, 0x00610198 + (i * 0x10), val);
+               val = nv_rd32(device, 0x0061610c + (i * 0x800));
+               nv_wr32(device, 0x0061019c + (i * 0x10), val);
        }
  
        /* DAC */
        for (i = 0; i < 3; i++) {
-               val = nv_rd32(dev, 0x0061a000 + (i * 0x800));
-               nv_wr32(dev, 0x006101d0 + (i * 0x04), val);
+               val = nv_rd32(device, 0x0061a000 + (i * 0x800));
+               nv_wr32(device, 0x006101d0 + (i * 0x04), val);
        }
  
        /* SOR */
        for (i = 0; i < nv50_sor_nr(dev); i++) {
-               val = nv_rd32(dev, 0x0061c000 + (i * 0x800));
-               nv_wr32(dev, 0x006101e0 + (i * 0x04), val);
+               val = nv_rd32(device, 0x0061c000 + (i * 0x800));
+               nv_wr32(device, 0x006101e0 + (i * 0x04), val);
        }
  
        /* EXT */
        for (i = 0; i < 3; i++) {
-               val = nv_rd32(dev, 0x0061e000 + (i * 0x800));
-               nv_wr32(dev, 0x006101f0 + (i * 0x04), val);
+               val = nv_rd32(device, 0x0061e000 + (i * 0x800));
+               nv_wr32(device, 0x006101f0 + (i * 0x04), val);
        }
  
        for (i = 0; i < 3; i++) {
-               nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(i), 0x00550000 |
+               nv_wr32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(i), 0x00550000 |
                        NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
-               nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(i), 0x00000001);
+               nv_wr32(device, NV50_PDISPLAY_DAC_CLK_CTRL1(i), 0x00000001);
        }
  
        /* The precise purpose is unknown, i suspect it has something to do
         * with text mode.
         */
-       if (nv_rd32(dev, NV50_PDISPLAY_INTR_1) & 0x100) {
-               nv_wr32(dev, NV50_PDISPLAY_INTR_1, 0x100);
-               nv_wr32(dev, 0x006194e8, nv_rd32(dev, 0x006194e8) & ~1);
-               if (!nv_wait(dev, 0x006194e8, 2, 0)) {
-                       NV_ERROR(dev, "timeout: (0x6194e8 & 2) != 0\n");
-                       NV_ERROR(dev, "0x6194e8 = 0x%08x\n",
-                                               nv_rd32(dev, 0x6194e8));
+       if (nv_rd32(device, NV50_PDISPLAY_INTR_1) & 0x100) {
+               nv_wr32(device, NV50_PDISPLAY_INTR_1, 0x100);
+               nv_wr32(device, 0x006194e8, nv_rd32(device, 0x006194e8) & ~1);
+               if (!nv_wait(device, 0x006194e8, 2, 0)) {
+                       NV_ERROR(drm, "timeout: (0x6194e8 & 2) != 0\n");
+                       NV_ERROR(drm, "0x6194e8 = 0x%08x\n",
+                                               nv_rd32(device, 0x6194e8));
                        return -EBUSY;
                }
        }
  
        for (i = 0; i < 2; i++) {
-               nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000);
-               if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+               nv_wr32(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000);
+               if (!nv_wait(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
                             NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
-                       NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n");
-                       NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n",
-                                nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
+                       NV_ERROR(drm, "timeout: CURSOR_CTRL2_STATUS == 0\n");
+                       NV_ERROR(drm, "CURSOR_CTRL2 = 0x%08x\n",
+                                nv_rd32(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
                        return -EBUSY;
                }
  
-               nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+               nv_wr32(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
                        NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON);
-               if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+               if (!nv_wait(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
                             NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS,
                             NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) {
-                       NV_ERROR(dev, "timeout: "
+                       NV_ERROR(drm, "timeout: "
                                      "CURSOR_CTRL2_STATUS_ACTIVE(%d)\n", i);
-                       NV_ERROR(dev, "CURSOR_CTRL2(%d) = 0x%08x\n", i,
-                                nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
+                       NV_ERROR(drm, "CURSOR_CTRL2(%d) = 0x%08x\n", i,
+                                nv_rd32(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
                        return -EBUSY;
                }
        }
  
-       nv_wr32(dev, NV50_PDISPLAY_PIO_CTRL, 0x00000000);
-       nv_mask(dev, NV50_PDISPLAY_INTR_0, 0x00000000, 0x00000000);
-       nv_wr32(dev, NV50_PDISPLAY_INTR_EN_0, 0x00000000);
-       nv_mask(dev, NV50_PDISPLAY_INTR_1, 0x00000000, 0x00000000);
-       nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1,
+       nv_wr32(device, NV50_PDISPLAY_PIO_CTRL, 0x00000000);
+       nv_mask(device, NV50_PDISPLAY_INTR_0, 0x00000000, 0x00000000);
+       nv_wr32(device, NV50_PDISPLAY_INTR_EN_0, 0x00000000);
+       nv_mask(device, NV50_PDISPLAY_INTR_1, 0x00000000, 0x00000000);
+       nv_wr32(device, NV50_PDISPLAY_INTR_EN_1,
                     NV50_PDISPLAY_INTR_EN_1_CLK_UNK10 |
                     NV50_PDISPLAY_INTR_EN_1_CLK_UNK20 |
                     NV50_PDISPLAY_INTR_EN_1_CLK_UNK40);
                return ret;
        evo = nv50_display(dev)->master;
  
-       nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9);
+       nv_wr32(device, NV50_PDISPLAY_OBJECTS, (nv50_display(dev)->ramin->addr >> 8) | 9);
  
        ret = RING_SPACE(evo, 3);
        if (ret)
  void
  nv50_display_fini(struct drm_device *dev)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nouveau_dev(dev);
        struct nv50_display *disp = nv50_display(dev);
        struct nouveau_channel *evo = disp->master;
        struct drm_crtc *drm_crtc;
        int ret, i;
  
-       NV_DEBUG_KMS(dev, "\n");
+       NV_DEBUG(drm, "\n");
  
        list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) {
                struct nouveau_crtc *crtc = nouveau_crtc(drm_crtc);
                if (!crtc->base.enabled)
                        continue;
  
-               nv_wr32(dev, NV50_PDISPLAY_INTR_1, mask);
-               if (!nv_wait(dev, NV50_PDISPLAY_INTR_1, mask, mask)) {
-                       NV_ERROR(dev, "timeout: (0x610024 & 0x%08x) == "
+               nv_wr32(device, NV50_PDISPLAY_INTR_1, mask);
+               if (!nv_wait(device, NV50_PDISPLAY_INTR_1, mask, mask)) {
+                       NV_ERROR(drm, "timeout: (0x610024 & 0x%08x) == "
                                      "0x%08x\n", mask, mask);
-                       NV_ERROR(dev, "0x610024 = 0x%08x\n",
-                                nv_rd32(dev, NV50_PDISPLAY_INTR_1));
+                       NV_ERROR(drm, "0x610024 = 0x%08x\n",
+                                nv_rd32(device, NV50_PDISPLAY_INTR_1));
                }
        }
  
        for (i = 0; i < 2; i++) {
-               nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0);
-               if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+               nv_wr32(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0);
+               if (!nv_wait(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
                             NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
-                       NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n");
-                       NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n",
-                                nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
+                       NV_ERROR(drm, "timeout: CURSOR_CTRL2_STATUS == 0\n");
+                       NV_ERROR(drm, "CURSOR_CTRL2 = 0x%08x\n",
+                                nv_rd32(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
                }
        }
  
        nv50_evo_fini(dev);
  
        for (i = 0; i < 3; i++) {
-               if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i),
+               if (!nv_wait(device, NV50_PDISPLAY_SOR_DPMS_STATE(i),
                             NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
-                       NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", i);
-                       NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", i,
-                                 nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i)));
+                       NV_ERROR(drm, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", i);
+                       NV_ERROR(drm, "SOR_DPMS_STATE(%d) = 0x%08x\n", i,
+                                 nv_rd32(device, NV50_PDISPLAY_SOR_DPMS_STATE(i)));
                }
        }
  
        /* disable interrupts. */
-       nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1, 0x00000000);
+       nv_wr32(device, NV50_PDISPLAY_INTR_EN_1, 0x00000000);
  }
  
  int
  nv50_display_create(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct dcb_table *dcb = &dev_priv->vbios.dcb;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct dcb_table *dcb = &drm->vbios.dcb;
        struct drm_connector *connector, *ct;
        struct nv50_display *priv;
        int ret, i;
  
-       NV_DEBUG_KMS(dev, "\n");
+       NV_DEBUG(drm, "\n");
  
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
-       dev_priv->engine.display.priv = priv;
+       nouveau_display(dev)->priv = priv;
+       nouveau_display(dev)->dtor = nv50_display_destroy;
+       nouveau_display(dev)->init = nv50_display_init;
+       nouveau_display(dev)->fini = nv50_display_fini;
  
        /* Create CRTC objects */
        for (i = 0; i < 2; i++) {
  
        /* We setup the encoders from the BIOS table */
        for (i = 0 ; i < dcb->entries; i++) {
-               struct dcb_entry *entry = &dcb->entry[i];
+               struct dcb_output *entry = &dcb->entry[i];
  
                if (entry->location != DCB_LOC_ON_CHIP) {
-                       NV_WARN(dev, "Off-chip encoder %d/%d unsupported\n",
+                       NV_WARN(drm, "Off-chip encoder %d/%d unsupported\n",
                                entry->type, ffs(entry->or) - 1);
                        continue;
                }
                        continue;
  
                switch (entry->type) {
-               case OUTPUT_TMDS:
-               case OUTPUT_LVDS:
-               case OUTPUT_DP:
+               case DCB_OUTPUT_TMDS:
+               case DCB_OUTPUT_LVDS:
+               case DCB_OUTPUT_DP:
                        nv50_sor_create(connector, entry);
                        break;
-               case OUTPUT_ANALOG:
+               case DCB_OUTPUT_ANALOG:
                        nv50_dac_create(connector, entry);
                        break;
                default:
-                       NV_WARN(dev, "DCB encoder %d unknown\n", entry->type);
+                       NV_WARN(drm, "DCB encoder %d unknown\n", entry->type);
                        continue;
                }
        }
        list_for_each_entry_safe(connector, ct,
                                 &dev->mode_config.connector_list, head) {
                if (!connector->encoder_ids[0]) {
-                       NV_WARN(dev, "%s has no encoders, removing\n",
+                       NV_WARN(drm, "%s has no encoders, removing\n",
                                drm_get_connector_name(connector));
                        connector->funcs->destroy(connector);
                }
        }
  
        tasklet_init(&priv->tasklet, nv50_display_bh, (unsigned long)dev);
-       nouveau_irq_register(dev, 26, nv50_display_isr);
  
        ret = nv50_evo_create(dev);
        if (ret) {
@@@ -420,13 -379,16 +379,16 @@@ nv50_display_destroy(struct drm_device 
  {
        struct nv50_display *disp = nv50_display(dev);
  
-       NV_DEBUG_KMS(dev, "\n");
        nv50_evo_destroy(dev);
-       nouveau_irq_unregister(dev, 26);
        kfree(disp);
  }
  
+ struct nouveau_bo *
+ nv50_display_crtc_sema(struct drm_device *dev, int crtc)
+ {
+       return nv50_display(dev)->crtc[crtc].sem.bo;
+ }
  void
  nv50_display_flip_stop(struct drm_crtc *crtc)
  {
@@@ -457,7 -419,7 +419,7 @@@ in
  nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                       struct nouveau_channel *chan)
  {
-       struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(crtc->dev);
        struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
        struct nv50_display *disp = nv50_display(crtc->dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
                        return ret;
                }
  
-               if (dev_priv->chipset < 0xc0) {
+               if (nv_device(drm->device)->chipset < 0xc0) {
                        BEGIN_NV04(chan, 0, 0x0060, 2);
                        OUT_RING  (chan, NvEvoSema0 + nv_crtc->index);
                        OUT_RING  (chan, dispc->sem.offset);
                        OUT_RING  (chan, dispc->sem.offset ^ 0x10);
                        OUT_RING  (chan, 0x74b1e000);
                        BEGIN_NV04(chan, 0, 0x0060, 1);
-                       if (dev_priv->chipset < 0x84)
+                       if (nv_device(drm->device)->chipset < 0x84)
                                OUT_RING  (chan, NvSema);
                        else
-                               OUT_RING  (chan, chan->vram_handle);
+                               OUT_RING  (chan, chan->vram);
                } else {
-                       u64 offset = nvc0_software_crtc(chan, nv_crtc->index);
+                       u64 offset = nvc0_fence_crtc(chan, nv_crtc->index);
                        offset += dispc->sem.offset;
                        BEGIN_NVC0(chan, 0, 0x0010, 4);
                        OUT_RING  (chan, upper_32_bits(offset));
  }
  
  static u16
- nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
+ nv50_display_script_select(struct drm_device *dev, struct dcb_output *dcb,
                           u32 mc, int pxclk)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_connector *nv_connector = NULL;
        struct drm_encoder *encoder;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nvbios *bios = &drm->vbios;
        u32 script = 0, or;
  
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
  
        or = ffs(dcb->or) - 1;
        switch (dcb->type) {
-       case OUTPUT_LVDS:
+       case DCB_OUTPUT_LVDS:
                script = (mc >> 8) & 0xf;
                if (bios->fp_no_ddc) {
                        if (bios->fp.dual_link)
                            (nv_connector->edid->input & 0x70) >= 0x20)
                                script |= 0x0200;
                }
-               if (nouveau_uscript_lvds >= 0) {
-                       NV_INFO(dev, "override script 0x%04x with 0x%04x "
-                                    "for output LVDS-%d\n", script,
-                                    nouveau_uscript_lvds, or);
-                       script = nouveau_uscript_lvds;
-               }
                break;
-       case OUTPUT_TMDS:
+       case DCB_OUTPUT_TMDS:
                script = (mc >> 8) & 0xf;
                if (pxclk >= 165000)
                        script |= 0x0100;
-               if (nouveau_uscript_tmds >= 0) {
-                       NV_INFO(dev, "override script 0x%04x with 0x%04x "
-                                    "for output TMDS-%d\n", script,
-                                    nouveau_uscript_tmds, or);
-                       script = nouveau_uscript_tmds;
-               }
                break;
-       case OUTPUT_DP:
+       case DCB_OUTPUT_DP:
                script = (mc >> 8) & 0xf;
                break;
-       case OUTPUT_ANALOG:
+       case DCB_OUTPUT_ANALOG:
                script = 0xff;
                break;
        default:
-               NV_ERROR(dev, "modeset on unsupported output type!\n");
+               NV_ERROR(drm, "modeset on unsupported output type!\n");
                break;
        }
  
  }
  
  static void
- nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc)
- {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_software_priv *psw = nv_engine(dev, NVOBJ_ENGINE_SW);
-       struct nouveau_software_chan *pch, *tmp;
-       list_for_each_entry_safe(pch, tmp, &psw->vblank, vblank.list) {
-               if (pch->vblank.head != crtc)
-                       continue;
-               spin_lock(&psw->peephole_lock);
-               nv_wr32(dev, 0x001704, pch->vblank.channel);
-               nv_wr32(dev, 0x001710, 0x80000000 | pch->vblank.ctxdma);
-               if (dev_priv->chipset == 0x50) {
-                       nv_wr32(dev, 0x001570, pch->vblank.offset);
-                       nv_wr32(dev, 0x001574, pch->vblank.value);
-               } else {
-                       nv_wr32(dev, 0x060010, pch->vblank.offset);
-                       nv_wr32(dev, 0x060014, pch->vblank.value);
-               }
-               spin_unlock(&psw->peephole_lock);
-               list_del(&pch->vblank.list);
-               drm_vblank_put(dev, crtc);
-       }
-       drm_handle_vblank(dev, crtc);
- }
- static void
- nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
- {
-       if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_0)
-               nv50_display_vblank_crtc_handler(dev, 0);
-       if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_1)
-               nv50_display_vblank_crtc_handler(dev, 1);
-       nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_VBLANK_CRTC);
- }
- static void
  nv50_display_unk10_handler(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nv50_display *disp = nv50_display(dev);
-       u32 unk30 = nv_rd32(dev, 0x610030), mc;
-       int i, crtc, or = 0, type = OUTPUT_ANY;
+       u32 unk30 = nv_rd32(device, 0x610030), mc;
+       int i, crtc, or = 0, type = DCB_OUTPUT_ANY;
  
-       NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
+       NV_DEBUG(drm, "0x610030: 0x%08x\n", unk30);
        disp->irq.dcb = NULL;
  
-       nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) & ~8);
+       nv_wr32(device, 0x619494, nv_rd32(device, 0x619494) & ~8);
  
        /* Determine which CRTC we're dealing with, only 1 ever will be
         * signalled at the same time with the current nouveau code.
                goto ack;
  
        /* Find which encoder was connected to the CRTC */
-       for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
-               mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
-               NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc);
+       for (i = 0; type == DCB_OUTPUT_ANY && i < 3; i++) {
+               mc = nv_rd32(device, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
+               NV_DEBUG(drm, "DAC-%d mc: 0x%08x\n", i, mc);
                if (!(mc & (1 << crtc)))
                        continue;
  
                switch ((mc & 0x00000f00) >> 8) {
-               case 0: type = OUTPUT_ANALOG; break;
-               case 1: type = OUTPUT_TV; break;
+               case 0: type = DCB_OUTPUT_ANALOG; break;
+               case 1: type = DCB_OUTPUT_TV; break;
                default:
-                       NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
+                       NV_ERROR(drm, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
                        goto ack;
                }
  
                or = i;
        }
  
-       for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
-               if (dev_priv->chipset  < 0x90 ||
-                   dev_priv->chipset == 0x92 ||
-                   dev_priv->chipset == 0xa0)
-                       mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
+       for (i = 0; type == DCB_OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
+               if (nv_device(drm->device)->chipset  < 0x90 ||
+                   nv_device(drm->device)->chipset == 0x92 ||
+                   nv_device(drm->device)->chipset == 0xa0)
+                       mc = nv_rd32(device, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
                else
-                       mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
+                       mc = nv_rd32(device, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
  
-               NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
+               NV_DEBUG(drm, "SOR-%d mc: 0x%08x\n", i, mc);
                if (!(mc & (1 << crtc)))
                        continue;
  
                switch ((mc & 0x00000f00) >> 8) {
-               case 0: type = OUTPUT_LVDS; break;
-               case 1: type = OUTPUT_TMDS; break;
-               case 2: type = OUTPUT_TMDS; break;
-               case 5: type = OUTPUT_TMDS; break;
-               case 8: type = OUTPUT_DP; break;
-               case 9: type = OUTPUT_DP; break;
+               case 0: type = DCB_OUTPUT_LVDS; break;
+               case 1: type = DCB_OUTPUT_TMDS; break;
+               case 2: type = DCB_OUTPUT_TMDS; break;
+               case 5: type = DCB_OUTPUT_TMDS; break;
+               case 8: type = DCB_OUTPUT_DP; break;
+               case 9: type = DCB_OUTPUT_DP; break;
                default:
-                       NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
+                       NV_ERROR(drm, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
                        goto ack;
                }
  
        }
  
        /* There was no encoder to disable */
-       if (type == OUTPUT_ANY)
+       if (type == DCB_OUTPUT_ANY)
                goto ack;
  
        /* Disable the encoder */
-       for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
-               struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
+       for (i = 0; i < drm->vbios.dcb.entries; i++) {
+               struct dcb_output *dcb = &drm->vbios.dcb.entry[i];
  
                if (dcb->type == type && (dcb->or & (1 << or))) {
                        nouveau_bios_run_display_table(dev, 0, -1, dcb, -1);
                }
        }
  
-       NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
+       NV_ERROR(drm, "no dcb for %d %d 0x%08x\n", or, type, mc);
  ack:
-       nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10);
-       nv_wr32(dev, 0x610030, 0x80000000);
+       nv_wr32(device, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10);
+       nv_wr32(device, 0x610030, 0x80000000);
  }
  
  static void
  nv50_display_unk20_handler(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nv50_display *disp = nv50_display(dev);
-       u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc = 0;
-       struct dcb_entry *dcb;
-       int i, crtc, or = 0, type = OUTPUT_ANY;
+       u32 unk30 = nv_rd32(device, 0x610030), tmp, pclk, script, mc = 0;
+       struct dcb_output *dcb;
+       int i, crtc, or = 0, type = DCB_OUTPUT_ANY;
  
-       NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
+       NV_DEBUG(drm, "0x610030: 0x%08x\n", unk30);
        dcb = disp->irq.dcb;
        if (dcb) {
                nouveau_bios_run_display_table(dev, 0, -2, dcb, -1);
        /* CRTC clock change requested? */
        crtc = ffs((unk30 & 0x00000600) >> 9) - 1;
        if (crtc >= 0) {
-               pclk  = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK));
+               pclk  = nv_rd32(device, NV50_PDISPLAY_CRTC_P(crtc, CLOCK));
                pclk &= 0x003fffff;
                if (pclk)
                        nv50_crtc_set_clock(dev, crtc, pclk);
  
-               tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc));
+               tmp = nv_rd32(device, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc));
                tmp &= ~0x000000f;
-               nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc), tmp);
+               nv_wr32(device, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc), tmp);
        }
  
        /* Nothing needs to be done for the encoder */
        crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
        if (crtc < 0)
                goto ack;
-       pclk  = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)) & 0x003fffff;
+       pclk  = nv_rd32(device, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)) & 0x003fffff;
  
        /* Find which encoder is connected to the CRTC */
-       for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
-               mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(i));
-               NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc);
+       for (i = 0; type == DCB_OUTPUT_ANY && i < 3; i++) {
+               mc = nv_rd32(device, NV50_PDISPLAY_DAC_MODE_CTRL_P(i));
+               NV_DEBUG(drm, "DAC-%d mc: 0x%08x\n", i, mc);
                if (!(mc & (1 << crtc)))
                        continue;
  
                switch ((mc & 0x00000f00) >> 8) {
-               case 0: type = OUTPUT_ANALOG; break;
-               case 1: type = OUTPUT_TV; break;
+               case 0: type = DCB_OUTPUT_ANALOG; break;
+               case 1: type = DCB_OUTPUT_TV; break;
                default:
-                       NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
+                       NV_ERROR(drm, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
                        goto ack;
                }
  
                or = i;
        }
  
-       for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
-               if (dev_priv->chipset  < 0x90 ||
-                   dev_priv->chipset == 0x92 ||
-                   dev_priv->chipset == 0xa0)
-                       mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(i));
+       for (i = 0; type == DCB_OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
+               if (nv_device(drm->device)->chipset  < 0x90 ||
+                   nv_device(drm->device)->chipset == 0x92 ||
+                   nv_device(drm->device)->chipset == 0xa0)
+                       mc = nv_rd32(device, NV50_PDISPLAY_SOR_MODE_CTRL_P(i));
                else
-                       mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(i));
+                       mc = nv_rd32(device, NV90_PDISPLAY_SOR_MODE_CTRL_P(i));
  
-               NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
+               NV_DEBUG(drm, "SOR-%d mc: 0x%08x\n", i, mc);
                if (!(mc & (1 << crtc)))
                        continue;
  
                switch ((mc & 0x00000f00) >> 8) {
-               case 0: type = OUTPUT_LVDS; break;
-               case 1: type = OUTPUT_TMDS; break;
-               case 2: type = OUTPUT_TMDS; break;
-               case 5: type = OUTPUT_TMDS; break;
-               case 8: type = OUTPUT_DP; break;
-               case 9: type = OUTPUT_DP; break;
+               case 0: type = DCB_OUTPUT_LVDS; break;
+               case 1: type = DCB_OUTPUT_TMDS; break;
+               case 2: type = DCB_OUTPUT_TMDS; break;
+               case 5: type = DCB_OUTPUT_TMDS; break;
+               case 8: type = DCB_OUTPUT_DP; break;
+               case 9: type = DCB_OUTPUT_DP; break;
                default:
-                       NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
+                       NV_ERROR(drm, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
                        goto ack;
                }
  
                or = i;
        }
  
-       if (type == OUTPUT_ANY)
+       if (type == DCB_OUTPUT_ANY)
                goto ack;
  
        /* Enable the encoder */
-       for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
-               dcb = &dev_priv->vbios.dcb.entry[i];
+       for (i = 0; i < drm->vbios.dcb.entries; i++) {
+               dcb = &drm->vbios.dcb.entry[i];
                if (dcb->type == type && (dcb->or & (1 << or)))
                        break;
        }
  
-       if (i == dev_priv->vbios.dcb.entries) {
-               NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
+       if (i == drm->vbios.dcb.entries) {
+               NV_ERROR(drm, "no dcb for %d %d 0x%08x\n", or, type, mc);
                goto ack;
        }
  
        script = nv50_display_script_select(dev, dcb, mc, pclk);
        nouveau_bios_run_display_table(dev, script, pclk, dcb, -1);
  
-       if (type == OUTPUT_DP) {
+       if (type == DCB_OUTPUT_DP) {
                int link = !(dcb->dpconf.sor.link & 1);
                if ((mc & 0x000f0000) == 0x00020000)
                        nv50_sor_dp_calc_tu(dev, or, link, pclk, 18);
                        nv50_sor_dp_calc_tu(dev, or, link, pclk, 24);
        }
  
-       if (dcb->type != OUTPUT_ANALOG) {
-               tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or));
+       if (dcb->type != DCB_OUTPUT_ANALOG) {
+               tmp = nv_rd32(device, NV50_PDISPLAY_SOR_CLK_CTRL2(or));
                tmp &= ~0x00000f0f;
                if (script & 0x0100)
                        tmp |= 0x00000101;
-               nv_wr32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or), tmp);
+               nv_wr32(device, NV50_PDISPLAY_SOR_CLK_CTRL2(or), tmp);
        } else {
-               nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0);
+               nv_wr32(device, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0);
        }
  
        disp->irq.dcb = dcb;
        disp->irq.script = script;
  
  ack:
-       nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20);
-       nv_wr32(dev, 0x610030, 0x80000000);
+       nv_wr32(device, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20);
+       nv_wr32(device, 0x610030, 0x80000000);
  }
  
  /* If programming a TMDS output on a SOR that can also be configured for
   * programmed for DisplayPort.
   */
  static void
- nv50_display_unk40_dp_set_tmds(struct drm_device *dev, struct dcb_entry *dcb)
+ nv50_display_unk40_dp_set_tmds(struct drm_device *dev, struct dcb_output *dcb)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
        struct drm_encoder *encoder;
        u32 tmp;
  
-       if (dcb->type != OUTPUT_TMDS)
+       if (dcb->type != DCB_OUTPUT_TMDS)
                return;
  
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
  
-               if (nv_encoder->dcb->type == OUTPUT_DP &&
+               if (nv_encoder->dcb->type == DCB_OUTPUT_DP &&
                    nv_encoder->dcb->or & (1 << or)) {
-                       tmp  = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
+                       tmp  = nv_rd32(device, NV50_SOR_DP_CTRL(or, link));
                        tmp &= ~NV50_SOR_DP_CTRL_ENABLED;
-                       nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
+                       nv_wr32(device, NV50_SOR_DP_CTRL(or, link), tmp);
                        break;
                }
        }
  static void
  nv50_display_unk40_handler(struct drm_device *dev)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nv50_display *disp = nv50_display(dev);
-       struct dcb_entry *dcb = disp->irq.dcb;
+       struct dcb_output *dcb = disp->irq.dcb;
        u16 script = disp->irq.script;
-       u32 unk30 = nv_rd32(dev, 0x610030), pclk = disp->irq.pclk;
+       u32 unk30 = nv_rd32(device, 0x610030), pclk = disp->irq.pclk;
  
-       NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
+       NV_DEBUG(drm, "0x610030: 0x%08x\n", unk30);
        disp->irq.dcb = NULL;
        if (!dcb)
                goto ack;
        nv50_display_unk40_dp_set_tmds(dev, dcb);
  
  ack:
-       nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40);
-       nv_wr32(dev, 0x610030, 0x80000000);
-       nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) | 8);
+       nv_wr32(device, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40);
+       nv_wr32(device, 0x610030, 0x80000000);
+       nv_wr32(device, 0x619494, nv_rd32(device, 0x619494) | 8);
  }
  
  static void
  nv50_display_bh(unsigned long data)
  {
        struct drm_device *dev = (struct drm_device *)data;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
        for (;;) {
-               uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0);
-               uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1);
+               uint32_t intr0 = nv_rd32(device, NV50_PDISPLAY_INTR_0);
+               uint32_t intr1 = nv_rd32(device, NV50_PDISPLAY_INTR_1);
  
-               NV_DEBUG_KMS(dev, "PDISPLAY_INTR_BH 0x%08x 0x%08x\n", intr0, intr1);
+               NV_DEBUG(drm, "PDISPLAY_INTR_BH 0x%08x 0x%08x\n", intr0, intr1);
  
                if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK10)
                        nv50_display_unk10_handler(dev);
                        break;
        }
  
-       nv_wr32(dev, NV03_PMC_INTR_EN_0, 1);
+       nv_wr32(device, NV03_PMC_INTR_EN_0, 1);
  }
  
  static void
  nv50_display_error_handler(struct drm_device *dev)
  {
-       u32 channels = (nv_rd32(dev, NV50_PDISPLAY_INTR_0) & 0x001f0000) >> 16;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       u32 channels = (nv_rd32(device, NV50_PDISPLAY_INTR_0) & 0x001f0000) >> 16;
        u32 addr, data;
        int chid;
  
                if (!(channels & (1 << chid)))
                        continue;
  
-               nv_wr32(dev, NV50_PDISPLAY_INTR_0, 0x00010000 << chid);
-               addr = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid));
-               data = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_DATA(chid));
-               NV_ERROR(dev, "EvoCh %d Mthd 0x%04x Data 0x%08x "
+               nv_wr32(device, NV50_PDISPLAY_INTR_0, 0x00010000 << chid);
+               addr = nv_rd32(device, NV50_PDISPLAY_TRAPPED_ADDR(chid));
+               data = nv_rd32(device, NV50_PDISPLAY_TRAPPED_DATA(chid));
+               NV_ERROR(drm, "EvoCh %d Mthd 0x%04x Data 0x%08x "
                              "(0x%04x 0x%02x)\n", chid,
                         addr & 0xffc, data, addr >> 16, (addr >> 12) & 0xf);
  
-               nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid), 0x90000000);
+               nv_wr32(device, NV50_PDISPLAY_TRAPPED_ADDR(chid), 0x90000000);
        }
  }
  
static void
- nv50_display_isr(struct drm_device *dev)
+ void
+ nv50_display_intr(struct drm_device *dev)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nv50_display *disp = nv50_display(dev);
        uint32_t delayed = 0;
  
-       while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
-               uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0);
-               uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1);
+       while (nv_rd32(device, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
+               uint32_t intr0 = nv_rd32(device, NV50_PDISPLAY_INTR_0);
+               uint32_t intr1 = nv_rd32(device, NV50_PDISPLAY_INTR_1);
                uint32_t clock;
  
-               NV_DEBUG_KMS(dev, "PDISPLAY_INTR 0x%08x 0x%08x\n", intr0, intr1);
+               NV_DEBUG(drm, "PDISPLAY_INTR 0x%08x 0x%08x\n", intr0, intr1);
  
                if (!intr0 && !(intr1 & ~delayed))
                        break;
                }
  
                if (intr1 & NV50_PDISPLAY_INTR_1_VBLANK_CRTC) {
-                       nv50_display_vblank_handler(dev, intr1);
                        intr1 &= ~NV50_PDISPLAY_INTR_1_VBLANK_CRTC;
+                       delayed |= NV50_PDISPLAY_INTR_1_VBLANK_CRTC;
                }
  
                clock = (intr1 & (NV50_PDISPLAY_INTR_1_CLK_UNK10 |
                                  NV50_PDISPLAY_INTR_1_CLK_UNK20 |
                                  NV50_PDISPLAY_INTR_1_CLK_UNK40));
                if (clock) {
-                       nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
+                       nv_wr32(device, NV03_PMC_INTR_EN_0, 0);
                        tasklet_schedule(&disp->tasklet);
                        delayed |= clock;
                        intr1 &= ~clock;
                }
  
                if (intr0) {
-                       NV_ERROR(dev, "unknown PDISPLAY_INTR_0: 0x%08x\n", intr0);
-                       nv_wr32(dev, NV50_PDISPLAY_INTR_0, intr0);
+                       NV_ERROR(drm, "unknown PDISPLAY_INTR_0: 0x%08x\n", intr0);
+                       nv_wr32(device, NV50_PDISPLAY_INTR_0, intr0);
                }
  
                if (intr1) {
-                       NV_ERROR(dev,
+                       NV_ERROR(drm,
                                 "unknown PDISPLAY_INTR_1: 0x%08x\n", intr1);
-                       nv_wr32(dev, NV50_PDISPLAY_INTR_1, intr1);
+                       nv_wr32(device, NV50_PDISPLAY_INTR_1, intr1);
                }
        }
  }
   * Authors: Ben Skeggs
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
  
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
  #include "nouveau_dma.h"
- #include "nouveau_ramht.h"
  #include "nv50_display.h"
  
+ #include <core/gpuobj.h>
+ #include <subdev/timer.h>
+ #include <subdev/fb.h>
+ static u32
+ nv50_evo_rd32(struct nouveau_object *object, u32 addr)
+ {
+       void __iomem *iomem = object->oclass->ofuncs->rd08;
+       return ioread32_native(iomem + addr);
+ }
+ static void
+ nv50_evo_wr32(struct nouveau_object *object, u32 addr, u32 data)
+ {
+       void __iomem *iomem = object->oclass->ofuncs->rd08;
+       iowrite32_native(data, iomem + addr);
+ }
  static void
  nv50_evo_channel_del(struct nouveau_channel **pevo)
  {
                return;
        *pevo = NULL;
  
-       nouveau_ramht_ref(NULL, &evo->ramht, evo);
-       nouveau_gpuobj_channel_takedown(evo);
-       nouveau_bo_unmap(evo->pushbuf_bo);
-       nouveau_bo_ref(NULL, &evo->pushbuf_bo);
+       nouveau_bo_unmap(evo->push.buffer);
+       nouveau_bo_ref(NULL, &evo->push.buffer);
  
-       if (evo->user)
-               iounmap(evo->user);
+       if (evo->object)
+               iounmap(evo->object->oclass->ofuncs);
  
        kfree(evo);
  }
  
- void
- nv50_evo_dmaobj_init(struct nouveau_gpuobj *obj, u32 memtype, u64 base, u64 size)
+ int
+ nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 handle, u32 memtype,
+                   u64 base, u64 size, struct nouveau_gpuobj **pobj)
  {
-       struct drm_nouveau_private *dev_priv = obj->dev->dev_private;
+       struct drm_device *dev = evo->fence;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nv50_display *disp = nv50_display(dev);
+       u32 dmao = disp->dmao;
+       u32 hash = disp->hash;
        u32 flags5;
  
-       if (dev_priv->chipset < 0xc0) {
+       if (nv_device(drm->device)->chipset < 0xc0) {
                /* not supported on 0x50, specified in format mthd */
-               if (dev_priv->chipset == 0x50)
+               if (nv_device(drm->device)->chipset == 0x50)
                        memtype = 0;
                flags5 = 0x00010000;
        } else {
                        flags5 = 0x00020000;
        }
  
-       nv50_gpuobj_dma_init(obj, 0, 0x3d, base, size, NV_MEM_TARGET_VRAM,
-                            NV_MEM_ACCESS_RW, (memtype >> 8) & 0xff, 0);
-       nv_wo32(obj, 0x14, flags5);
-       dev_priv->engine.instmem.flush(obj->dev);
- }
+       nv_wo32(disp->ramin, dmao + 0x00, 0x0019003d | (memtype << 22));
+       nv_wo32(disp->ramin, dmao + 0x04, lower_32_bits(base + size - 1));
+       nv_wo32(disp->ramin, dmao + 0x08, lower_32_bits(base));
+       nv_wo32(disp->ramin, dmao + 0x0c, upper_32_bits(base + size - 1) << 24 |
+                                         upper_32_bits(base));
+       nv_wo32(disp->ramin, dmao + 0x10, 0x00000000);
+       nv_wo32(disp->ramin, dmao + 0x14, flags5);
  
- int
- nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 handle, u32 memtype,
-                   u64 base, u64 size, struct nouveau_gpuobj **pobj)
- {
-       struct nv50_display *disp = nv50_display(evo->dev);
-       struct nouveau_gpuobj *obj = NULL;
-       int ret;
-       ret = nouveau_gpuobj_new(evo->dev, disp->master, 6*4, 32, 0, &obj);
-       if (ret)
-               return ret;
-       obj->engine = NVOBJ_ENGINE_DISPLAY;
-       nv50_evo_dmaobj_init(obj, memtype, base, size);
-       ret = nouveau_ramht_insert(evo, handle, obj);
-       if (ret)
-               goto out;
+       nv_wo32(disp->ramin, hash + 0x00, handle);
+       nv_wo32(disp->ramin, hash + 0x04, (evo->handle << 28) | (dmao << 10) |
+                                          evo->handle);
  
-       if (pobj)
-               nouveau_gpuobj_ref(obj, pobj);
- out:
-       nouveau_gpuobj_ref(NULL, &obj);
-       return ret;
+       disp->dmao += 0x20;
+       disp->hash += 0x08;
+       return 0;
  }
  
  static int
  nv50_evo_channel_new(struct drm_device *dev, int chid,
                     struct nouveau_channel **pevo)
  {
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nv50_display *disp = nv50_display(dev);
        struct nouveau_channel *evo;
        int ret;
                return -ENOMEM;
        *pevo = evo;
  
-       evo->id = chid;
-       evo->dev = dev;
+       evo->drm = drm;
+       evo->handle = chid;
+       evo->fence = dev;
        evo->user_get = 4;
        evo->user_put = 0;
  
        ret = nouveau_bo_new(dev, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, NULL,
-                            &evo->pushbuf_bo);
+                            &evo->push.buffer);
        if (ret == 0)
-               ret = nouveau_bo_pin(evo->pushbuf_bo, TTM_PL_FLAG_VRAM);
+               ret = nouveau_bo_pin(evo->push.buffer, TTM_PL_FLAG_VRAM);
        if (ret) {
-               NV_ERROR(dev, "Error creating EVO DMA push buffer: %d\n", ret);
+               NV_ERROR(drm, "Error creating EVO DMA push buffer: %d\n", ret);
                nv50_evo_channel_del(pevo);
                return ret;
        }
  
-       ret = nouveau_bo_map(evo->pushbuf_bo);
+       ret = nouveau_bo_map(evo->push.buffer);
        if (ret) {
-               NV_ERROR(dev, "Error mapping EVO DMA push buffer: %d\n", ret);
+               NV_ERROR(drm, "Error mapping EVO DMA push buffer: %d\n", ret);
                nv50_evo_channel_del(pevo);
                return ret;
        }
  
-       evo->user = ioremap(pci_resource_start(dev->pdev, 0) +
-                           NV50_PDISPLAY_USER(evo->id), PAGE_SIZE);
-       if (!evo->user) {
-               NV_ERROR(dev, "Error mapping EVO control regs.\n");
-               nv50_evo_channel_del(pevo);
-               return -ENOMEM;
-       }
-       /* bind primary evo channel's ramht to the channel */
-       if (disp->master && evo != disp->master)
-               nouveau_ramht_ref(disp->master->ramht, &evo->ramht, NULL);
+       evo->object = kzalloc(sizeof(*evo->object), GFP_KERNEL);
+ #ifdef NOUVEAU_OBJECT_MAGIC
+       evo->object->_magic = NOUVEAU_OBJECT_MAGIC;
+ #endif
+       evo->object->parent = nv_object(disp->ramin)->parent;
+       evo->object->engine = nv_object(disp->ramin)->engine;
+       evo->object->oclass =
+               kzalloc(sizeof(*evo->object->oclass), GFP_KERNEL);
+       evo->object->oclass->ofuncs =
+               kzalloc(sizeof(*evo->object->oclass->ofuncs), GFP_KERNEL);
+       evo->object->oclass->ofuncs->rd32 = nv50_evo_rd32;
+       evo->object->oclass->ofuncs->wr32 = nv50_evo_wr32;
+       evo->object->oclass->ofuncs->rd08 =
+               ioremap(pci_resource_start(dev->pdev, 0) +
+                       NV50_PDISPLAY_USER(evo->handle), PAGE_SIZE);
        return 0;
  }
  
  static int
  nv50_evo_channel_init(struct nouveau_channel *evo)
  {
-       struct drm_device *dev = evo->dev;
-       int id = evo->id, ret, i;
-       u64 pushbuf = evo->pushbuf_bo->bo.offset;
+       struct nouveau_drm *drm = evo->drm;
+       struct nouveau_device *device = nv_device(drm->device);
+       int id = evo->handle, ret, i;
+       u64 pushbuf = evo->push.buffer->bo.offset;
        u32 tmp;
  
-       tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id));
+       tmp = nv_rd32(device, NV50_PDISPLAY_EVO_CTRL(id));
        if ((tmp & 0x009f0000) == 0x00020000)
-               nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x00800000);
+               nv_wr32(device, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x00800000);
  
-       tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id));
+       tmp = nv_rd32(device, NV50_PDISPLAY_EVO_CTRL(id));
        if ((tmp & 0x003f0000) == 0x00030000)
-               nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x00600000);
+               nv_wr32(device, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x00600000);
  
        /* initialise fifo */
-       nv_wr32(dev, NV50_PDISPLAY_EVO_DMA_CB(id), pushbuf >> 8 |
+       nv_wr32(device, NV50_PDISPLAY_EVO_DMA_CB(id), pushbuf >> 8 |
                     NV50_PDISPLAY_EVO_DMA_CB_LOCATION_VRAM |
                     NV50_PDISPLAY_EVO_DMA_CB_VALID);
-       nv_wr32(dev, NV50_PDISPLAY_EVO_UNK2(id), 0x00010000);
-       nv_wr32(dev, NV50_PDISPLAY_EVO_HASH_TAG(id), id);
-       nv_mask(dev, NV50_PDISPLAY_EVO_CTRL(id), NV50_PDISPLAY_EVO_CTRL_DMA,
+       nv_wr32(device, NV50_PDISPLAY_EVO_UNK2(id), 0x00010000);
+       nv_wr32(device, NV50_PDISPLAY_EVO_HASH_TAG(id), id);
+       nv_mask(device, NV50_PDISPLAY_EVO_CTRL(id), NV50_PDISPLAY_EVO_CTRL_DMA,
                     NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED);
  
-       nv_wr32(dev, NV50_PDISPLAY_USER_PUT(id), 0x00000000);
-       nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x01000003 |
+       nv_wr32(device, NV50_PDISPLAY_USER_PUT(id), 0x00000000);
+       nv_wr32(device, NV50_PDISPLAY_EVO_CTRL(id), 0x01000003 |
                     NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED);
-       if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x80000000, 0x00000000)) {
-               NV_ERROR(dev, "EvoCh %d init timeout: 0x%08x\n", id,
-                        nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id)));
+       if (!nv_wait(device, NV50_PDISPLAY_EVO_CTRL(id), 0x80000000, 0x00000000)) {
+               NV_ERROR(drm, "EvoCh %d init timeout: 0x%08x\n", id,
+                        nv_rd32(device, NV50_PDISPLAY_EVO_CTRL(id)));
                return -EBUSY;
        }
  
        /* enable error reporting on the channel */
-       nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << id);
+       nv_mask(device, 0x610028, 0x00000000, 0x00010001 << id);
  
        evo->dma.max = (4096/4) - 2;
        evo->dma.max &= ~7;
  static void
  nv50_evo_channel_fini(struct nouveau_channel *evo)
  {
-       struct drm_device *dev = evo->dev;
-       int id = evo->id;
-       nv_mask(dev, 0x610028, 0x00010001 << id, 0x00000000);
-       nv_mask(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x00001010, 0x00001000);
-       nv_wr32(dev, NV50_PDISPLAY_INTR_0, (1 << id));
-       nv_mask(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x00000003, 0x00000000);
-       if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x001e0000, 0x00000000)) {
-               NV_ERROR(dev, "EvoCh %d takedown timeout: 0x%08x\n", id,
-                        nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id)));
+       struct nouveau_drm *drm = evo->drm;
+       struct nouveau_device *device = nv_device(drm->device);
+       int id = evo->handle;
+       nv_mask(device, 0x610028, 0x00010001 << id, 0x00000000);
+       nv_mask(device, NV50_PDISPLAY_EVO_CTRL(id), 0x00001010, 0x00001000);
+       nv_wr32(device, NV50_PDISPLAY_INTR_0, (1 << id));
+       nv_mask(device, NV50_PDISPLAY_EVO_CTRL(id), 0x00000003, 0x00000000);
+       if (!nv_wait(device, NV50_PDISPLAY_EVO_CTRL(id), 0x001e0000, 0x00000000)) {
+               NV_ERROR(drm, "EvoCh %d takedown timeout: 0x%08x\n", id,
+                        nv_rd32(device, NV50_PDISPLAY_EVO_CTRL(id)));
        }
  }
  
@@@ -231,93 -244,66 +244,66 @@@ nv50_evo_destroy(struct drm_device *dev
                }
                nv50_evo_channel_del(&disp->crtc[i].sync);
        }
-       nouveau_gpuobj_ref(NULL, &disp->ntfy);
        nv50_evo_channel_del(&disp->master);
+       nouveau_gpuobj_ref(NULL, &disp->ramin);
  }
  
  int
  nv50_evo_create(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_fb *pfb = nouveau_fb(drm->device);
        struct nv50_display *disp = nv50_display(dev);
-       struct nouveau_gpuobj *ramht = NULL;
        struct nouveau_channel *evo;
        int ret, i, j;
  
-       /* create primary evo channel, the one we use for modesetting
-        * purporses
-        */
-       ret = nv50_evo_channel_new(dev, 0, &disp->master);
-       if (ret)
-               return ret;
-       evo = disp->master;
        /* setup object management on it, any other evo channel will
         * use this also as there's no per-channel support on the
         * hardware
         */
-       ret = nouveau_gpuobj_new(dev, NULL, 32768, 65536,
-                                NVOBJ_FLAG_ZERO_ALLOC, &evo->ramin);
-       if (ret) {
-               NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret);
-               goto err;
-       }
-       ret = drm_mm_init(&evo->ramin_heap, 0, 32768);
+       ret = nouveau_gpuobj_new(drm->device, NULL, 32768, 65536,
+                                NVOBJ_FLAG_ZERO_ALLOC, &disp->ramin);
        if (ret) {
-               NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret);
+               NV_ERROR(drm, "Error allocating EVO channel memory: %d\n", ret);
                goto err;
        }
  
-       ret = nouveau_gpuobj_new(dev, evo, 4096, 16, 0, &ramht);
-       if (ret) {
-               NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret);
-               goto err;
-       }
-       ret = nouveau_ramht_new(dev, ramht, &evo->ramht);
-       nouveau_gpuobj_ref(NULL, &ramht);
-       if (ret)
-               goto err;
+       disp->hash = 0x0000;
+       disp->dmao = 0x1000;
  
-       /* not sure exactly what this is..
-        *
-        * the first dword of the structure is used by nvidia to wait on
-        * full completion of an EVO "update" command.
-        *
-        * method 0x8c on the master evo channel will fill a lot more of
-        * this structure with some undefined info
+       /* create primary evo channel, the one we use for modesetting
+        * purporses
         */
-       ret = nouveau_gpuobj_new(dev, disp->master, 0x1000, 0,
-                                NVOBJ_FLAG_ZERO_ALLOC, &disp->ntfy);
+       ret = nv50_evo_channel_new(dev, 0, &disp->master);
        if (ret)
-               goto err;
+               return ret;
+       evo = disp->master;
  
        ret = nv50_evo_dmaobj_new(disp->master, NvEvoSync, 0x0000,
-                                 disp->ntfy->vinst, disp->ntfy->size, NULL);
+                                 disp->ramin->addr + 0x2000, 0x1000, NULL);
        if (ret)
                goto err;
  
        /* create some default objects for the scanout memtypes we support */
        ret = nv50_evo_dmaobj_new(disp->master, NvEvoVRAM, 0x0000,
-                                 0, dev_priv->vram_size, NULL);
+                                 0, pfb->ram.size, NULL);
        if (ret)
                goto err;
  
        ret = nv50_evo_dmaobj_new(disp->master, NvEvoVRAM_LP, 0x80000000,
-                                 0, dev_priv->vram_size, NULL);
+                                 0, pfb->ram.size, NULL);
        if (ret)
                goto err;
  
        ret = nv50_evo_dmaobj_new(disp->master, NvEvoFB32, 0x80000000 |
-                                 (dev_priv->chipset < 0xc0 ? 0x7a00 : 0xfe00),
-                                 0, dev_priv->vram_size, NULL);
+                                 (nv_device(drm->device)->chipset < 0xc0 ? 0x7a : 0xfe),
+                                 0, pfb->ram.size, NULL);
        if (ret)
                goto err;
  
        ret = nv50_evo_dmaobj_new(disp->master, NvEvoFB16, 0x80000000 |
-                                 (dev_priv->chipset < 0xc0 ? 0x7000 : 0xfe00),
-                                 0, dev_priv->vram_size, NULL);
+                                 (nv_device(drm->device)->chipset < 0xc0 ? 0x70 : 0xfe),
+                                 0, pfb->ram.size, NULL);
        if (ret)
                goto err;
  
                        goto err;
  
                ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoVRAM_LP, 0x80000000,
-                                         0, dev_priv->vram_size, NULL);
+                                         0, pfb->ram.size, NULL);
                if (ret)
                        goto err;
  
                ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoFB32, 0x80000000 |
-                                         (dev_priv->chipset < 0xc0 ?
-                                         0x7a00 : 0xfe00),
-                                         0, dev_priv->vram_size, NULL);
+                                         (nv_device(drm->device)->chipset < 0xc0 ?
+                                         0x7a : 0xfe),
+                                         0, pfb->ram.size, NULL);
                if (ret)
                        goto err;
  
                ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoFB16, 0x80000000 |
-                                         (dev_priv->chipset < 0xc0 ?
-                                         0x7000 : 0xfe00),
-                                         0, dev_priv->vram_size, NULL);
+                                         (nv_device(drm->device)->chipset < 0xc0 ?
+                                         0x70 : 0xfe),
+                                         0, pfb->ram.size, NULL);
                if (ret)
                        goto err;
  
   * Authors: Ben Skeggs
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
  #include "nouveau_bios.h"
  #include "nouveau_hw.h"
  #include "nouveau_pm.h"
  #include "nouveau_hwsq.h"
  #include "nv50_display.h"
  
+ #include <subdev/bios/pll.h>
+ #include <subdev/clock.h>
+ #include <subdev/timer.h>
+ #include <subdev/fb.h>
  enum clk_src {
        clk_src_crystal,
        clk_src_href,
@@@ -49,19 -55,20 +55,20 @@@ static u32 read_clk(struct drm_device *
  static u32
  read_div(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
  
-       switch (dev_priv->chipset) {
+       switch (nv_device(drm->device)->chipset) {
        case 0x50: /* it exists, but only has bit 31, not the dividers.. */
        case 0x84:
        case 0x86:
        case 0x98:
        case 0xa0:
-               return nv_rd32(dev, 0x004700);
+               return nv_rd32(device, 0x004700);
        case 0x92:
        case 0x94:
        case 0x96:
-               return nv_rd32(dev, 0x004800);
+               return nv_rd32(device, 0x004800);
        default:
                return 0x00000000;
        }
  static u32
  read_pll_src(struct drm_device *dev, u32 base)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        u32 coef, ref = read_clk(dev, clk_src_crystal);
-       u32 rsel = nv_rd32(dev, 0x00e18c);
+       u32 rsel = nv_rd32(device, 0x00e18c);
        int P, N, M, id;
  
-       switch (dev_priv->chipset) {
+       switch (nv_device(drm->device)->chipset) {
        case 0x50:
        case 0xa0:
                switch (base) {
                case 0x4008: id = !!(rsel & 0x00000008); break;
                case 0x4030: id = 0; break;
                default:
-                       NV_ERROR(dev, "ref: bad pll 0x%06x\n", base);
+                       NV_ERROR(drm, "ref: bad pll 0x%06x\n", base);
                        return 0;
                }
  
-               coef = nv_rd32(dev, 0x00e81c + (id * 0x0c));
+               coef = nv_rd32(device, 0x00e81c + (id * 0x0c));
                ref *=  (coef & 0x01000000) ? 2 : 4;
                P    =  (coef & 0x00070000) >> 16;
                N    = ((coef & 0x0000ff00) >> 8) + 1;
        case 0x84:
        case 0x86:
        case 0x92:
-               coef = nv_rd32(dev, 0x00e81c);
+               coef = nv_rd32(device, 0x00e81c);
                P    = (coef & 0x00070000) >> 16;
                N    = (coef & 0x0000ff00) >> 8;
                M    = (coef & 0x000000ff) >> 0;
        case 0x94:
        case 0x96:
        case 0x98:
-               rsel = nv_rd32(dev, 0x00c050);
+               rsel = nv_rd32(device, 0x00c050);
                switch (base) {
                case 0x4020: rsel = (rsel & 0x00000003) >> 0; break;
                case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break;
                case 0x4028: rsel = (rsel & 0x00001800) >> 11; break;
                case 0x4030: rsel = 3; break;
                default:
-                       NV_ERROR(dev, "ref: bad pll 0x%06x\n", base);
+                       NV_ERROR(drm, "ref: bad pll 0x%06x\n", base);
                        return 0;
                }
  
                case 3: id = 0; break;
                }
  
-               coef =  nv_rd32(dev, 0x00e81c + (id * 0x28));
-               P    = (nv_rd32(dev, 0x00e824 + (id * 0x28)) >> 16) & 7;
+               coef =  nv_rd32(device, 0x00e81c + (id * 0x28));
+               P    = (nv_rd32(device, 0x00e824 + (id * 0x28)) >> 16) & 7;
                P   += (coef & 0x00070000) >> 16;
                N    = (coef & 0x0000ff00) >> 8;
                M    = (coef & 0x000000ff) >> 0;
  static u32
  read_pll_ref(struct drm_device *dev, u32 base)
  {
-       u32 src, mast = nv_rd32(dev, 0x00c040);
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       u32 src, mast = nv_rd32(device, 0x00c040);
  
        switch (base) {
        case 0x004028:
        case 0x00e810:
                return read_clk(dev, clk_src_crystal);
        default:
-               NV_ERROR(dev, "bad pll 0x%06x\n", base);
+               NV_ERROR(drm, "bad pll 0x%06x\n", base);
                return 0;
        }
  
  static u32
  read_pll(struct drm_device *dev, u32 base)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       u32 mast = nv_rd32(dev, 0x00c040);
-       u32 ctrl = nv_rd32(dev, base + 0);
-       u32 coef = nv_rd32(dev, base + 4);
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       u32 mast = nv_rd32(device, 0x00c040);
+       u32 ctrl = nv_rd32(device, base + 0);
+       u32 coef = nv_rd32(device, base + 4);
        u32 ref = read_pll_ref(dev, base);
        u32 clk = 0;
        int N1, N2, M1, M2;
  
        if (base == 0x004028 && (mast & 0x00100000)) {
                /* wtf, appears to only disable post-divider on nva0 */
-               if (dev_priv->chipset != 0xa0)
+               if (nv_device(drm->device)->chipset != 0xa0)
                        return read_clk(dev, clk_src_dom6);
        }
  
  static u32
  read_clk(struct drm_device *dev, enum clk_src src)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       u32 mast = nv_rd32(dev, 0x00c040);
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       u32 mast = nv_rd32(device, 0x00c040);
        u32 P = 0;
  
        switch (src) {
        case clk_src_crystal:
-               return dev_priv->crystal;
+               return device->crystal;
        case clk_src_href:
                return 100000; /* PCIE reference clock */
        case clk_src_hclk:
                break;
        case clk_src_nvclk:
                if (!(mast & 0x00100000))
-                       P = (nv_rd32(dev, 0x004028) & 0x00070000) >> 16;
+                       P = (nv_rd32(device, 0x004028) & 0x00070000) >> 16;
                switch (mast & 0x00000003) {
                case 0x00000000: return read_clk(dev, clk_src_crystal) >> P;
                case 0x00000001: return read_clk(dev, clk_src_dom6);
                }
                break;
        case clk_src_sclk:
-               P = (nv_rd32(dev, 0x004020) & 0x00070000) >> 16;
+               P = (nv_rd32(device, 0x004020) & 0x00070000) >> 16;
                switch (mast & 0x00000030) {
                case 0x00000000:
                        if (mast & 0x00000080)
                }
                break;
        case clk_src_mclk:
-               P = (nv_rd32(dev, 0x004008) & 0x00070000) >> 16;
-               if (nv_rd32(dev, 0x004008) & 0x00000200) {
+               P = (nv_rd32(device, 0x004008) & 0x00070000) >> 16;
+               if (nv_rd32(device, 0x004008) & 0x00000200) {
                        switch (mast & 0x0000c000) {
                        case 0x00000000:
                                return read_clk(dev, clk_src_crystal) >> P;
                break;
        case clk_src_vdec:
                P = (read_div(dev) & 0x00000700) >> 8;
-               switch (dev_priv->chipset) {
+               switch (nv_device(drm->device)->chipset) {
                case 0x84:
                case 0x86:
                case 0x92:
                case 0xa0:
                        switch (mast & 0x00000c00) {
                        case 0x00000000:
-                               if (dev_priv->chipset == 0xa0) /* wtf?? */
+                               if (nv_device(drm->device)->chipset == 0xa0) /* wtf?? */
                                        return read_clk(dev, clk_src_nvclk) >> P;
                                return read_clk(dev, clk_src_crystal) >> P;
                        case 0x00000400:
                }
                break;
        case clk_src_dom6:
-               switch (dev_priv->chipset) {
+               switch (nv_device(drm->device)->chipset) {
                case 0x50:
                case 0xa0:
                        return read_pll(dev, 0x00e810) >> 2;
                break;
        }
  
-       NV_DEBUG(dev, "unknown clock source %d 0x%08x\n", src, mast);
+       NV_DEBUG(drm, "unknown clock source %d 0x%08x\n", src, mast);
        return 0;
  }
  
  int
  nv50_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       if (dev_priv->chipset == 0xaa ||
-           dev_priv->chipset == 0xac)
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       if (nv_device(drm->device)->chipset == 0xaa ||
+           nv_device(drm->device)->chipset == 0xac)
                return 0;
  
        perflvl->core   = read_clk(dev, clk_src_nvclk);
        perflvl->shader = read_clk(dev, clk_src_sclk);
        perflvl->memory = read_clk(dev, clk_src_mclk);
-       if (dev_priv->chipset != 0x50) {
+       if (nv_device(drm->device)->chipset != 0x50) {
                perflvl->vdec = read_clk(dev, clk_src_vdec);
                perflvl->dom6 = read_clk(dev, clk_src_dom6);
        }
@@@ -363,22 -375,25 +375,25 @@@ struct nv50_pm_state 
  };
  
  static u32
- calc_pll(struct drm_device *dev, u32 reg, struct pll_lims *pll,
+ calc_pll(struct drm_device *dev, u32 reg, struct nvbios_pll *pll,
         u32 clk, int *N1, int *M1, int *log2P)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_bios *bios = nouveau_bios(device);
+       struct nouveau_clock *pclk = nouveau_clock(device);
        struct nouveau_pll_vals coef;
        int ret;
  
-       ret = get_pll_limits(dev, reg, pll);
+       ret = nvbios_pll_parse(bios, reg, pll);
        if (ret)
                return 0;
  
-       pll->vco2.maxfreq = 0;
+       pll->vco2.max_freq = 0;
        pll->refclk = read_pll_ref(dev, reg);
        if (!pll->refclk)
                return 0;
  
-       ret = nouveau_calc_pll_mnp(dev, pll, clk, &coef);
+       ret = pclk->pll_calc(pclk, pll, clk, &coef);
        if (ret == 0)
                return 0;
  
@@@ -461,27 -476,29 +476,29 @@@ mclk_wait(struct nouveau_mem_exec_func 
  static u32
  mclk_mrg(struct nouveau_mem_exec_func *exec, int mr)
  {
+       struct nouveau_device *device = nouveau_dev(exec->dev);
        if (mr <= 1)
-               return nv_rd32(exec->dev, 0x1002c0 + ((mr - 0) * 4));
+               return nv_rd32(device, 0x1002c0 + ((mr - 0) * 4));
        if (mr <= 3)
-               return nv_rd32(exec->dev, 0x1002e0 + ((mr - 2) * 4));
+               return nv_rd32(device, 0x1002e0 + ((mr - 2) * 4));
        return 0;
  }
  
  static void
  mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data)
  {
-       struct drm_nouveau_private *dev_priv = exec->dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(exec->dev);
+       struct nouveau_fb *pfb = nouveau_fb(device);
        struct nv50_pm_state *info = exec->priv;
        struct hwsq_ucode *hwsq = &info->mclk_hwsq;
  
        if (mr <= 1) {
-               if (dev_priv->vram_rank_B)
+               if (pfb->ram.ranks > 1)
                        hwsq_wr32(hwsq, 0x1002c8 + ((mr - 0) * 4), data);
                hwsq_wr32(hwsq, 0x1002c0 + ((mr - 0) * 4), data);
        } else
        if (mr <= 3) {
-               if (dev_priv->vram_rank_B)
+               if (pfb->ram.ranks > 1)
                        hwsq_wr32(hwsq, 0x1002e8 + ((mr - 2) * 4), data);
                hwsq_wr32(hwsq, 0x1002e0 + ((mr - 2) * 4), data);
        }
  static void
  mclk_clock_set(struct nouveau_mem_exec_func *exec)
  {
+       struct nouveau_device *device = nouveau_dev(exec->dev);
        struct nv50_pm_state *info = exec->priv;
        struct hwsq_ucode *hwsq = &info->mclk_hwsq;
-       u32 ctrl = nv_rd32(exec->dev, 0x004008);
+       u32 ctrl = nv_rd32(device, 0x004008);
  
-       info->mmast = nv_rd32(exec->dev, 0x00c040);
+       info->mmast = nv_rd32(device, 0x00c040);
        info->mmast &= ~0xc0000000; /* get MCLK_2 from HREF */
        info->mmast |=  0x0000c000; /* use MCLK_2 as MPLL_BYPASS clock */
  
  static void
  mclk_timing_set(struct nouveau_mem_exec_func *exec)
  {
-       struct drm_device *dev = exec->dev;
+       struct nouveau_device *device = nouveau_dev(exec->dev);
        struct nv50_pm_state *info = exec->priv;
        struct nouveau_pm_level *perflvl = info->perflvl;
        struct hwsq_ucode *hwsq = &info->mclk_hwsq;
  
        for (i = 0; i < 9; i++) {
                u32 reg = 0x100220 + (i * 4);
-               u32 val = nv_rd32(dev, reg);
+               u32 val = nv_rd32(device, reg);
                if (val != perflvl->timing.reg[i])
                        hwsq_wr32(hwsq, reg, perflvl->timing.reg[i]);
        }
@@@ -526,7 -544,8 +544,8 @@@ static in
  calc_mclk(struct drm_device *dev, struct nouveau_pm_level *perflvl,
          struct nv50_pm_state *info)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nouveau_dev(dev);
        u32 crtc_mask = nv50_display_active_crtcs(dev);
        struct nouveau_mem_exec_func exec = {
                .dev = dev,
                .priv = info
        };
        struct hwsq_ucode *hwsq = &info->mclk_hwsq;
-       struct pll_lims pll;
+       struct nvbios_pll pll;
        int N, M, P;
        int ret;
  
        /* use pcie refclock if possible, otherwise use mpll */
-       info->mctrl  = nv_rd32(dev, 0x004008);
+       info->mctrl  = nv_rd32(device, 0x004008);
        info->mctrl &= ~0x81ff0200;
        if (clk_same(perflvl->memory, read_clk(dev, clk_src_href))) {
-               info->mctrl |= 0x00000200 | (pll.log2p_bias << 19);
+               info->mctrl |= 0x00000200 | (pll.bias_p << 19);
        } else {
                ret = calc_pll(dev, 0x4008, &pll, perflvl->memory, &N, &M, &P);
                if (ret == 0)
                        return -EINVAL;
  
                info->mctrl |= 0x80000000 | (P << 22) | (P << 16);
-               info->mctrl |= pll.log2p_bias << 19;
+               info->mctrl |= pll.bias_p << 19;
                info->mcoef  = (N << 8) | M;
        }
  
                hwsq_op5f(hwsq, crtc_mask, 0x00); /* wait for scanout */
                hwsq_op5f(hwsq, crtc_mask, 0x01); /* wait for vblank */
        }
-       if (dev_priv->chipset >= 0x92)
+       if (nv_device(drm->device)->chipset >= 0x92)
                hwsq_wr32(hwsq, 0x611200, 0x00003300); /* disable scanout */
        hwsq_setf(hwsq, 0x10, 0); /* disable bus access */
        hwsq_op5f(hwsq, 0x00, 0x01); /* no idea :s */
  
        hwsq_setf(hwsq, 0x10, 1); /* enable bus access */
        hwsq_op5f(hwsq, 0x00, 0x00); /* no idea, reverse of 0x00, 0x01? */
-       if (dev_priv->chipset >= 0x92)
+       if (nv_device(drm->device)->chipset >= 0x92)
                hwsq_wr32(hwsq, 0x611200, 0x00003330); /* enable scanout */
        hwsq_fini(hwsq);
        return 0;
  void *
  nv50_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nv50_pm_state *info;
        struct hwsq_ucode *hwsq;
-       struct pll_lims pll;
+       struct nvbios_pll pll;
        u32 out, mast, divs, ctrl;
        int clk, ret = -EINVAL;
        int N, M, P1, P2;
  
-       if (dev_priv->chipset == 0xaa ||
-           dev_priv->chipset == 0xac)
+       if (nv_device(drm->device)->chipset == 0xaa ||
+           nv_device(drm->device)->chipset == 0xac)
                return ERR_PTR(-ENODEV);
  
        info = kmalloc(sizeof(*info), GFP_KERNEL);
                clk = calc_div(perflvl->core, perflvl->vdec, &P1);
  
                /* see how close we can get using xpll/hclk as a source */
-               if (dev_priv->chipset != 0x98)
+               if (nv_device(drm->device)->chipset != 0x98)
                        out = read_pll(dev, 0x004030);
                else
                        out = read_clk(dev, clk_src_hclkm3d2);
                /* select whichever gets us closest */
                if (abs((int)perflvl->vdec - clk) <=
                    abs((int)perflvl->vdec - out)) {
-                       if (dev_priv->chipset != 0x98)
+                       if (nv_device(drm->device)->chipset != 0x98)
                                mast |= 0x00000c00;
                        divs |= P1 << 8;
                } else {
        }
  
        /* vdec/dom6: complete switch to new clocks */
-       switch (dev_priv->chipset) {
+       switch (nv_device(drm->device)->chipset) {
        case 0x92:
        case 0x94:
        case 0x96:
        /* core/shader: make sure sclk/nvclk are disconnected from their
         * PLLs (nvclk to dom6, sclk to hclk)
         */
-       if (dev_priv->chipset < 0x92)
+       if (nv_device(drm->device)->chipset < 0x92)
                mast = (mast & ~0x001000b0) | 0x00100080;
        else
                mast = (mast & ~0x000000b3) | 0x00000081;
        if (clk == 0)
                goto error;
  
-       ctrl  = nv_rd32(dev, 0x004028) & ~0xc03f0100;
+       ctrl  = nv_rd32(device, 0x004028) & ~0xc03f0100;
        mast &= ~0x00100000;
        mast |= 3;
  
         * cases will be handled by tying to nvclk, but it's possible there's
         * corners
         */
-       ctrl = nv_rd32(dev, 0x004020) & ~0xc03f0100;
+       ctrl = nv_rd32(device, 0x004020) & ~0xc03f0100;
  
        if (P1-- && perflvl->shader == (perflvl->core << 1)) {
                hwsq_wr32(hwsq, 0x004020, (P1 << 19) | (P1 << 16) | ctrl);
@@@ -752,11 -772,12 +772,12 @@@ error
  static int
  prog_hwsq(struct drm_device *dev, struct hwsq_ucode *hwsq)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        u32 hwsq_data, hwsq_kick;
        int i;
  
-       if (dev_priv->chipset < 0x94) {
+       if (nv_device(drm->device)->chipset < 0x94) {
                hwsq_data = 0x001400;
                hwsq_kick = 0x00000003;
        } else {
                hwsq_kick = 0x00000001;
        }
        /* upload hwsq ucode */
-       nv_mask(dev, 0x001098, 0x00000008, 0x00000000);
-       nv_wr32(dev, 0x001304, 0x00000000);
-       if (dev_priv->chipset >= 0x92)
-               nv_wr32(dev, 0x001318, 0x00000000);
+       nv_mask(device, 0x001098, 0x00000008, 0x00000000);
+       nv_wr32(device, 0x001304, 0x00000000);
+       if (nv_device(drm->device)->chipset >= 0x92)
+               nv_wr32(device, 0x001318, 0x00000000);
        for (i = 0; i < hwsq->len / 4; i++)
-               nv_wr32(dev, hwsq_data + (i * 4), hwsq->ptr.u32[i]);
-       nv_mask(dev, 0x001098, 0x00000018, 0x00000018);
+               nv_wr32(device, hwsq_data + (i * 4), hwsq->ptr.u32[i]);
+       nv_mask(device, 0x001098, 0x00000018, 0x00000018);
  
        /* launch, and wait for completion */
-       nv_wr32(dev, 0x00130c, hwsq_kick);
-       if (!nv_wait(dev, 0x001308, 0x00000100, 0x00000000)) {
-               NV_ERROR(dev, "hwsq ucode exec timed out\n");
-               NV_ERROR(dev, "0x001308: 0x%08x\n", nv_rd32(dev, 0x001308));
+       nv_wr32(device, 0x00130c, hwsq_kick);
+       if (!nv_wait(device, 0x001308, 0x00000100, 0x00000000)) {
+               NV_ERROR(drm, "hwsq ucode exec timed out\n");
+               NV_ERROR(drm, "0x001308: 0x%08x\n", nv_rd32(device, 0x001308));
                for (i = 0; i < hwsq->len / 4; i++) {
-                       NV_ERROR(dev, "0x%06x: 0x%08x\n", 0x1400 + (i * 4),
-                                nv_rd32(dev, 0x001400 + (i * 4)));
+                       NV_ERROR(drm, "0x%06x: 0x%08x\n", 0x1400 + (i * 4),
+                                nv_rd32(device, 0x001400 + (i * 4)));
                }
  
                return -EIO;
  int
  nv50_pm_clocks_set(struct drm_device *dev, void *data)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        struct nv50_pm_state *info = data;
        struct bit_entry M;
        int ret = -EBUSY;
  
        /* halt and idle execution engines */
-       nv_mask(dev, 0x002504, 0x00000001, 0x00000001);
-       if (!nv_wait(dev, 0x002504, 0x00000010, 0x00000010))
+       nv_mask(device, 0x002504, 0x00000001, 0x00000001);
+       if (!nv_wait(device, 0x002504, 0x00000010, 0x00000010))
                goto resume;
-       if (!nv_wait(dev, 0x00251c, 0x0000003f, 0x0000003f))
+       if (!nv_wait(device, 0x00251c, 0x0000003f, 0x0000003f))
                goto resume;
  
        /* program memory clock, if necessary - must come before engine clock
         * reprogramming due to how we construct the hwsq scripts in pre()
         */
+ #define nouveau_bios_init_exec(a,b) nouveau_bios_run_init_table((a), (b), NULL, 0)
        if (info->mclk_hwsq.len) {
                /* execute some scripts that do ??? from the vbios.. */
                if (!bit_table(dev, 'M', &M) && M.version == 1) {
        ret = prog_hwsq(dev, &info->eclk_hwsq);
  
  resume:
-       nv_mask(dev, 0x002504, 0x00000001, 0x00000000);
+       nv_mask(device, 0x002504, 0x00000001, 0x00000000);
        kfree(info);
        return ret;
  }
- static int
- pwm_info(struct drm_device *dev, int *line, int *ctrl, int *indx)
- {
-       if (*line == 0x04) {
-               *ctrl = 0x00e100;
-               *line = 4;
-               *indx = 0;
-       } else
-       if (*line == 0x09) {
-               *ctrl = 0x00e100;
-               *line = 9;
-               *indx = 1;
-       } else
-       if (*line == 0x10) {
-               *ctrl = 0x00e28c;
-               *line = 0;
-               *indx = 0;
-       } else {
-               NV_ERROR(dev, "unknown pwm ctrl for gpio %d\n", *line);
-               return -ENODEV;
-       }
-       return 0;
- }
- int
- nv50_pm_pwm_get(struct drm_device *dev, int line, u32 *divs, u32 *duty)
- {
-       int ctrl, id, ret = pwm_info(dev, &line, &ctrl, &id);
-       if (ret)
-               return ret;
-       if (nv_rd32(dev, ctrl) & (1 << line)) {
-               *divs = nv_rd32(dev, 0x00e114 + (id * 8));
-               *duty = nv_rd32(dev, 0x00e118 + (id * 8));
-               return 0;
-       }
-       return -EINVAL;
- }
- int
- nv50_pm_pwm_set(struct drm_device *dev, int line, u32 divs, u32 duty)
- {
-       int ctrl, id, ret = pwm_info(dev, &line, &ctrl, &id);
-       if (ret)
-               return ret;
-       nv_mask(dev, ctrl, 0x00010001 << line, 0x00000001 << line);
-       nv_wr32(dev, 0x00e114 + (id * 8), divs);
-       nv_wr32(dev, 0x00e118 + (id * 8), duty | 0x80000000);
-       return 0;
- }
   *
   */
  
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
  
  #define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
  #include "nouveau_reg.h"
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
  #include "nouveau_dma.h"
  #include "nouveau_encoder.h"
  #include "nouveau_connector.h"
  #include "nouveau_crtc.h"
  #include "nv50_display.h"
  
+ #include <subdev/timer.h>
  static u32
- nv50_sor_dp_lane_map(struct drm_device *dev, struct dcb_entry *dcb, u8 lane)
+ nv50_sor_dp_lane_map(struct drm_device *dev, struct dcb_output *dcb, u8 lane)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        static const u8 nvaf[] = { 24, 16, 8, 0 }; /* thanks, apple.. */
        static const u8 nv50[] = { 16, 8, 0, 24 };
-       if (dev_priv->chipset == 0xaf)
+       if (nv_device(drm->device)->chipset == 0xaf)
                return nvaf[lane];
        return nv50[lane];
  }
  
  static void
- nv50_sor_dp_train_set(struct drm_device *dev, struct dcb_entry *dcb, u8 pattern)
+ nv50_sor_dp_train_set(struct drm_device *dev, struct dcb_output *dcb, u8 pattern)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
-       nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x0f000000, pattern << 24);
+       nv_mask(device, NV50_SOR_DP_CTRL(or, link), 0x0f000000, pattern << 24);
  }
  
  static void
- nv50_sor_dp_train_adj(struct drm_device *dev, struct dcb_entry *dcb,
+ nv50_sor_dp_train_adj(struct drm_device *dev, struct dcb_output *dcb,
                      u8 lane, u8 swing, u8 preem)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
        u32 shift = nv50_sor_dp_lane_map(dev, dcb, lane);
        u32 mask = 0x000000ff << shift;
@@@ -65,7 -70,7 +70,7 @@@
  
        table = nouveau_dp_bios_data(dev, dcb, &entry);
        if (!table || (table[0] != 0x20 && table[0] != 0x21)) {
-               NV_ERROR(dev, "PDISP: unsupported DP table for chipset\n");
+               NV_ERROR(drm, "PDISP: unsupported DP table for chipset\n");
                return;
        }
  
                        return;
        }
  
-       nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, config[2] << shift);
-       nv_mask(dev, NV50_SOR_DP_UNK120(or, link), mask, config[3] << shift);
-       nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000ff00, config[4] << 8);
+       nv_mask(device, NV50_SOR_DP_UNK118(or, link), mask, config[2] << shift);
+       nv_mask(device, NV50_SOR_DP_UNK120(or, link), mask, config[3] << shift);
+       nv_mask(device, NV50_SOR_DP_UNK130(or, link), 0x0000ff00, config[4] << 8);
  }
  
  static void
- nv50_sor_dp_link_set(struct drm_device *dev, struct dcb_entry *dcb, int crtc,
+ nv50_sor_dp_link_set(struct drm_device *dev, struct dcb_output *dcb, int crtc,
                     int link_nr, u32 link_bw, bool enhframe)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
-       u32 dpctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)) & ~0x001f4000;
-       u32 clksor = nv_rd32(dev, 0x614300 + (or * 0x800)) & ~0x000c0000;
+       u32 dpctrl = nv_rd32(device, NV50_SOR_DP_CTRL(or, link)) & ~0x001f4000;
+       u32 clksor = nv_rd32(device, 0x614300 + (or * 0x800)) & ~0x000c0000;
        u8 *table, *entry, mask;
        int i;
  
        table = nouveau_dp_bios_data(dev, dcb, &entry);
        if (!table || (table[0] != 0x20 && table[0] != 0x21)) {
-               NV_ERROR(dev, "PDISP: unsupported DP table for chipset\n");
+               NV_ERROR(drm, "PDISP: unsupported DP table for chipset\n");
                return;
        }
  
        if (link_bw > 162000)
                clksor |= 0x00040000;
  
-       nv_wr32(dev, 0x614300 + (or * 0x800), clksor);
-       nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), dpctrl);
+       nv_wr32(device, 0x614300 + (or * 0x800), clksor);
+       nv_wr32(device, NV50_SOR_DP_CTRL(or, link), dpctrl);
  
        mask = 0;
        for (i = 0; i < link_nr; i++)
                mask |= 1 << (nv50_sor_dp_lane_map(dev, dcb, i) >> 3);
-       nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000000f, mask);
+       nv_mask(device, NV50_SOR_DP_UNK130(or, link), 0x0000000f, mask);
  }
  
  static void
  nv50_sor_dp_link_get(struct drm_device *dev, u32 or, u32 link, u32 *nr, u32 *bw)
  {
-       u32 dpctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)) & 0x000f0000;
-       u32 clksor = nv_rd32(dev, 0x614300 + (or * 0x800));
+       struct nouveau_device *device = nouveau_dev(dev);
+       u32 dpctrl = nv_rd32(device, NV50_SOR_DP_CTRL(or, link)) & 0x000f0000;
+       u32 clksor = nv_rd32(device, 0x614300 + (or * 0x800));
        if (clksor & 0x000c0000)
                *bw = 270000;
        else
  void
  nv50_sor_dp_calc_tu(struct drm_device *dev, int or, int link, u32 clk, u32 bpp)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        const u32 symbol = 100000;
        int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
        int TU, VTUi, VTUf, VTUa;
        }
  
        if (!bestTU) {
-               NV_ERROR(dev, "DP: unable to find suitable config\n");
+               NV_ERROR(drm, "DP: unable to find suitable config\n");
                return;
        }
  
        r = do_div(unk, symbol);
        unk += 6;
  
-       nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2);
-       nv_mask(dev, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 |
+       nv_mask(device, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2);
+       nv_mask(device, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 |
                                                             bestVTUf << 16 |
                                                             bestVTUi << 8 |
                                                             unk);
@@@ -227,6 -237,7 +237,7 @@@ static voi
  nv50_sor_disconnect(struct drm_encoder *encoder)
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
        struct drm_device *dev = encoder->dev;
        struct nouveau_channel *evo = nv50_display(dev)->master;
        int ret;
                return;
        nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true);
  
-       NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or);
+       NV_DEBUG(drm, "Disconnecting SOR %d\n", nv_encoder->or);
  
        ret = RING_SPACE(evo, 4);
        if (ret) {
-               NV_ERROR(dev, "no space while disconnecting SOR\n");
+               NV_ERROR(drm, "no space while disconnecting SOR\n");
                return;
        }
        BEGIN_NV04(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
  static void
  nv50_sor_dpms(struct drm_encoder *encoder, int mode)
  {
+       struct nouveau_device *device = nouveau_dev(encoder->dev);
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
        struct drm_device *dev = encoder->dev;
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_encoder *enc;
        uint32_t val;
        int or = nv_encoder->or;
  
-       NV_DEBUG_KMS(dev, "or %d type %d mode %d\n", or, nv_encoder->dcb->type, mode);
+       NV_DEBUG(drm, "or %d type %d mode %d\n", or, nv_encoder->dcb->type, mode);
  
        nv_encoder->last_dpms = mode;
        list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
                struct nouveau_encoder *nvenc = nouveau_encoder(enc);
  
                if (nvenc == nv_encoder ||
-                   (nvenc->dcb->type != OUTPUT_TMDS &&
-                    nvenc->dcb->type != OUTPUT_LVDS &&
-                    nvenc->dcb->type != OUTPUT_DP) ||
+                   (nvenc->dcb->type != DCB_OUTPUT_TMDS &&
+                    nvenc->dcb->type != DCB_OUTPUT_LVDS &&
+                    nvenc->dcb->type != DCB_OUTPUT_DP) ||
                    nvenc->dcb->or != nv_encoder->dcb->or)
                        continue;
  
        }
  
        /* wait for it to be done */
-       if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or),
+       if (!nv_wait(device, NV50_PDISPLAY_SOR_DPMS_CTRL(or),
                     NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING, 0)) {
-               NV_ERROR(dev, "timeout: SOR_DPMS_CTRL_PENDING(%d) == 0\n", or);
-               NV_ERROR(dev, "SOR_DPMS_CTRL(%d) = 0x%08x\n", or,
-                        nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or)));
+               NV_ERROR(drm, "timeout: SOR_DPMS_CTRL_PENDING(%d) == 0\n", or);
+               NV_ERROR(drm, "SOR_DPMS_CTRL(%d) = 0x%08x\n", or,
+                        nv_rd32(device, NV50_PDISPLAY_SOR_DPMS_CTRL(or)));
        }
  
-       val = nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or));
+       val = nv_rd32(device, NV50_PDISPLAY_SOR_DPMS_CTRL(or));
  
        if (mode == DRM_MODE_DPMS_ON)
                val |= NV50_PDISPLAY_SOR_DPMS_CTRL_ON;
        else
                val &= ~NV50_PDISPLAY_SOR_DPMS_CTRL_ON;
  
-       nv_wr32(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or), val |
+       nv_wr32(device, NV50_PDISPLAY_SOR_DPMS_CTRL(or), val |
                NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING);
-       if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or),
+       if (!nv_wait(device, NV50_PDISPLAY_SOR_DPMS_STATE(or),
                     NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
-               NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", or);
-               NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", or,
-                        nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or)));
+               NV_ERROR(drm, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", or);
+               NV_ERROR(drm, "SOR_DPMS_STATE(%d) = 0x%08x\n", or,
+                        nv_rd32(device, NV50_PDISPLAY_SOR_DPMS_STATE(or)));
        }
  
-       if (nv_encoder->dcb->type == OUTPUT_DP) {
+       if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
                struct dp_train_func func = {
                        .link_set = nv50_sor_dp_link_set,
                        .train_set = nv50_sor_dp_train_set,
  static void
  nv50_sor_save(struct drm_encoder *encoder)
  {
-       NV_ERROR(encoder->dev, "!!\n");
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+       NV_ERROR(drm, "!!\n");
  }
  
  static void
  nv50_sor_restore(struct drm_encoder *encoder)
  {
-       NV_ERROR(encoder->dev, "!!\n");
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+       NV_ERROR(drm, "!!\n");
  }
  
  static bool
@@@ -331,14 -346,15 +346,15 @@@ nv50_sor_mode_fixup(struct drm_encoder 
                    const struct drm_display_mode *mode,
                    struct drm_display_mode *adjusted_mode)
  {
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct nouveau_connector *connector;
  
-       NV_DEBUG_KMS(encoder->dev, "or %d\n", nv_encoder->or);
+       NV_DEBUG(drm, "or %d\n", nv_encoder->or);
  
        connector = nouveau_encoder_connector_get(nv_encoder);
        if (!connector) {
-               NV_ERROR(encoder->dev, "Encoder has no connector\n");
+               NV_ERROR(drm, "Encoder has no connector\n");
                return false;
        }
  
@@@ -354,7 -370,7 +370,7 @@@ nv50_sor_prepare(struct drm_encoder *en
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        nv50_sor_disconnect(encoder);
-       if (nv_encoder->dcb->type == OUTPUT_DP) {
+       if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
                /* avoid race between link training and supervisor intr */
                nv50_display_sync(encoder->dev);
        }
@@@ -371,18 -387,18 +387,18 @@@ nv50_sor_mode_set(struct drm_encoder *e
  {
        struct nouveau_channel *evo = nv50_display(encoder->dev)->master;
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-       struct drm_device *dev = encoder->dev;
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
        struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc);
        struct nouveau_connector *nv_connector;
        uint32_t mode_ctl = 0;
        int ret;
  
-       NV_DEBUG_KMS(dev, "or %d type %d -> crtc %d\n",
+       NV_DEBUG(drm, "or %d type %d -> crtc %d\n",
                     nv_encoder->or, nv_encoder->dcb->type, crtc->index);
        nv_encoder->crtc = encoder->crtc;
  
        switch (nv_encoder->dcb->type) {
-       case OUTPUT_TMDS:
+       case DCB_OUTPUT_TMDS:
                if (nv_encoder->dcb->sorconf.link & 1) {
                        if (mode->clock < 165000)
                                mode_ctl = 0x0100;
  
                nouveau_hdmi_mode_set(encoder, mode);
                break;
-       case OUTPUT_DP:
+       case DCB_OUTPUT_DP:
                nv_connector = nouveau_encoder_connector_get(nv_encoder);
                if (nv_connector && nv_connector->base.display_info.bpc == 6) {
                        nv_encoder->dp.datarate = mode->clock * 18 / 8;
  
        ret = RING_SPACE(evo, 2);
        if (ret) {
-               NV_ERROR(dev, "no space while connecting SOR\n");
+               NV_ERROR(drm, "no space while connecting SOR\n");
                nv_encoder->crtc = NULL;
                return;
        }
@@@ -458,11 -474,9 +474,9 @@@ static voi
  nv50_sor_destroy(struct drm_encoder *encoder)
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+       struct nouveau_drm *drm = nouveau_drm(encoder->dev);
  
-       if (!encoder)
-               return;
-       NV_DEBUG_KMS(encoder->dev, "\n");
+       NV_DEBUG(drm, "\n");
  
        drm_encoder_cleanup(encoder);
  
@@@ -474,21 -488,22 +488,22 @@@ static const struct drm_encoder_funcs n
  };
  
  int
- nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry)
+ nv50_sor_create(struct drm_connector *connector, struct dcb_output *entry)
  {
        struct nouveau_encoder *nv_encoder = NULL;
        struct drm_device *dev = connector->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct drm_encoder *encoder;
        int type;
  
-       NV_DEBUG_KMS(dev, "\n");
+       NV_DEBUG(drm, "\n");
  
        switch (entry->type) {
-       case OUTPUT_TMDS:
-       case OUTPUT_DP:
+       case DCB_OUTPUT_TMDS:
+       case DCB_OUTPUT_DP:
                type = DRM_MODE_ENCODER_TMDS;
                break;
-       case OUTPUT_LVDS:
+       case DCB_OUTPUT_LVDS:
                type = DRM_MODE_ENCODER_LVDS;
                break;
        default:
   * Authors: Ben Skeggs
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
  #include "nouveau_bios.h"
  #include "nouveau_pm.h"
  
+ #include <subdev/bios/pll.h>
+ #include <subdev/bios.h>
+ #include <subdev/clock.h>
+ #include <subdev/timer.h>
+ #include <subdev/fb.h>
  static u32 read_clk(struct drm_device *, int, bool);
  static u32 read_pll(struct drm_device *, int, u32);
  
  static u32
  read_vco(struct drm_device *dev, int clk)
  {
-       u32 sctl = nv_rd32(dev, 0x4120 + (clk * 4));
+       struct nouveau_device *device = nouveau_dev(dev);
+       u32 sctl = nv_rd32(device, 0x4120 + (clk * 4));
        if ((sctl & 0x00000030) != 0x00000030)
                return read_pll(dev, 0x41, 0x00e820);
        return read_pll(dev, 0x42, 0x00e8a0);
  static u32
  read_clk(struct drm_device *dev, int clk, bool ignore_en)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        u32 sctl, sdiv, sclk;
  
        /* refclk for the 0xe8xx plls is a fixed frequency */
        if (clk >= 0x40) {
-               if (dev_priv->chipset == 0xaf) {
+               if (nv_device(drm->device)->chipset == 0xaf) {
                        /* no joke.. seriously.. sigh.. */
-                       return nv_rd32(dev, 0x00471c) * 1000;
+                       return nv_rd32(device, 0x00471c) * 1000;
                }
  
-               return dev_priv->crystal;
+               return device->crystal;
        }
  
-       sctl = nv_rd32(dev, 0x4120 + (clk * 4));
+       sctl = nv_rd32(device, 0x4120 + (clk * 4));
        if (!ignore_en && !(sctl & 0x00000100))
                return 0;
  
        switch (sctl & 0x00003000) {
        case 0x00000000:
-               return dev_priv->crystal;
+               return device->crystal;
        case 0x00002000:
                if (sctl & 0x00000040)
                        return 108000;
  static u32
  read_pll(struct drm_device *dev, int clk, u32 pll)
  {
-       u32 ctrl = nv_rd32(dev, pll + 0);
+       struct nouveau_device *device = nouveau_dev(dev);
+       u32 ctrl = nv_rd32(device, pll + 0);
        u32 sclk = 0, P = 1, N = 1, M = 1;
  
        if (!(ctrl & 0x00000008)) {
                if (ctrl & 0x00000001) {
-                       u32 coef = nv_rd32(dev, pll + 4);
+                       u32 coef = nv_rd32(device, pll + 4);
                        M = (coef & 0x000000ff) >> 0;
                        N = (coef & 0x0000ff00) >> 8;
                        P = (coef & 0x003f0000) >> 16;
@@@ -111,7 -120,10 +120,10 @@@ struct creg 
  static int
  calc_clk(struct drm_device *dev, int clk, u32 pll, u32 khz, struct creg *reg)
  {
-       struct pll_lims limits;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_bios *bios = nouveau_bios(device);
+       struct nvbios_pll limits;
        u32 oclk, sclk, sdiv;
        int P, N, M, diff;
        int ret;
        reg->pll = 0;
        reg->clk = 0;
        if (!khz) {
-               NV_DEBUG(dev, "no clock for 0x%04x/0x%02x\n", pll, clk);
+               NV_DEBUG(drm, "no clock for 0x%04x/0x%02x\n", pll, clk);
                return 0;
        }
  
                }
  
                if (!pll) {
-                       NV_ERROR(dev, "bad freq %02x: %d %d\n", clk, khz, sclk);
+                       NV_ERROR(drm, "bad freq %02x: %d %d\n", clk, khz, sclk);
                        return -ERANGE;
                }
  
                break;
        }
  
-       ret = get_pll_limits(dev, pll, &limits);
+       ret = nvbios_pll_parse(bios, pll, &limits);
        if (ret)
                return ret;
  
  
        ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P);
        if (ret >= 0) {
-               reg->clk = nv_rd32(dev, 0x4120 + (clk * 4));
+               reg->clk = nv_rd32(device, 0x4120 + (clk * 4));
                reg->pll = (P << 16) | (N << 8) | M;
        }
        return ret;
  }
  
  static void
  prog_pll(struct drm_device *dev, int clk, u32 pll, struct creg *reg)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        const u32 src0 = 0x004120 + (clk * 4);
        const u32 src1 = 0x004160 + (clk * 4);
        const u32 ctrl = pll + 0;
        const u32 coef = pll + 4;
  
        if (!reg->clk && !reg->pll) {
-               NV_DEBUG(dev, "no clock for %02x\n", clk);
+               NV_DEBUG(drm, "no clock for %02x\n", clk);
                return;
        }
  
        if (reg->pll) {
-               nv_mask(dev, src0, 0x00000101, 0x00000101);
-               nv_wr32(dev, coef, reg->pll);
-               nv_mask(dev, ctrl, 0x00000015, 0x00000015);
-               nv_mask(dev, ctrl, 0x00000010, 0x00000000);
-               nv_wait(dev, ctrl, 0x00020000, 0x00020000);
-               nv_mask(dev, ctrl, 0x00000010, 0x00000010);
-               nv_mask(dev, ctrl, 0x00000008, 0x00000000);
-               nv_mask(dev, src1, 0x00000100, 0x00000000);
-               nv_mask(dev, src1, 0x00000001, 0x00000000);
+               nv_mask(device, src0, 0x00000101, 0x00000101);
+               nv_wr32(device, coef, reg->pll);
+               nv_mask(device, ctrl, 0x00000015, 0x00000015);
+               nv_mask(device, ctrl, 0x00000010, 0x00000000);
+               nv_wait(device, ctrl, 0x00020000, 0x00020000);
+               nv_mask(device, ctrl, 0x00000010, 0x00000010);
+               nv_mask(device, ctrl, 0x00000008, 0x00000000);
+               nv_mask(device, src1, 0x00000100, 0x00000000);
+               nv_mask(device, src1, 0x00000001, 0x00000000);
        } else {
-               nv_mask(dev, src1, 0x003f3141, 0x00000101 | reg->clk);
-               nv_mask(dev, ctrl, 0x00000018, 0x00000018);
+               nv_mask(device, src1, 0x003f3141, 0x00000101 | reg->clk);
+               nv_mask(device, ctrl, 0x00000018, 0x00000018);
                udelay(20);
-               nv_mask(dev, ctrl, 0x00000001, 0x00000000);
-               nv_mask(dev, src0, 0x00000100, 0x00000000);
-               nv_mask(dev, src0, 0x00000001, 0x00000000);
+               nv_mask(device, ctrl, 0x00000001, 0x00000000);
+               nv_mask(device, src0, 0x00000100, 0x00000000);
+               nv_mask(device, src0, 0x00000001, 0x00000000);
        }
  }
  
  static void
  prog_clk(struct drm_device *dev, int clk, struct creg *reg)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        if (!reg->clk) {
-               NV_DEBUG(dev, "no clock for %02x\n", clk);
+               NV_DEBUG(drm, "no clock for %02x\n", clk);
                return;
        }
  
-       nv_mask(dev, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | reg->clk);
+       nv_mask(device, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | reg->clk);
  }
  
  int
@@@ -309,10 -327,11 +327,11 @@@ static boo
  nva3_pm_grcp_idle(void *data)
  {
        struct drm_device *dev = data;
+       struct nouveau_device *device = nouveau_dev(dev);
  
-       if (!(nv_rd32(dev, 0x400304) & 0x00000001))
+       if (!(nv_rd32(device, 0x400304) & 0x00000001))
                return true;
-       if (nv_rd32(dev, 0x400308) == 0x0050001c)
+       if (nv_rd32(device, 0x400308) == 0x0050001c)
                return true;
        return false;
  }
  static void
  mclk_precharge(struct nouveau_mem_exec_func *exec)
  {
-       nv_wr32(exec->dev, 0x1002d4, 0x00000001);
+       struct nouveau_device *device = nouveau_dev(exec->dev);
+       nv_wr32(device, 0x1002d4, 0x00000001);
  }
  
  static void
  mclk_refresh(struct nouveau_mem_exec_func *exec)
  {
-       nv_wr32(exec->dev, 0x1002d0, 0x00000001);
+       struct nouveau_device *device = nouveau_dev(exec->dev);
+       nv_wr32(device, 0x1002d0, 0x00000001);
  }
  
  static void
  mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable)
  {
-       nv_wr32(exec->dev, 0x100210, enable ? 0x80000000 : 0x00000000);
+       struct nouveau_device *device = nouveau_dev(exec->dev);
+       nv_wr32(device, 0x100210, enable ? 0x80000000 : 0x00000000);
  }
  
  static void
  mclk_refresh_self(struct nouveau_mem_exec_func *exec, bool enable)
  {
-       nv_wr32(exec->dev, 0x1002dc, enable ? 0x00000001 : 0x00000000);
+       struct nouveau_device *device = nouveau_dev(exec->dev);
+       nv_wr32(device, 0x1002dc, enable ? 0x00000001 : 0x00000000);
  }
  
  static void
  mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec)
  {
-       volatile u32 post = nv_rd32(exec->dev, 0); (void)post;
+       struct nouveau_device *device = nouveau_dev(exec->dev);
+       volatile u32 post = nv_rd32(device, 0); (void)post;
        udelay((nsec + 500) / 1000);
  }
  
  static u32
  mclk_mrg(struct nouveau_mem_exec_func *exec, int mr)
  {
+       struct nouveau_device *device = nouveau_dev(exec->dev);
        if (mr <= 1)
-               return nv_rd32(exec->dev, 0x1002c0 + ((mr - 0) * 4));
+               return nv_rd32(device, 0x1002c0 + ((mr - 0) * 4));
        if (mr <= 3)
-               return nv_rd32(exec->dev, 0x1002e0 + ((mr - 2) * 4));
+               return nv_rd32(device, 0x1002e0 + ((mr - 2) * 4));
        return 0;
  }
  
  static void
  mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data)
  {
-       struct drm_nouveau_private *dev_priv = exec->dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(exec->dev);
+       struct nouveau_fb *pfb = nouveau_fb(device);
        if (mr <= 1) {
-               if (dev_priv->vram_rank_B)
-                       nv_wr32(exec->dev, 0x1002c8 + ((mr - 0) * 4), data);
-               nv_wr32(exec->dev, 0x1002c0 + ((mr - 0) * 4), data);
+               if (pfb->ram.ranks > 1)
+                       nv_wr32(device, 0x1002c8 + ((mr - 0) * 4), data);
+               nv_wr32(device, 0x1002c0 + ((mr - 0) * 4), data);
        } else
        if (mr <= 3) {
-               if (dev_priv->vram_rank_B)
-                       nv_wr32(exec->dev, 0x1002e8 + ((mr - 2) * 4), data);
-               nv_wr32(exec->dev, 0x1002e0 + ((mr - 2) * 4), data);
+               if (pfb->ram.ranks > 1)
+                       nv_wr32(device, 0x1002e8 + ((mr - 2) * 4), data);
+               nv_wr32(device, 0x1002e0 + ((mr - 2) * 4), data);
        }
  }
  
  static void
  mclk_clock_set(struct nouveau_mem_exec_func *exec)
  {
-       struct drm_device *dev = exec->dev;
+       struct nouveau_device *device = nouveau_dev(exec->dev);
        struct nva3_pm_state *info = exec->priv;
        u32 ctrl;
  
-       ctrl = nv_rd32(dev, 0x004000);
+       ctrl = nv_rd32(device, 0x004000);
        if (!(ctrl & 0x00000008) && info->mclk.pll) {
-               nv_wr32(dev, 0x004000, (ctrl |=  0x00000008));
-               nv_mask(dev, 0x1110e0, 0x00088000, 0x00088000);
-               nv_wr32(dev, 0x004018, 0x00001000);
-               nv_wr32(dev, 0x004000, (ctrl &= ~0x00000001));
-               nv_wr32(dev, 0x004004, info->mclk.pll);
-               nv_wr32(dev, 0x004000, (ctrl |=  0x00000001));
+               nv_wr32(device, 0x004000, (ctrl |=  0x00000008));
+               nv_mask(device, 0x1110e0, 0x00088000, 0x00088000);
+               nv_wr32(device, 0x004018, 0x00001000);
+               nv_wr32(device, 0x004000, (ctrl &= ~0x00000001));
+               nv_wr32(device, 0x004004, info->mclk.pll);
+               nv_wr32(device, 0x004000, (ctrl |=  0x00000001));
                udelay(64);
-               nv_wr32(dev, 0x004018, 0x00005000 | info->r004018);
+               nv_wr32(device, 0x004018, 0x00005000 | info->r004018);
                udelay(20);
        } else
        if (!info->mclk.pll) {
-               nv_mask(dev, 0x004168, 0x003f3040, info->mclk.clk);
-               nv_wr32(dev, 0x004000, (ctrl |= 0x00000008));
-               nv_mask(dev, 0x1110e0, 0x00088000, 0x00088000);
-               nv_wr32(dev, 0x004018, 0x0000d000 | info->r004018);
+               nv_mask(device, 0x004168, 0x003f3040, info->mclk.clk);
+               nv_wr32(device, 0x004000, (ctrl |= 0x00000008));
+               nv_mask(device, 0x1110e0, 0x00088000, 0x00088000);
+               nv_wr32(device, 0x004018, 0x0000d000 | info->r004018);
        }
  
        if (info->rammap) {
                                     (info->ramcfg[3] & 0x0f) << 16 |
                                     (info->ramcfg[9] & 0x0f) |
                                     0x80000000;
-                       nv_wr32(dev, 0x1005a0, unk5a0);
-                       nv_wr32(dev, 0x1005a4, unk5a4);
-                       nv_wr32(dev, 0x10f804, unk804);
-                       nv_mask(dev, 0x10053c, 0x00001000, 0x00000000);
+                       nv_wr32(device, 0x1005a0, unk5a0);
+                       nv_wr32(device, 0x1005a4, unk5a4);
+                       nv_wr32(device, 0x10f804, unk804);
+                       nv_mask(device, 0x10053c, 0x00001000, 0x00000000);
                } else {
-                       nv_mask(dev, 0x10053c, 0x00001000, 0x00001000);
-                       nv_mask(dev, 0x10f804, 0x80000000, 0x00000000);
-                       nv_mask(dev, 0x100760, 0x22222222, info->r100760);
-                       nv_mask(dev, 0x1007a0, 0x22222222, info->r100760);
-                       nv_mask(dev, 0x1007e0, 0x22222222, info->r100760);
+                       nv_mask(device, 0x10053c, 0x00001000, 0x00001000);
+                       nv_mask(device, 0x10f804, 0x80000000, 0x00000000);
+                       nv_mask(device, 0x100760, 0x22222222, info->r100760);
+                       nv_mask(device, 0x1007a0, 0x22222222, info->r100760);
+                       nv_mask(device, 0x1007e0, 0x22222222, info->r100760);
                }
        }
  
        if (info->mclk.pll) {
-               nv_mask(dev, 0x1110e0, 0x00088000, 0x00011000);
-               nv_wr32(dev, 0x004000, (ctrl &= ~0x00000008));
+               nv_mask(device, 0x1110e0, 0x00088000, 0x00011000);
+               nv_wr32(device, 0x004000, (ctrl &= ~0x00000008));
        }
  }
  
  static void
  mclk_timing_set(struct nouveau_mem_exec_func *exec)
  {
-       struct drm_device *dev = exec->dev;
+       struct nouveau_device *device = nouveau_dev(exec->dev);
        struct nva3_pm_state *info = exec->priv;
        struct nouveau_pm_level *perflvl = info->perflvl;
        int i;
  
        for (i = 0; i < 9; i++)
-               nv_wr32(dev, 0x100220 + (i * 4), perflvl->timing.reg[i]);
+               nv_wr32(device, 0x100220 + (i * 4), perflvl->timing.reg[i]);
  
        if (info->ramcfg) {
                u32 data = (info->ramcfg[2] & 0x08) ? 0x00000000 : 0x00001000;
-               nv_mask(dev, 0x100200, 0x00001000, data);
+               nv_mask(device, 0x100200, 0x00001000, data);
        }
  
        if (info->ramcfg) {
-               u32 unk714 = nv_rd32(dev, 0x100714) & ~0xf0000010;
-               u32 unk718 = nv_rd32(dev, 0x100718) & ~0x00000100;
-               u32 unk71c = nv_rd32(dev, 0x10071c) & ~0x00000100;
+               u32 unk714 = nv_rd32(device, 0x100714) & ~0xf0000010;
+               u32 unk718 = nv_rd32(device, 0x100718) & ~0x00000100;
+               u32 unk71c = nv_rd32(device, 0x10071c) & ~0x00000100;
                if ( (info->ramcfg[2] & 0x20))
                        unk714 |= 0xf0000000;
                if (!(info->ramcfg[2] & 0x04))
                        unk714 |= 0x00000010;
-               nv_wr32(dev, 0x100714, unk714);
+               nv_wr32(device, 0x100714, unk714);
  
                if (info->ramcfg[2] & 0x01)
                        unk71c |= 0x00000100;
-               nv_wr32(dev, 0x10071c, unk71c);
+               nv_wr32(device, 0x10071c, unk71c);
  
                if (info->ramcfg[2] & 0x02)
                        unk718 |= 0x00000100;
-               nv_wr32(dev, 0x100718, unk718);
+               nv_wr32(device, 0x100718, unk718);
  
                if (info->ramcfg[2] & 0x10)
-                       nv_wr32(dev, 0x111100, 0x48000000); /*XXX*/
+                       nv_wr32(device, 0x111100, 0x48000000); /*XXX*/
        }
  }
  
  static void
  prog_mem(struct drm_device *dev, struct nva3_pm_state *info)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        struct nouveau_mem_exec_func exec = {
                .dev = dev,
                .precharge = mclk_precharge,
                info->r100760 = 0x22222222;
        }
  
-       ctrl = nv_rd32(dev, 0x004000);
+       ctrl = nv_rd32(device, 0x004000);
        if (ctrl & 0x00000008) {
                if (info->mclk.pll) {
-                       nv_mask(dev, 0x004128, 0x00000101, 0x00000101);
-                       nv_wr32(dev, 0x004004, info->mclk.pll);
-                       nv_wr32(dev, 0x004000, (ctrl |= 0x00000001));
-                       nv_wr32(dev, 0x004000, (ctrl &= 0xffffffef));
-                       nv_wait(dev, 0x004000, 0x00020000, 0x00020000);
-                       nv_wr32(dev, 0x004000, (ctrl |= 0x00000010));
-                       nv_wr32(dev, 0x004018, 0x00005000 | info->r004018);
-                       nv_wr32(dev, 0x004000, (ctrl |= 0x00000004));
+                       nv_mask(device, 0x004128, 0x00000101, 0x00000101);
+                       nv_wr32(device, 0x004004, info->mclk.pll);
+                       nv_wr32(device, 0x004000, (ctrl |= 0x00000001));
+                       nv_wr32(device, 0x004000, (ctrl &= 0xffffffef));
+                       nv_wait(device, 0x004000, 0x00020000, 0x00020000);
+                       nv_wr32(device, 0x004000, (ctrl |= 0x00000010));
+                       nv_wr32(device, 0x004018, 0x00005000 | info->r004018);
+                       nv_wr32(device, 0x004000, (ctrl |= 0x00000004));
                }
        } else {
                u32 ssel = 0x00000101;
                        ssel |= info->mclk.clk;
                else
                        ssel |= 0x00080000; /* 324MHz, shouldn't matter... */
-               nv_mask(dev, 0x004168, 0x003f3141, ctrl);
+               nv_mask(device, 0x004168, 0x003f3141, ctrl);
        }
  
        if (info->ramcfg) {
                if (info->ramcfg[2] & 0x10) {
-                       nv_mask(dev, 0x111104, 0x00000600, 0x00000000);
+                       nv_mask(device, 0x111104, 0x00000600, 0x00000000);
                } else {
-                       nv_mask(dev, 0x111100, 0x40000000, 0x40000000);
-                       nv_mask(dev, 0x111104, 0x00000180, 0x00000000);
+                       nv_mask(device, 0x111100, 0x40000000, 0x40000000);
+                       nv_mask(device, 0x111104, 0x00000180, 0x00000000);
                }
        }
        if (info->rammap && !(info->rammap[4] & 0x02))
-               nv_mask(dev, 0x100200, 0x00000800, 0x00000000);
-       nv_wr32(dev, 0x611200, 0x00003300);
+               nv_mask(device, 0x100200, 0x00000800, 0x00000000);
+       nv_wr32(device, 0x611200, 0x00003300);
        if (!(info->ramcfg[2] & 0x10))
-               nv_wr32(dev, 0x111100, 0x4c020000); /*XXX*/
+               nv_wr32(device, 0x111100, 0x4c020000); /*XXX*/
  
        nouveau_mem_exec(&exec, info->perflvl);
  
-       nv_wr32(dev, 0x611200, 0x00003330);
+       nv_wr32(device, 0x611200, 0x00003330);
        if (info->rammap && (info->rammap[4] & 0x02))
-               nv_mask(dev, 0x100200, 0x00000800, 0x00000800);
+               nv_mask(device, 0x100200, 0x00000800, 0x00000800);
        if (info->ramcfg) {
                if (info->ramcfg[2] & 0x10) {
-                       nv_mask(dev, 0x111104, 0x00000180, 0x00000180);
-                       nv_mask(dev, 0x111100, 0x40000000, 0x00000000);
+                       nv_mask(device, 0x111104, 0x00000180, 0x00000180);
+                       nv_mask(device, 0x111100, 0x40000000, 0x00000000);
                } else {
-                       nv_mask(dev, 0x111104, 0x00000600, 0x00000600);
+                       nv_mask(device, 0x111104, 0x00000600, 0x00000600);
                }
        }
  
        if (info->mclk.pll) {
-               nv_mask(dev, 0x004168, 0x00000001, 0x00000000);
-               nv_mask(dev, 0x004168, 0x00000100, 0x00000000);
+               nv_mask(device, 0x004168, 0x00000001, 0x00000000);
+               nv_mask(device, 0x004168, 0x00000100, 0x00000000);
        } else {
-               nv_mask(dev, 0x004000, 0x00000001, 0x00000000);
-               nv_mask(dev, 0x004128, 0x00000001, 0x00000000);
-               nv_mask(dev, 0x004128, 0x00000100, 0x00000000);
+               nv_mask(device, 0x004000, 0x00000001, 0x00000000);
+               nv_mask(device, 0x004128, 0x00000001, 0x00000000);
+               nv_mask(device, 0x004128, 0x00000100, 0x00000000);
        }
  }
  
  int
  nva3_pm_clocks_set(struct drm_device *dev, void *pre_state)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nva3_pm_state *info = pre_state;
-       unsigned long flags;
        int ret = -EAGAIN;
  
        /* prevent any new grctx switches from starting */
-       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       nv_wr32(dev, 0x400324, 0x00000000);
-       nv_wr32(dev, 0x400328, 0x0050001c); /* wait flag 0x1c */
+       nv_wr32(device, 0x400324, 0x00000000);
+       nv_wr32(device, 0x400328, 0x0050001c); /* wait flag 0x1c */
        /* wait for any pending grctx switches to complete */
-       if (!nv_wait_cb(dev, nva3_pm_grcp_idle, dev)) {
-               NV_ERROR(dev, "pm: ctxprog didn't go idle\n");
+       if (!nv_wait_cb(device, nva3_pm_grcp_idle, dev)) {
+               NV_ERROR(drm, "pm: ctxprog didn't go idle\n");
                goto cleanup;
        }
        /* freeze PFIFO */
-       nv_mask(dev, 0x002504, 0x00000001, 0x00000001);
-       if (!nv_wait(dev, 0x002504, 0x00000010, 0x00000010)) {
-               NV_ERROR(dev, "pm: fifo didn't go idle\n");
+       nv_mask(device, 0x002504, 0x00000001, 0x00000001);
+       if (!nv_wait(device, 0x002504, 0x00000010, 0x00000010)) {
+               NV_ERROR(drm, "pm: fifo didn't go idle\n");
                goto cleanup;
        }
  
  
  cleanup:
        /* unfreeze PFIFO */
-       nv_mask(dev, 0x002504, 0x00000001, 0x00000000);
+       nv_mask(device, 0x002504, 0x00000001, 0x00000000);
        /* restore ctxprog to normal */
-       nv_wr32(dev, 0x400324, 0x00000000);
-       nv_wr32(dev, 0x400328, 0x0070009c); /* set flag 0x1c */
+       nv_wr32(device, 0x400324, 0x00000000);
+       nv_wr32(device, 0x400328, 0x0070009c); /* set flag 0x1c */
        /* unblock it if necessary */
-       if (nv_rd32(dev, 0x400308) == 0x0050001c)
-               nv_mask(dev, 0x400824, 0x10000000, 0x10000000);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+       if (nv_rd32(device, 0x400308) == 0x0050001c)
+               nv_mask(device, 0x400824, 0x10000000, 0x10000000);
        kfree(info);
        return ret;
  }
  
  #include <linux/dma-mapping.h>
  
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
  
- #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_dma.h"
+ #include "nouveau_gem.h"
  #include "nouveau_connector.h"
  #include "nouveau_encoder.h"
  #include "nouveau_crtc.h"
- #include "nouveau_dma.h"
- #include "nouveau_fb.h"
- #include "nouveau_software.h"
+ #include "nouveau_fence.h"
  #include "nv50_display.h"
  
+ #include <core/gpuobj.h>
+ #include <subdev/timer.h>
+ #include <subdev/bar.h>
+ #include <subdev/fb.h>
  #define EVO_DMA_NR 9
  
  #define EVO_MASTER  (0x00)
@@@ -72,8 -78,7 +78,7 @@@ struct nvd0_display 
  static struct nvd0_display *
  nvd0_display(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       return dev_priv->engine.display.priv;
+       return nouveau_display(dev)->priv;
  }
  
  static struct drm_crtc *
@@@ -88,55 -93,47 +93,47 @@@ nvd0_display_crtc_get(struct drm_encode
  static inline int
  evo_icmd(struct drm_device *dev, int id, u32 mthd, u32 data)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        int ret = 0;
-       nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000001);
-       nv_wr32(dev, 0x610704 + (id * 0x10), data);
-       nv_mask(dev, 0x610704 + (id * 0x10), 0x80000ffc, 0x80000000 | mthd);
-       if (!nv_wait(dev, 0x610704 + (id * 0x10), 0x80000000, 0x00000000))
+       nv_mask(device, 0x610700 + (id * 0x10), 0x00000001, 0x00000001);
+       nv_wr32(device, 0x610704 + (id * 0x10), data);
+       nv_mask(device, 0x610704 + (id * 0x10), 0x80000ffc, 0x80000000 | mthd);
+       if (!nv_wait(device, 0x610704 + (id * 0x10), 0x80000000, 0x00000000))
                ret = -EBUSY;
-       nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000000);
+       nv_mask(device, 0x610700 + (id * 0x10), 0x00000001, 0x00000000);
        return ret;
  }
  
  static u32 *
  evo_wait(struct drm_device *dev, int id, int nr)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nvd0_display *disp = nvd0_display(dev);
-       u32 put = nv_rd32(dev, 0x640000 + (id * 0x1000)) / 4;
+       u32 put = nv_rd32(device, 0x640000 + (id * 0x1000)) / 4;
  
        if (put + nr >= (PAGE_SIZE / 4)) {
                disp->evo[id].ptr[put] = 0x20000000;
  
-               nv_wr32(dev, 0x640000 + (id * 0x1000), 0x00000000);
-               if (!nv_wait(dev, 0x640004 + (id * 0x1000), ~0, 0x00000000)) {
-                       NV_ERROR(dev, "evo %d dma stalled\n", id);
+               nv_wr32(device, 0x640000 + (id * 0x1000), 0x00000000);
+               if (!nv_wait(device, 0x640004 + (id * 0x1000), ~0, 0x00000000)) {
+                       NV_ERROR(drm, "evo %d dma stalled\n", id);
                        return NULL;
                }
  
                put = 0;
        }
  
-       if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
-               NV_INFO(dev, "Evo%d: %p START\n", id, disp->evo[id].ptr + put);
        return disp->evo[id].ptr + put;
  }
  
  static void
  evo_kick(u32 *push, struct drm_device *dev, int id)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        struct nvd0_display *disp = nvd0_display(dev);
  
-       if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO) {
-               u32 curp = nv_rd32(dev, 0x640000 + (id * 0x1000)) >> 2;
-               u32 *cur = disp->evo[id].ptr + curp;
-               while (cur < push)
-                       NV_INFO(dev, "Evo%d: 0x%08x\n", id, *cur++);
-               NV_INFO(dev, "Evo%d: %p KICK!\n", id, push);
-       }
-       nv_wr32(dev, 0x640000 + (id * 0x1000), (push - disp->evo[id].ptr) << 2);
+       nv_wr32(device, 0x640000 + (id * 0x1000), (push - disp->evo[id].ptr) << 2);
  }
  
  #define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m))
  static int
  evo_init_dma(struct drm_device *dev, int ch)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nvd0_display *disp = nvd0_display(dev);
        u32 flags;
  
        if (ch == EVO_MASTER)
                flags |= 0x01000000;
  
-       nv_wr32(dev, 0x610494 + (ch * 0x0010), (disp->evo[ch].handle >> 8) | 3);
-       nv_wr32(dev, 0x610498 + (ch * 0x0010), 0x00010000);
-       nv_wr32(dev, 0x61049c + (ch * 0x0010), 0x00000001);
-       nv_mask(dev, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000010);
-       nv_wr32(dev, 0x640000 + (ch * 0x1000), 0x00000000);
-       nv_wr32(dev, 0x610490 + (ch * 0x0010), 0x00000013 | flags);
-       if (!nv_wait(dev, 0x610490 + (ch * 0x0010), 0x80000000, 0x00000000)) {
-               NV_ERROR(dev, "PDISP: ch%d 0x%08x\n", ch,
-                             nv_rd32(dev, 0x610490 + (ch * 0x0010)));
+       nv_wr32(device, 0x610494 + (ch * 0x0010), (disp->evo[ch].handle >> 8) | 3);
+       nv_wr32(device, 0x610498 + (ch * 0x0010), 0x00010000);
+       nv_wr32(device, 0x61049c + (ch * 0x0010), 0x00000001);
+       nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000010);
+       nv_wr32(device, 0x640000 + (ch * 0x1000), 0x00000000);
+       nv_wr32(device, 0x610490 + (ch * 0x0010), 0x00000013 | flags);
+       if (!nv_wait(device, 0x610490 + (ch * 0x0010), 0x80000000, 0x00000000)) {
+               NV_ERROR(drm, "PDISP: ch%d 0x%08x\n", ch,
+                             nv_rd32(device, 0x610490 + (ch * 0x0010)));
                return -EBUSY;
        }
  
-       nv_mask(dev, 0x610090, (1 << ch), (1 << ch));
-       nv_mask(dev, 0x6100a0, (1 << ch), (1 << ch));
+       nv_mask(device, 0x610090, (1 << ch), (1 << ch));
+       nv_mask(device, 0x6100a0, (1 << ch), (1 << ch));
        return 0;
  }
  
  static void
  evo_fini_dma(struct drm_device *dev, int ch)
  {
-       if (!(nv_rd32(dev, 0x610490 + (ch * 0x0010)) & 0x00000010))
+       struct nouveau_device *device = nouveau_dev(dev);
+       if (!(nv_rd32(device, 0x610490 + (ch * 0x0010)) & 0x00000010))
                return;
  
-       nv_mask(dev, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000000);
-       nv_mask(dev, 0x610490 + (ch * 0x0010), 0x00000003, 0x00000000);
-       nv_wait(dev, 0x610490 + (ch * 0x0010), 0x80000000, 0x00000000);
-       nv_mask(dev, 0x610090, (1 << ch), 0x00000000);
-       nv_mask(dev, 0x6100a0, (1 << ch), 0x00000000);
+       nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000000);
+       nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000003, 0x00000000);
+       nv_wait(device, 0x610490 + (ch * 0x0010), 0x80000000, 0x00000000);
+       nv_mask(device, 0x610090, (1 << ch), 0x00000000);
+       nv_mask(device, 0x6100a0, (1 << ch), 0x00000000);
  }
  
  static inline void
  evo_piow(struct drm_device *dev, int ch, u16 mthd, u32 data)
  {
-       nv_wr32(dev, 0x640000 + (ch * 0x1000) + mthd, data);
+       struct nouveau_device *device = nouveau_dev(dev);
+       nv_wr32(device, 0x640000 + (ch * 0x1000) + mthd, data);
  }
  
  static int
  evo_init_pio(struct drm_device *dev, int ch)
  {
-       nv_wr32(dev, 0x610490 + (ch * 0x0010), 0x00000001);
-       if (!nv_wait(dev, 0x610490 + (ch * 0x0010), 0x00010000, 0x00010000)) {
-               NV_ERROR(dev, "PDISP: ch%d 0x%08x\n", ch,
-                             nv_rd32(dev, 0x610490 + (ch * 0x0010)));
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       nv_wr32(device, 0x610490 + (ch * 0x0010), 0x00000001);
+       if (!nv_wait(device, 0x610490 + (ch * 0x0010), 0x00010000, 0x00010000)) {
+               NV_ERROR(drm, "PDISP: ch%d 0x%08x\n", ch,
+                             nv_rd32(device, 0x610490 + (ch * 0x0010)));
                return -EBUSY;
        }
  
-       nv_mask(dev, 0x610090, (1 << ch), (1 << ch));
-       nv_mask(dev, 0x6100a0, (1 << ch), (1 << ch));
+       nv_mask(device, 0x610090, (1 << ch), (1 << ch));
+       nv_mask(device, 0x6100a0, (1 << ch), (1 << ch));
        return 0;
  }
  
  static void
  evo_fini_pio(struct drm_device *dev, int ch)
  {
-       if (!(nv_rd32(dev, 0x610490 + (ch * 0x0010)) & 0x00000001))
+       struct nouveau_device *device = nouveau_dev(dev);
+       if (!(nv_rd32(device, 0x610490 + (ch * 0x0010)) & 0x00000001))
                return;
  
-       nv_mask(dev, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000010);
-       nv_mask(dev, 0x610490 + (ch * 0x0010), 0x00000001, 0x00000000);
-       nv_wait(dev, 0x610490 + (ch * 0x0010), 0x00010000, 0x00000000);
-       nv_mask(dev, 0x610090, (1 << ch), 0x00000000);
-       nv_mask(dev, 0x6100a0, (1 << ch), 0x00000000);
+       nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000010);
+       nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000001, 0x00000000);
+       nv_wait(device, 0x610490 + (ch * 0x0010), 0x00010000, 0x00000000);
+       nv_mask(device, 0x610090, (1 << ch), 0x00000000);
+       nv_mask(device, 0x6100a0, (1 << ch), 0x00000000);
  }
  
  static bool
@@@ -225,6 -232,7 +232,7 @@@ evo_sync_wait(void *data
  static int
  evo_sync(struct drm_device *dev, int ch)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        struct nvd0_display *disp = nvd0_display(dev);
        u32 *push = evo_wait(dev, ch, 8);
        if (push) {
                evo_data(push, 0x00000000);
                evo_data(push, 0x00000000);
                evo_kick(push, dev, ch);
-               if (nv_wait_cb(dev, evo_sync_wait, disp->sync))
+               if (nv_wait_cb(device, evo_sync_wait, disp->sync))
                        return 0;
        }
  
@@@ -300,7 -308,7 +308,7 @@@ nvd0_display_flip_next(struct drm_crtc 
                        return ret;
  
  
-               offset  = nvc0_software_crtc(chan, nv_crtc->index);
+               offset  = nvc0_fence_crtc(chan, nv_crtc->index);
                offset += evo->sem.offset;
  
                BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
  static int
  nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
  {
-       struct drm_nouveau_private *dev_priv = nv_crtc->base.dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(nv_crtc->base.dev);
        struct drm_device *dev = nv_crtc->base.dev;
        struct nouveau_connector *nv_connector;
        struct drm_connector *connector;
                mode |= nv_connector->dithering_depth;
        }
  
-       if (dev_priv->card_type < NV_E0)
+       if (nv_device(drm->device)->card_type < NV_E0)
                mthd = 0x0490 + (nv_crtc->index * 0x0300);
        else
                mthd = 0x04a0 + (nv_crtc->index * 0x0300);
@@@ -701,11 -709,12 +709,12 @@@ static in
  nvd0_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
                        struct drm_framebuffer *old_fb)
  {
+       struct nouveau_drm *drm = nouveau_drm(crtc->dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        int ret;
  
        if (!crtc->fb) {
-               NV_DEBUG_KMS(crtc->dev, "No FB bound\n");
+               NV_DEBUG(drm, "No FB bound\n");
                return 0;
        }
  
@@@ -923,6 -932,7 +932,7 @@@ nvd0_dac_dpms(struct drm_encoder *encod
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_device *dev = encoder->dev;
+       struct nouveau_device *device = nouveau_dev(dev);
        int or = nv_encoder->or;
        u32 dpms_ctrl;
  
        if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF)
                dpms_ctrl |= 0x00000004;
  
-       nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
-       nv_mask(dev, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl);
-       nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
+       nv_wait(device, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
+       nv_mask(device, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl);
+       nv_wait(device, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
  }
  
  static bool
@@@ -1025,18 -1035,19 +1035,19 @@@ nvd0_dac_detect(struct drm_encoder *enc
        enum drm_connector_status status = connector_status_disconnected;
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_device *dev = encoder->dev;
+       struct nouveau_device *device = nouveau_dev(dev);
        int or = nv_encoder->or;
        u32 load;
  
-       nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00100000);
+       nv_wr32(device, 0x61a00c + (or * 0x800), 0x00100000);
        udelay(9500);
-       nv_wr32(dev, 0x61a00c + (or * 0x800), 0x80000000);
+       nv_wr32(device, 0x61a00c + (or * 0x800), 0x80000000);
  
-       load = nv_rd32(dev, 0x61a00c + (or * 0x800));
+       load = nv_rd32(device, 0x61a00c + (or * 0x800));
        if ((load & 0x38000000) == 0x38000000)
                status = connector_status_connected;
  
-       nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00000000);
+       nv_wr32(device, 0x61a00c + (or * 0x800), 0x00000000);
        return status;
  }
  
@@@ -1063,7 -1074,7 +1074,7 @@@ static const struct drm_encoder_funcs n
  };
  
  static int
- nvd0_dac_create(struct drm_connector *connector, struct dcb_entry *dcbe)
+ nvd0_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
  {
        struct drm_device *dev = connector->dev;
        struct nouveau_encoder *nv_encoder;
@@@ -1094,24 -1105,25 +1105,25 @@@ nvd0_audio_mode_set(struct drm_encoder 
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct nouveau_connector *nv_connector;
        struct drm_device *dev = encoder->dev;
+       struct nouveau_device *device = nouveau_dev(dev);
        int i, or = nv_encoder->or * 0x30;
  
        nv_connector = nouveau_encoder_connector_get(nv_encoder);
        if (!drm_detect_monitor_audio(nv_connector->edid))
                return;
  
-       nv_mask(dev, 0x10ec10 + or, 0x80000003, 0x80000001);
+       nv_mask(device, 0x10ec10 + or, 0x80000003, 0x80000001);
  
        drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
        if (nv_connector->base.eld[0]) {
                u8 *eld = nv_connector->base.eld;
  
                for (i = 0; i < eld[2] * 4; i++)
-                       nv_wr32(dev, 0x10ec00 + or, (i << 8) | eld[i]);
+                       nv_wr32(device, 0x10ec00 + or, (i << 8) | eld[i]);
                for (i = eld[2] * 4; i < 0x60; i++)
-                       nv_wr32(dev, 0x10ec00 + or, (i << 8) | 0x00);
+                       nv_wr32(device, 0x10ec00 + or, (i << 8) | 0x00);
  
-               nv_mask(dev, 0x10ec10 + or, 0x80000002, 0x80000002);
+               nv_mask(device, 0x10ec10 + or, 0x80000002, 0x80000002);
        }
  }
  
@@@ -1120,9 -1132,10 +1132,10 @@@ nvd0_audio_disconnect(struct drm_encode
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_device *dev = encoder->dev;
+       struct nouveau_device *device = nouveau_dev(dev);
        int or = nv_encoder->or * 0x30;
  
-       nv_mask(dev, 0x10ec10 + or, 0x80000003, 0x80000000);
+       nv_mask(device, 0x10ec10 + or, 0x80000003, 0x80000000);
  }
  
  /******************************************************************************
@@@ -1135,6 -1148,7 +1148,7 @@@ nvd0_hdmi_mode_set(struct drm_encoder *
        struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
        struct nouveau_connector *nv_connector;
        struct drm_device *dev = encoder->dev;
+       struct nouveau_device *device = nouveau_dev(dev);
        int head = nv_crtc->index * 0x800;
        u32 rekey = 56; /* binary driver, and tegra constant */
        u32 max_ac_packet;
        max_ac_packet /= 32;
  
        /* AVI InfoFrame */
-       nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000000);
-       nv_wr32(dev, 0x61671c + head, 0x000d0282);
-       nv_wr32(dev, 0x616720 + head, 0x0000006f);
-       nv_wr32(dev, 0x616724 + head, 0x00000000);
-       nv_wr32(dev, 0x616728 + head, 0x00000000);
-       nv_wr32(dev, 0x61672c + head, 0x00000000);
-       nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000001);
+       nv_mask(device, 0x616714 + head, 0x00000001, 0x00000000);
+       nv_wr32(device, 0x61671c + head, 0x000d0282);
+       nv_wr32(device, 0x616720 + head, 0x0000006f);
+       nv_wr32(device, 0x616724 + head, 0x00000000);
+       nv_wr32(device, 0x616728 + head, 0x00000000);
+       nv_wr32(device, 0x61672c + head, 0x00000000);
+       nv_mask(device, 0x616714 + head, 0x00000001, 0x00000001);
  
        /* ??? InfoFrame? */
-       nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000000);
-       nv_wr32(dev, 0x6167ac + head, 0x00000010);
-       nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000001);
+       nv_mask(device, 0x6167a4 + head, 0x00000001, 0x00000000);
+       nv_wr32(device, 0x6167ac + head, 0x00000010);
+       nv_mask(device, 0x6167a4 + head, 0x00000001, 0x00000001);
  
        /* HDMI_CTRL */
-       nv_mask(dev, 0x616798 + head, 0x401f007f, 0x40000000 | rekey |
+       nv_mask(device, 0x616798 + head, 0x401f007f, 0x40000000 | rekey |
                                                  max_ac_packet << 16);
  
        /* NFI, audio doesn't work without it though.. */
-       nv_mask(dev, 0x616548 + head, 0x00000070, 0x00000000);
+       nv_mask(device, 0x616548 + head, 0x00000070, 0x00000000);
  
        nvd0_audio_mode_set(encoder, mode);
  }
@@@ -1178,37 -1192,41 +1192,41 @@@ nvd0_hdmi_disconnect(struct drm_encode
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
        struct drm_device *dev = encoder->dev;
+       struct nouveau_device *device = nouveau_dev(dev);
        int head = nv_crtc->index * 0x800;
  
        nvd0_audio_disconnect(encoder);
  
-       nv_mask(dev, 0x616798 + head, 0x40000000, 0x00000000);
-       nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000000);
-       nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000000);
+       nv_mask(device, 0x616798 + head, 0x40000000, 0x00000000);
+       nv_mask(device, 0x6167a4 + head, 0x00000001, 0x00000000);
+       nv_mask(device, 0x616714 + head, 0x00000001, 0x00000000);
  }
  
  /******************************************************************************
   * SOR
   *****************************************************************************/
  static inline u32
- nvd0_sor_dp_lane_map(struct drm_device *dev, struct dcb_entry *dcb, u8 lane)
+ nvd0_sor_dp_lane_map(struct drm_device *dev, struct dcb_output *dcb, u8 lane)
  {
        static const u8 nvd0[] = { 16, 8, 0, 24 };
        return nvd0[lane];
  }
  
  static void
- nvd0_sor_dp_train_set(struct drm_device *dev, struct dcb_entry *dcb, u8 pattern)
+ nvd0_sor_dp_train_set(struct drm_device *dev, struct dcb_output *dcb, u8 pattern)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
        const u32 loff = (or * 0x800) + (link * 0x80);
-       nv_mask(dev, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
+       nv_mask(device, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
  }
  
  static void
- nvd0_sor_dp_train_adj(struct drm_device *dev, struct dcb_entry *dcb,
+ nvd0_sor_dp_train_adj(struct drm_device *dev, struct dcb_output *dcb,
                      u8 lane, u8 swing, u8 preem)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
        const u32 loff = (or * 0x800) + (link * 0x80);
        u32 shift = nvd0_sor_dp_lane_map(dev, dcb, lane);
        }
  
        if (!config) {
-               NV_ERROR(dev, "PDISP: unsupported DP table for chipset\n");
+               NV_ERROR(drm, "PDISP: unsupported DP table for chipset\n");
                return;
        }
  
-       nv_mask(dev, 0x61c118 + loff, mask, config[1] << shift);
-       nv_mask(dev, 0x61c120 + loff, mask, config[2] << shift);
-       nv_mask(dev, 0x61c130 + loff, 0x0000ff00, config[3] << 8);
-       nv_mask(dev, 0x61c13c + loff, 0x00000000, 0x00000000);
+       nv_mask(device, 0x61c118 + loff, mask, config[1] << shift);
+       nv_mask(device, 0x61c120 + loff, mask, config[2] << shift);
+       nv_mask(device, 0x61c130 + loff, 0x0000ff00, config[3] << 8);
+       nv_mask(device, 0x61c13c + loff, 0x00000000, 0x00000000);
  }
  
  static void
- nvd0_sor_dp_link_set(struct drm_device *dev, struct dcb_entry *dcb, int crtc,
+ nvd0_sor_dp_link_set(struct drm_device *dev, struct dcb_output *dcb, int crtc,
                     int link_nr, u32 link_bw, bool enhframe)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
        const u32 loff = (or * 0x800) + (link * 0x80);
        const u32 soff = (or * 0x800);
-       u32 dpctrl = nv_rd32(dev, 0x61c10c + loff) & ~0x001f4000;
-       u32 clksor = nv_rd32(dev, 0x612300 + soff) & ~0x007c0000;
+       u32 dpctrl = nv_rd32(device, 0x61c10c + loff) & ~0x001f4000;
+       u32 clksor = nv_rd32(device, 0x612300 + soff) & ~0x007c0000;
        u32 script = 0x0000, lane_mask = 0;
        u8 *table, *entry;
        int i;
        for (i = 0; i < link_nr; i++)
                lane_mask |= 1 << (nvd0_sor_dp_lane_map(dev, dcb, i) >> 3);
  
-       nv_wr32(dev, 0x612300 + soff, clksor);
-       nv_wr32(dev, 0x61c10c + loff, dpctrl);
-       nv_mask(dev, 0x61c130 + loff, 0x0000000f, lane_mask);
+       nv_wr32(device, 0x612300 + soff, clksor);
+       nv_wr32(device, 0x61c10c + loff, dpctrl);
+       nv_mask(device, 0x61c130 + loff, 0x0000000f, lane_mask);
  }
  
  static void
- nvd0_sor_dp_link_get(struct drm_device *dev, struct dcb_entry *dcb,
+ nvd0_sor_dp_link_get(struct drm_device *dev, struct dcb_output *dcb,
                     u32 *link_nr, u32 *link_bw)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
        const u32 loff = (or * 0x800) + (link * 0x80);
        const u32 soff = (or * 0x800);
-       u32 dpctrl = nv_rd32(dev, 0x61c10c + loff) & 0x000f0000;
-       u32 clksor = nv_rd32(dev, 0x612300 + soff);
+       u32 dpctrl = nv_rd32(device, 0x61c10c + loff) & 0x000f0000;
+       u32 clksor = nv_rd32(device, 0x612300 + soff);
  
        if      (dpctrl > 0x00030000) *link_nr = 4;
        else if (dpctrl > 0x00010000) *link_nr = 2;
  }
  
  static void
- nvd0_sor_dp_calc_tu(struct drm_device *dev, struct dcb_entry *dcb,
+ nvd0_sor_dp_calc_tu(struct drm_device *dev, struct dcb_output *dcb,
                    u32 crtc, u32 datarate)
  {
+       struct nouveau_device *device = nouveau_dev(dev);
        const u32 symbol = 100000;
        const u32 TU = 64;
        u32 link_nr, link_bw;
        value += 5;
        value |= 0x08000000;
  
-       nv_wr32(dev, 0x616610 + (crtc * 0x800), value);
+       nv_wr32(device, 0x616610 + (crtc * 0x800), value);
  }
  
  static void
@@@ -1338,6 -1359,7 +1359,7 @@@ nvd0_sor_dpms(struct drm_encoder *encod
  {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_device *dev = encoder->dev;
+       struct nouveau_device *device = nouveau_dev(dev);
        struct drm_encoder *partner;
        int or = nv_encoder->or;
        u32 dpms_ctrl;
        dpms_ctrl  = (mode == DRM_MODE_DPMS_ON);
        dpms_ctrl |= 0x80000000;
  
-       nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
-       nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl);
-       nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
-       nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000);
+       nv_wait(device, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
+       nv_mask(device, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl);
+       nv_wait(device, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
+       nv_wait(device, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000);
  
-       if (nv_encoder->dcb->type == OUTPUT_DP) {
+       if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
                struct dp_train_func func = {
                        .link_set = nvd0_sor_dp_link_set,
                        .train_set = nvd0_sor_dp_train_set,
@@@ -1427,7 -1449,7 +1449,7 @@@ static voi
  nvd0_sor_prepare(struct drm_encoder *encoder)
  {
        nvd0_sor_disconnect(encoder);
-       if (nouveau_encoder(encoder)->dcb->type == OUTPUT_DP)
+       if (nouveau_encoder(encoder)->dcb->type == DCB_OUTPUT_DP)
                evo_sync(encoder->dev, EVO_MASTER);
  }
  
@@@ -1441,11 -1463,11 +1463,11 @@@ nvd0_sor_mode_set(struct drm_encoder *e
                  struct drm_display_mode *mode)
  {
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
        struct nouveau_connector *nv_connector;
-       struct nvbios *bios = &dev_priv->vbios;
+       struct nvbios *bios = &drm->vbios;
        u32 mode_ctrl = (1 << nv_crtc->index);
        u32 syncs, magic, *push;
        u32 or_config;
  
        nv_connector = nouveau_encoder_connector_get(nv_encoder);
        switch (nv_encoder->dcb->type) {
-       case OUTPUT_TMDS:
+       case DCB_OUTPUT_TMDS:
                if (nv_encoder->dcb->sorconf.link & 1) {
                        if (mode->clock < 165000)
                                mode_ctrl |= 0x00000100;
  
                nvd0_hdmi_mode_set(encoder, mode);
                break;
-       case OUTPUT_LVDS:
+       case DCB_OUTPUT_LVDS:
                or_config = (mode_ctrl & 0x00000f00) >> 8;
                if (bios->fp_no_ddc) {
                        if (bios->fp.dual_link)
  
                }
                break;
-       case OUTPUT_DP:
+       case DCB_OUTPUT_DP:
                if (nv_connector->base.display_info.bpc == 6) {
                        nv_encoder->dp.datarate = mode->clock * 18 / 8;
                        syncs |= 0x00000002 << 6;
  
        nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON);
  
-       if (nv_encoder->dcb->type == OUTPUT_DP) {
+       if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
                nvd0_sor_dp_calc_tu(dev, nv_encoder->dcb, nv_crtc->index,
                                         nv_encoder->dp.datarate);
        }
@@@ -1571,7 -1593,7 +1593,7 @@@ static const struct drm_encoder_funcs n
  };
  
  static int
- nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe)
+ nvd0_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
  {
        struct drm_device *dev = connector->dev;
        struct nouveau_encoder *nv_encoder;
  /******************************************************************************
   * IRQ
   *****************************************************************************/
- static struct dcb_entry *
+ static struct dcb_output *
  lookup_dcb(struct drm_device *dev, int id, u32 mc)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(dev);
        int type, or, i, link = -1;
  
        if (id < 4) {
-               type = OUTPUT_ANALOG;
+               type = DCB_OUTPUT_ANALOG;
                or   = id;
        } else {
                switch (mc & 0x00000f00) {
-               case 0x00000000: link = 0; type = OUTPUT_LVDS; break;
-               case 0x00000100: link = 0; type = OUTPUT_TMDS; break;
-               case 0x00000200: link = 1; type = OUTPUT_TMDS; break;
-               case 0x00000500: link = 0; type = OUTPUT_TMDS; break;
-               case 0x00000800: link = 0; type = OUTPUT_DP; break;
-               case 0x00000900: link = 1; type = OUTPUT_DP; break;
+               case 0x00000000: link = 0; type = DCB_OUTPUT_LVDS; break;
+               case 0x00000100: link = 0; type = DCB_OUTPUT_TMDS; break;
+               case 0x00000200: link = 1; type = DCB_OUTPUT_TMDS; break;
+               case 0x00000500: link = 0; type = DCB_OUTPUT_TMDS; break;
+               case 0x00000800: link = 0; type = DCB_OUTPUT_DP; break;
+               case 0x00000900: link = 1; type = DCB_OUTPUT_DP; break;
                default:
-                       NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc);
+                       NV_ERROR(drm, "PDISP: unknown SOR mc 0x%08x\n", mc);
                        return NULL;
                }
  
                or = id - 4;
        }
  
-       for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
-               struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
+       for (i = 0; i < drm->vbios.dcb.entries; i++) {
+               struct dcb_output *dcb = &drm->vbios.dcb.entry[i];
                if (dcb->type == type && (dcb->or & (1 << or)) &&
                    (link < 0 || link == !(dcb->sorconf.link & 1)))
                        return dcb;
        }
  
-       NV_ERROR(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc);
+       NV_ERROR(drm, "PDISP: DCB for %d/0x%08x not found\n", id, mc);
        return NULL;
  }
  
  static void
  nvd0_display_unk1_handler(struct drm_device *dev, u32 crtc, u32 mask)
  {
-       struct dcb_entry *dcb;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct dcb_output *dcb;
        int i;
  
        for (i = 0; mask && i < 8; i++) {
-               u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
+               u32 mcc = nv_rd32(device, 0x640180 + (i * 0x20));
                if (!(mcc & (1 << crtc)))
                        continue;
  
                nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc);
        }
  
-       nv_wr32(dev, 0x6101d4, 0x00000000);
-       nv_wr32(dev, 0x6109d4, 0x00000000);
-       nv_wr32(dev, 0x6101d0, 0x80000000);
+       nv_wr32(device, 0x6101d4, 0x00000000);
+       nv_wr32(device, 0x6109d4, 0x00000000);
+       nv_wr32(device, 0x6101d0, 0x80000000);
  }
  
  static void
  nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask)
  {
-       struct dcb_entry *dcb;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct dcb_output *dcb;
        u32 or, tmp, pclk;
        int i;
  
        for (i = 0; mask && i < 8; i++) {
-               u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
+               u32 mcc = nv_rd32(device, 0x640180 + (i * 0x20));
                if (!(mcc & (1 << crtc)))
                        continue;
  
                nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc);
        }
  
-       pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
-       NV_DEBUG_KMS(dev, "PDISP: crtc %d pclk %d mask 0x%08x\n",
+       pclk = nv_rd32(device, 0x660450 + (crtc * 0x300)) / 1000;
+       NV_DEBUG(drm, "PDISP: crtc %d pclk %d mask 0x%08x\n",
                          crtc, pclk, mask);
        if (pclk && (mask & 0x00010000)) {
                nv50_crtc_set_clock(dev, crtc, pclk);
        }
  
        for (i = 0; mask && i < 8; i++) {
-               u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
-               u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
+               u32 mcp = nv_rd32(device, 0x660180 + (i * 0x20));
+               u32 cfg = nv_rd32(device, 0x660184 + (i * 0x20));
                if (!(mcp & (1 << crtc)))
                        continue;
  
  
                nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc);
  
-               nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000);
+               nv_wr32(device, 0x612200 + (crtc * 0x800), 0x00000000);
                switch (dcb->type) {
-               case OUTPUT_ANALOG:
-                       nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000);
+               case DCB_OUTPUT_ANALOG:
+                       nv_wr32(device, 0x612280 + (or * 0x800), 0x00000000);
                        break;
-               case OUTPUT_TMDS:
-               case OUTPUT_LVDS:
-               case OUTPUT_DP:
+               case DCB_OUTPUT_TMDS:
+               case DCB_OUTPUT_LVDS:
+               case DCB_OUTPUT_DP:
                        if (cfg & 0x00000100)
                                tmp = 0x00000101;
                        else
                                tmp = 0x00000000;
  
-                       nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp);
+                       nv_mask(device, 0x612300 + (or * 0x800), 0x00000707, tmp);
                        break;
                default:
                        break;
                break;
        }
  
-       nv_wr32(dev, 0x6101d4, 0x00000000);
-       nv_wr32(dev, 0x6109d4, 0x00000000);
-       nv_wr32(dev, 0x6101d0, 0x80000000);
+       nv_wr32(device, 0x6101d4, 0x00000000);
+       nv_wr32(device, 0x6109d4, 0x00000000);
+       nv_wr32(device, 0x6101d0, 0x80000000);
  }
  
  static void
  nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask)
  {
-       struct dcb_entry *dcb;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct dcb_output *dcb;
        int pclk, i;
  
-       pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
+       pclk = nv_rd32(device, 0x660450 + (crtc * 0x300)) / 1000;
  
        for (i = 0; mask && i < 8; i++) {
-               u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
-               u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
+               u32 mcp = nv_rd32(device, 0x660180 + (i * 0x20));
+               u32 cfg = nv_rd32(device, 0x660184 + (i * 0x20));
                if (!(mcp & (1 << crtc)))
                        continue;
  
                nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc);
        }
  
-       nv_wr32(dev, 0x6101d4, 0x00000000);
-       nv_wr32(dev, 0x6109d4, 0x00000000);
-       nv_wr32(dev, 0x6101d0, 0x80000000);
+       nv_wr32(device, 0x6101d4, 0x00000000);
+       nv_wr32(device, 0x6109d4, 0x00000000);
+       nv_wr32(device, 0x6101d0, 0x80000000);
  }
  
  static void
  nvd0_display_bh(unsigned long data)
  {
        struct drm_device *dev = (struct drm_device *)data;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        struct nvd0_display *disp = nvd0_display(dev);
        u32 mask = 0, crtc = ~0;
        int i;
  
        if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) {
-               NV_INFO(dev, "PDISP: modeset req %d\n", disp->modeset);
-               NV_INFO(dev, " STAT: 0x%08x 0x%08x 0x%08x\n",
-                        nv_rd32(dev, 0x6101d0),
-                        nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4));
+               NV_INFO(drm, "PDISP: modeset req %d\n", disp->modeset);
+               NV_INFO(drm, " STAT: 0x%08x 0x%08x 0x%08x\n",
+                        nv_rd32(device, 0x6101d0),
+                        nv_rd32(device, 0x6101d4), nv_rd32(device, 0x6109d4));
                for (i = 0; i < 8; i++) {
-                       NV_INFO(dev, " %s%d: 0x%08x 0x%08x\n",
+                       NV_INFO(drm, " %s%d: 0x%08x 0x%08x\n",
                                i < 4 ? "DAC" : "SOR", i,
-                               nv_rd32(dev, 0x640180 + (i * 0x20)),
-                               nv_rd32(dev, 0x660180 + (i * 0x20)));
+                               nv_rd32(device, 0x640180 + (i * 0x20)),
+                               nv_rd32(device, 0x660180 + (i * 0x20)));
                }
        }
  
        while (!mask && ++crtc < dev->mode_config.num_crtc)
-               mask = nv_rd32(dev, 0x6101d4 + (crtc * 0x800));
+               mask = nv_rd32(device, 0x6101d4 + (crtc * 0x800));
  
        if (disp->modeset & 0x00000001)
                nvd0_display_unk1_handler(dev, crtc, mask);
                nvd0_display_unk4_handler(dev, crtc, mask);
  }
  
static void
+ void
  nvd0_display_intr(struct drm_device *dev)
  {
        struct nvd0_display *disp = nvd0_display(dev);
-       u32 intr = nv_rd32(dev, 0x610088);
-       int i;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       u32 intr = nv_rd32(device, 0x610088);
  
        if (intr & 0x00000001) {
-               u32 stat = nv_rd32(dev, 0x61008c);
-               nv_wr32(dev, 0x61008c, stat);
+               u32 stat = nv_rd32(device, 0x61008c);
+               nv_wr32(device, 0x61008c, stat);
                intr &= ~0x00000001;
        }
  
        if (intr & 0x00000002) {
-               u32 stat = nv_rd32(dev, 0x61009c);
+               u32 stat = nv_rd32(device, 0x61009c);
                int chid = ffs(stat) - 1;
                if (chid >= 0) {
-                       u32 mthd = nv_rd32(dev, 0x6101f0 + (chid * 12));
-                       u32 data = nv_rd32(dev, 0x6101f4 + (chid * 12));
-                       u32 unkn = nv_rd32(dev, 0x6101f8 + (chid * 12));
+                       u32 mthd = nv_rd32(device, 0x6101f0 + (chid * 12));
+                       u32 data = nv_rd32(device, 0x6101f4 + (chid * 12));
+                       u32 unkn = nv_rd32(device, 0x6101f8 + (chid * 12));
  
-                       NV_INFO(dev, "EvoCh: chid %d mthd 0x%04x data 0x%08x "
+                       NV_INFO(drm, "EvoCh: chid %d mthd 0x%04x data 0x%08x "
                                     "0x%08x 0x%08x\n",
                                chid, (mthd & 0x0000ffc), data, mthd, unkn);
-                       nv_wr32(dev, 0x61009c, (1 << chid));
-                       nv_wr32(dev, 0x6101f0 + (chid * 12), 0x90000000);
+                       nv_wr32(device, 0x61009c, (1 << chid));
+                       nv_wr32(device, 0x6101f0 + (chid * 12), 0x90000000);
                }
  
                intr &= ~0x00000002;
        }
  
        if (intr & 0x00100000) {
-               u32 stat = nv_rd32(dev, 0x6100ac);
+               u32 stat = nv_rd32(device, 0x6100ac);
  
                if (stat & 0x00000007) {
                        disp->modeset = stat;
                        tasklet_schedule(&disp->tasklet);
  
-                       nv_wr32(dev, 0x6100ac, (stat & 0x00000007));
+                       nv_wr32(device, 0x6100ac, (stat & 0x00000007));
                        stat &= ~0x00000007;
                }
  
                if (stat) {
-                       NV_INFO(dev, "PDISP: unknown intr24 0x%08x\n", stat);
-                       nv_wr32(dev, 0x6100ac, stat);
+                       NV_INFO(drm, "PDISP: unknown intr24 0x%08x\n", stat);
+                       nv_wr32(device, 0x6100ac, stat);
                }
  
                intr &= ~0x00100000;
        }
  
-       for (i = 0; i < dev->mode_config.num_crtc; i++) {
-               u32 mask = 0x01000000 << i;
-               if (intr & mask) {
-                       u32 stat = nv_rd32(dev, 0x6100bc + (i * 0x800));
-                       nv_wr32(dev, 0x6100bc + (i * 0x800), stat);
-                       intr &= ~mask;
-               }
-       }
+       intr &= ~0x0f000000; /* vblank, handled in core */
        if (intr)
-               NV_INFO(dev, "PDISP: unknown intr 0x%08x\n", intr);
+               NV_INFO(drm, "PDISP: unknown intr 0x%08x\n", intr);
  }
  
  /******************************************************************************
  nvd0_display_init(struct drm_device *dev)
  {
        struct nvd0_display *disp = nvd0_display(dev);
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
        int ret, i;
        u32 *push;
  
-       if (nv_rd32(dev, 0x6100ac) & 0x00000100) {
-               nv_wr32(dev, 0x6100ac, 0x00000100);
-               nv_mask(dev, 0x6194e8, 0x00000001, 0x00000000);
-               if (!nv_wait(dev, 0x6194e8, 0x00000002, 0x00000000)) {
-                       NV_ERROR(dev, "PDISP: 0x6194e8 0x%08x\n",
-                                nv_rd32(dev, 0x6194e8));
+       if (nv_rd32(device, 0x6100ac) & 0x00000100) {
+               nv_wr32(device, 0x6100ac, 0x00000100);
+               nv_mask(device, 0x6194e8, 0x00000001, 0x00000000);
+               if (!nv_wait(device, 0x6194e8, 0x00000002, 0x00000000)) {
+                       NV_ERROR(drm, "PDISP: 0x6194e8 0x%08x\n",
+                                nv_rd32(device, 0x6194e8));
                        return -EBUSY;
                }
        }
         * work at all unless you do the SOR part below.
         */
        for (i = 0; i < 3; i++) {
-               u32 dac = nv_rd32(dev, 0x61a000 + (i * 0x800));
-               nv_wr32(dev, 0x6101c0 + (i * 0x800), dac);
+               u32 dac = nv_rd32(device, 0x61a000 + (i * 0x800));
+               nv_wr32(device, 0x6101c0 + (i * 0x800), dac);
        }
  
        for (i = 0; i < 4; i++) {
-               u32 sor = nv_rd32(dev, 0x61c000 + (i * 0x800));
-               nv_wr32(dev, 0x6301c4 + (i * 0x800), sor);
+               u32 sor = nv_rd32(device, 0x61c000 + (i * 0x800));
+               nv_wr32(device, 0x6301c4 + (i * 0x800), sor);
        }
  
        for (i = 0; i < dev->mode_config.num_crtc; i++) {
-               u32 crtc0 = nv_rd32(dev, 0x616104 + (i * 0x800));
-               u32 crtc1 = nv_rd32(dev, 0x616108 + (i * 0x800));
-               u32 crtc2 = nv_rd32(dev, 0x61610c + (i * 0x800));
-               nv_wr32(dev, 0x6101b4 + (i * 0x800), crtc0);
-               nv_wr32(dev, 0x6101b8 + (i * 0x800), crtc1);
-               nv_wr32(dev, 0x6101bc + (i * 0x800), crtc2);
+               u32 crtc0 = nv_rd32(device, 0x616104 + (i * 0x800));
+               u32 crtc1 = nv_rd32(device, 0x616108 + (i * 0x800));
+               u32 crtc2 = nv_rd32(device, 0x61610c + (i * 0x800));
+               nv_wr32(device, 0x6101b4 + (i * 0x800), crtc0);
+               nv_wr32(device, 0x6101b8 + (i * 0x800), crtc1);
+               nv_wr32(device, 0x6101bc + (i * 0x800), crtc2);
        }
  
        /* point at our hash table / objects, enable interrupts */
-       nv_wr32(dev, 0x610010, (disp->mem->vinst >> 8) | 9);
-       nv_mask(dev, 0x6100b0, 0x00000307, 0x00000307);
+       nv_wr32(device, 0x610010, (disp->mem->addr >> 8) | 9);
+       nv_mask(device, 0x6100b0, 0x00000307, 0x00000307);
  
        /* init master */
        ret = evo_init_dma(dev, EVO_MASTER);
@@@ -1944,7 -1967,6 +1967,6 @@@ error
  void
  nvd0_display_destroy(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nvd0_display *disp = nvd0_display(dev);
        struct pci_dev *pdev = dev->pdev;
        int i;
        nouveau_gpuobj_ref(NULL, &disp->mem);
        nouveau_bo_unmap(disp->sync);
        nouveau_bo_ref(NULL, &disp->sync);
-       nouveau_irq_unregister(dev, 26);
  
-       dev_priv->engine.display.priv = NULL;
+       nouveau_display(dev)->priv = NULL;
        kfree(disp);
  }
  
  int
  nvd0_display_create(struct drm_device *dev)
  {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
-       struct dcb_table *dcb = &dev_priv->vbios.dcb;
+       struct nouveau_device *device = nouveau_dev(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_bar *bar = nouveau_bar(device);
+       struct nouveau_fb *pfb = nouveau_fb(device);
+       struct dcb_table *dcb = &drm->vbios.dcb;
        struct drm_connector *connector, *tmp;
        struct pci_dev *pdev = dev->pdev;
        struct nvd0_display *disp;
-       struct dcb_entry *dcbe;
+       struct dcb_output *dcbe;
        int crtcs, ret, i;
  
        disp = kzalloc(sizeof(*disp), GFP_KERNEL);
        if (!disp)
                return -ENOMEM;
-       dev_priv->engine.display.priv = disp;
+       nouveau_display(dev)->priv = disp;
+       nouveau_display(dev)->dtor = nvd0_display_destroy;
+       nouveau_display(dev)->init = nvd0_display_init;
+       nouveau_display(dev)->fini = nvd0_display_fini;
  
        /* create crtc objects to represent the hw heads */
-       crtcs = nv_rd32(dev, 0x022448);
+       crtcs = nv_rd32(device, 0x022448);
        for (i = 0; i < crtcs; i++) {
                ret = nvd0_crtc_create(dev, i);
                if (ret)
                        continue;
  
                if (dcbe->location != DCB_LOC_ON_CHIP) {
-                       NV_WARN(dev, "skipping off-chip encoder %d/%d\n",
+                       NV_WARN(drm, "skipping off-chip encoder %d/%d\n",
                                dcbe->type, ffs(dcbe->or) - 1);
                        continue;
                }
  
                switch (dcbe->type) {
-               case OUTPUT_TMDS:
-               case OUTPUT_LVDS:
-               case OUTPUT_DP:
+               case DCB_OUTPUT_TMDS:
+               case DCB_OUTPUT_LVDS:
+               case DCB_OUTPUT_DP:
                        nvd0_sor_create(connector, dcbe);
                        break;
-               case OUTPUT_ANALOG:
+               case DCB_OUTPUT_ANALOG:
                        nvd0_dac_create(connector, dcbe);
                        break;
                default:
-                       NV_WARN(dev, "skipping unsupported encoder %d/%d\n",
+                       NV_WARN(drm, "skipping unsupported encoder %d/%d\n",
                                dcbe->type, ffs(dcbe->or) - 1);
                        continue;
                }
                if (connector->encoder_ids[0])
                        continue;
  
-               NV_WARN(dev, "%s has no encoders, removing\n",
+               NV_WARN(drm, "%s has no encoders, removing\n",
                        drm_get_connector_name(connector));
                connector->funcs->destroy(connector);
        }
  
        /* setup interrupt handling */
        tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev);
-       nouveau_irq_register(dev, 26, nvd0_display_intr);
  
        /* small shared memory area we use for notifiers and semaphores */
        ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
                goto out;
  
        /* hash table and dma objects for the memory areas we care about */
-       ret = nouveau_gpuobj_new(dev, NULL, 0x4000, 0x10000,
+       ret = nouveau_gpuobj_new(nv_object(device), NULL, 0x4000, 0x10000,
                                 NVOBJ_FLAG_ZERO_ALLOC, &disp->mem);
        if (ret)
                goto out;
  
                nv_wo32(disp->mem, dmao + 0x20, 0x00000049);
                nv_wo32(disp->mem, dmao + 0x24, 0x00000000);
-               nv_wo32(disp->mem, dmao + 0x28, (dev_priv->vram_size - 1) >> 8);
+               nv_wo32(disp->mem, dmao + 0x28, (pfb->ram.size - 1) >> 8);
                nv_wo32(disp->mem, dmao + 0x2c, 0x00000000);
                nv_wo32(disp->mem, dmao + 0x30, 0x00000000);
                nv_wo32(disp->mem, dmao + 0x34, 0x00000000);
  
                nv_wo32(disp->mem, dmao + 0x40, 0x00000009);
                nv_wo32(disp->mem, dmao + 0x44, 0x00000000);
-               nv_wo32(disp->mem, dmao + 0x48, (dev_priv->vram_size - 1) >> 8);
+               nv_wo32(disp->mem, dmao + 0x48, (pfb->ram.size - 1) >> 8);
                nv_wo32(disp->mem, dmao + 0x4c, 0x00000000);
                nv_wo32(disp->mem, dmao + 0x50, 0x00000000);
                nv_wo32(disp->mem, dmao + 0x54, 0x00000000);
  
                nv_wo32(disp->mem, dmao + 0x60, 0x0fe00009);
                nv_wo32(disp->mem, dmao + 0x64, 0x00000000);
-               nv_wo32(disp->mem, dmao + 0x68, (dev_priv->vram_size - 1) >> 8);
+               nv_wo32(disp->mem, dmao + 0x68, (pfb->ram.size - 1) >> 8);
                nv_wo32(disp->mem, dmao + 0x6c, 0x00000000);
                nv_wo32(disp->mem, dmao + 0x70, 0x00000000);
                nv_wo32(disp->mem, dmao + 0x74, 0x00000000);
                                                ((dmao + 0x60) << 9));
        }
  
-       pinstmem->flush(dev);
+       bar->flush(bar);
  
  out:
        if (ret)
   *          Alex Deucher
   *          Jerome Glisse
   */
 -#include "drmP.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  
  #include "atom.h"
  #include "atom-bits.h"
 -#include "drm_dp_helper.h"
 +#include <drm/drm_dp_helper.h>
  
  /* move these to drm_dp_helper.c/h */
  #define DP_LINK_CONFIGURATION_SIZE 9
@@@ -653,9 -653,7 +653,7 @@@ static bool radeon_dp_get_link_status(s
                return false;
        }
  
-       DRM_DEBUG_KMS("link status %02x %02x %02x %02x %02x %02x\n",
-                 link_status[0], link_status[1], link_status[2],
-                 link_status[3], link_status[4], link_status[5]);
+       DRM_DEBUG_KMS("link status %*ph\n", 6, link_status);
        return true;
  }
  
   * Authors: Dave Airlie
   *          Alex Deucher
   */
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  #include "atom.h"
+ #include <linux/backlight.h>
  
  extern int atom_debug;
  
+ static u8
+ radeon_atom_get_backlight_level_from_reg(struct radeon_device *rdev)
+ {
+       u8 backlight_level;
+       u32 bios_2_scratch;
+       if (rdev->family >= CHIP_R600)
+               bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
+       else
+               bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
+       backlight_level = ((bios_2_scratch & ATOM_S2_CURRENT_BL_LEVEL_MASK) >>
+                          ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
+       return backlight_level;
+ }
+ static void
+ radeon_atom_set_backlight_level_to_reg(struct radeon_device *rdev,
+                                      u8 backlight_level)
+ {
+       u32 bios_2_scratch;
+       if (rdev->family >= CHIP_R600)
+               bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
+       else
+               bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
+       bios_2_scratch &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;
+       bios_2_scratch |= ((backlight_level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT) &
+                          ATOM_S2_CURRENT_BL_LEVEL_MASK);
+       if (rdev->family >= CHIP_R600)
+               WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
+       else
+               WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
+ }
+ u8
+ atombios_get_backlight_level(struct radeon_encoder *radeon_encoder)
+ {
+       struct drm_device *dev = radeon_encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
+               return 0;
+       return radeon_atom_get_backlight_level_from_reg(rdev);
+ }
+ void
+ atombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level)
+ {
+       struct drm_encoder *encoder = &radeon_encoder->base;
+       struct drm_device *dev = radeon_encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder_atom_dig *dig;
+       DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
+       int index;
+       if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
+               return;
+       if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) &&
+           radeon_encoder->enc_priv) {
+               dig = radeon_encoder->enc_priv;
+               dig->backlight_level = level;
+               radeon_atom_set_backlight_level_to_reg(rdev, dig->backlight_level);
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_INTERNAL_LVDS:
+               case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+                       index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
+                       if (dig->backlight_level == 0) {
+                               args.ucAction = ATOM_LCD_BLOFF;
+                               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+                       } else {
+                               args.ucAction = ATOM_LCD_BL_BRIGHTNESS_CONTROL;
+                               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+                               args.ucAction = ATOM_LCD_BLON;
+                               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+                       }
+                       break;
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+                       if (dig->backlight_level == 0)
+                               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
+                       else {
+                               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL, 0, 0);
+                               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+ }
+ #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
+ static u8 radeon_atom_bl_level(struct backlight_device *bd)
+ {
+       u8 level;
+       /* Convert brightness to hardware level */
+       if (bd->props.brightness < 0)
+               level = 0;
+       else if (bd->props.brightness > RADEON_MAX_BL_LEVEL)
+               level = RADEON_MAX_BL_LEVEL;
+       else
+               level = bd->props.brightness;
+       return level;
+ }
+ static int radeon_atom_backlight_update_status(struct backlight_device *bd)
+ {
+       struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+       struct radeon_encoder *radeon_encoder = pdata->encoder;
+       atombios_set_backlight_level(radeon_encoder, radeon_atom_bl_level(bd));
+       return 0;
+ }
+ static int radeon_atom_backlight_get_brightness(struct backlight_device *bd)
+ {
+       struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+       struct radeon_encoder *radeon_encoder = pdata->encoder;
+       struct drm_device *dev = radeon_encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       return radeon_atom_get_backlight_level_from_reg(rdev);
+ }
+ static const struct backlight_ops radeon_atom_backlight_ops = {
+       .get_brightness = radeon_atom_backlight_get_brightness,
+       .update_status  = radeon_atom_backlight_update_status,
+ };
+ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,
+                               struct drm_connector *drm_connector)
+ {
+       struct drm_device *dev = radeon_encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct backlight_device *bd;
+       struct backlight_properties props;
+       struct radeon_backlight_privdata *pdata;
+       struct radeon_encoder_atom_dig *dig;
+       u8 backlight_level;
+       if (!radeon_encoder->enc_priv)
+               return;
+       if (!rdev->is_atom_bios)
+               return;
+       if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
+               return;
+       pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
+       if (!pdata) {
+               DRM_ERROR("Memory allocation failed\n");
+               goto error;
+       }
+       memset(&props, 0, sizeof(props));
+       props.max_brightness = RADEON_MAX_BL_LEVEL;
+       props.type = BACKLIGHT_RAW;
+       bd = backlight_device_register("radeon_bl", &drm_connector->kdev,
+                                      pdata, &radeon_atom_backlight_ops, &props);
+       if (IS_ERR(bd)) {
+               DRM_ERROR("Backlight registration failed\n");
+               goto error;
+       }
+       pdata->encoder = radeon_encoder;
+       backlight_level = radeon_atom_get_backlight_level_from_reg(rdev);
+       dig = radeon_encoder->enc_priv;
+       dig->bl_dev = bd;
+       bd->props.brightness = radeon_atom_backlight_get_brightness(bd);
+       bd->props.power = FB_BLANK_UNBLANK;
+       backlight_update_status(bd);
+       DRM_INFO("radeon atom DIG backlight initialized\n");
+       return;
+ error:
+       kfree(pdata);
+       return;
+ }
+ static void radeon_atom_backlight_exit(struct radeon_encoder *radeon_encoder)
+ {
+       struct drm_device *dev = radeon_encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct backlight_device *bd = NULL;
+       struct radeon_encoder_atom_dig *dig;
+       if (!radeon_encoder->enc_priv)
+               return;
+       if (!rdev->is_atom_bios)
+               return;
+       if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
+               return;
+       dig = radeon_encoder->enc_priv;
+       bd = dig->bl_dev;
+       dig->bl_dev = NULL;
+       if (bd) {
+               struct radeon_legacy_backlight_privdata *pdata;
+               pdata = bl_get_data(bd);
+               backlight_device_unregister(bd);
+               kfree(pdata);
+               DRM_INFO("radeon atom LVDS backlight unloaded\n");
+       }
+ }
+ #else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */
+ void radeon_atom_backlight_init(struct radeon_encoder *encoder)
+ {
+ }
+ static void radeon_atom_backlight_exit(struct radeon_encoder *encoder)
+ {
+ }
+ #endif
  /* evil but including atombios.h is much worse */
  bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
                                struct drm_display_mode *mode);
@@@ -209,6 -451,32 +451,32 @@@ atombios_tv_setup(struct drm_encoder *e
  
  }
  
+ static u8 radeon_atom_get_bpc(struct drm_encoder *encoder)
+ {
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       int bpc = 8;
+       if (connector)
+               bpc = radeon_get_monitor_bpc(connector);
+       switch (bpc) {
+       case 0:
+               return PANEL_BPC_UNDEFINE;
+       case 6:
+               return PANEL_6BIT_PER_COLOR;
+       case 8:
+       default:
+               return PANEL_8BIT_PER_COLOR;
+       case 10:
+               return PANEL_10BIT_PER_COLOR;
+       case 12:
+               return PANEL_12BIT_PER_COLOR;
+       case 16:
+               return PANEL_16BIT_PER_COLOR;
+       }
+ }
  union dvo_encoder_control {
        ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds;
        DVO_ENCODER_CONTROL_PS_ALLOCATION dvo;
@@@ -406,7 -674,8 +674,8 @@@ atombios_get_encoder_mode(struct drm_en
                return ATOM_ENCODER_MODE_DP;
  
        /* DVO is always DVO */
-       if (radeon_encoder->encoder_id == ATOM_ENCODER_MODE_DVO)
+       if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DVO1) ||
+           (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1))
                return ATOM_ENCODER_MODE_DVO;
  
        connector = radeon_get_connector_for_encoder(encoder);
@@@ -535,7 -804,6 +804,6 @@@ atombios_dig_encoder_setup(struct drm_e
        int dp_clock = 0;
        int dp_lane_count = 0;
        int hpd_id = RADEON_HPD_NONE;
-       int bpc = 8;
  
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                dp_clock = dig_connector->dp_clock;
                dp_lane_count = dig_connector->dp_lane_count;
                hpd_id = radeon_connector->hpd.hpd;
-               bpc = radeon_get_monitor_bpc(connector);
        }
  
        /* no dig encoder assigned */
                        else
                                args.v3.ucEncoderMode = atombios_get_encoder_mode(encoder);
  
-                       if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode))
+                       if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode))
                                args.v3.ucLaneNum = dp_lane_count;
                        else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
                                args.v3.ucLaneNum = 8;
                        else
                                args.v3.ucLaneNum = 4;
  
-                       if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000))
+                       if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000))
                                args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
                        args.v3.acConfig.ucDigSel = dig->dig_encoder;
-                       switch (bpc) {
-                       case 0:
-                               args.v3.ucBitPerColor = PANEL_BPC_UNDEFINE;
-                               break;
-                       case 6:
-                               args.v3.ucBitPerColor = PANEL_6BIT_PER_COLOR;
-                               break;
-                       case 8:
-                       default:
-                               args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR;
-                               break;
-                       case 10:
-                               args.v3.ucBitPerColor = PANEL_10BIT_PER_COLOR;
-                               break;
-                       case 12:
-                               args.v3.ucBitPerColor = PANEL_12BIT_PER_COLOR;
-                               break;
-                       case 16:
-                               args.v3.ucBitPerColor = PANEL_16BIT_PER_COLOR;
-                               break;
-                       }
+                       args.v3.ucBitPerColor = radeon_atom_get_bpc(encoder);
                        break;
                case 4:
                        args.v4.ucAction = action;
                        else
                                args.v4.ucEncoderMode = atombios_get_encoder_mode(encoder);
  
-                       if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode))
+                       if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode))
                                args.v4.ucLaneNum = dp_lane_count;
                        else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
                                args.v4.ucLaneNum = 8;
                        else
                                args.v4.ucLaneNum = 4;
  
-                       if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) {
+                       if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) {
                                if (dp_clock == 270000)
                                        args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ;
                                else if (dp_clock == 540000)
                                        args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ;
                        }
                        args.v4.acConfig.ucDigSel = dig->dig_encoder;
-                       switch (bpc) {
-                       case 0:
-                               args.v4.ucBitPerColor = PANEL_BPC_UNDEFINE;
-                               break;
-                       case 6:
-                               args.v4.ucBitPerColor = PANEL_6BIT_PER_COLOR;
-                               break;
-                       case 8:
-                       default:
-                               args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR;
-                               break;
-                       case 10:
-                               args.v4.ucBitPerColor = PANEL_10BIT_PER_COLOR;
-                               break;
-                       case 12:
-                               args.v4.ucBitPerColor = PANEL_12BIT_PER_COLOR;
-                               break;
-                       case 16:
-                               args.v4.ucBitPerColor = PANEL_16BIT_PER_COLOR;
-                               break;
-                       }
+                       args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder);
                        if (hpd_id == RADEON_HPD_NONE)
                                args.v4.ucHPD_ID = 0;
                        else
@@@ -799,8 -1026,7 +1026,7 @@@ atombios_dig_transmitter_setup(struct d
                                args.v1.asMode.ucLaneSet = lane_set;
                        } else {
                                if (is_dp)
-                                       args.v1.usPixelClock =
-                                               cpu_to_le16(dp_clock / 10);
+                                       args.v1.usPixelClock = cpu_to_le16(dp_clock / 10);
                                else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
                                        args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
                                else
                                args.v2.asMode.ucLaneSet = lane_set;
                        } else {
                                if (is_dp)
-                                       args.v2.usPixelClock =
-                                               cpu_to_le16(dp_clock / 10);
+                                       args.v2.usPixelClock = cpu_to_le16(dp_clock / 10);
                                else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
                                        args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
                                else
                                args.v3.asMode.ucLaneSet = lane_set;
                        } else {
                                if (is_dp)
-                                       args.v3.usPixelClock =
-                                               cpu_to_le16(dp_clock / 10);
+                                       args.v3.usPixelClock = cpu_to_le16(dp_clock / 10);
                                else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
                                        args.v3.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
                                else
                                args.v4.asMode.ucLaneSet = lane_set;
                        } else {
                                if (is_dp)
-                                       args.v4.usPixelClock =
-                                               cpu_to_le16(dp_clock / 10);
+                                       args.v4.usPixelClock = cpu_to_le16(dp_clock / 10);
                                else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
                                        args.v4.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
                                else
@@@ -1147,7 -1370,6 +1370,6 @@@ atombios_external_encoder_setup(struct 
        int dp_lane_count = 0;
        int connector_object_id = 0;
        u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
-       int bpc = 8;
  
        if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
                connector = radeon_get_connector_for_encoder_init(encoder);
                dp_lane_count = dig_connector->dp_lane_count;
                connector_object_id =
                        (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
-               bpc = radeon_get_monitor_bpc(connector);
        }
  
        memset(&args, 0, sizeof(args));
                                args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3;
                                break;
                        }
-                       switch (bpc) {
-                       case 0:
-                               args.v3.sExtEncoder.ucBitPerColor = PANEL_BPC_UNDEFINE;
-                               break;
-                       case 6:
-                               args.v3.sExtEncoder.ucBitPerColor = PANEL_6BIT_PER_COLOR;
-                               break;
-                       case 8:
-                       default:
-                               args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR;
-                               break;
-                       case 10:
-                               args.v3.sExtEncoder.ucBitPerColor = PANEL_10BIT_PER_COLOR;
-                               break;
-                       case 12:
-                               args.v3.sExtEncoder.ucBitPerColor = PANEL_12BIT_PER_COLOR;
-                               break;
-                       case 16:
-                               args.v3.sExtEncoder.ucBitPerColor = PANEL_16BIT_PER_COLOR;
-                               break;
-                       }
+                       args.v3.sExtEncoder.ucBitPerColor = radeon_atom_get_bpc(encoder);
                        break;
                default:
                        DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
@@@ -2286,6 -2487,8 +2487,8 @@@ static const struct drm_encoder_helper_
  void radeon_enc_destroy(struct drm_encoder *encoder)
  {
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+               radeon_atom_backlight_exit(radeon_encoder);
        kfree(radeon_encoder->enc_priv);
        drm_encoder_cleanup(encoder);
        kfree(radeon_encoder);
@@@ -2295,7 -2498,7 +2498,7 @@@ static const struct drm_encoder_funcs r
        .destroy = radeon_enc_destroy,
  };
  
- struct radeon_encoder_atom_dac *
+ static struct radeon_encoder_atom_dac *
  radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder)
  {
        struct drm_device *dev = radeon_encoder->base.dev;
        return dac;
  }
  
- struct radeon_encoder_atom_dig *
+ static struct radeon_encoder_atom_dig *
  radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder)
  {
        int encoder_enum = (radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
  #include <linux/firmware.h>
  #include <linux/platform_device.h>
  #include <linux/slab.h>
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "radeon.h"
  #include "radeon_asic.h"
 -#include "radeon_drm.h"
 +#include <drm/radeon_drm.h>
  #include "evergreend.h"
  #include "atom.h"
  #include "avivod.h"
  #define EVERGREEN_PFP_UCODE_SIZE 1120
  #define EVERGREEN_PM4_UCODE_SIZE 1376
  
+ static const u32 crtc_offsets[6] =
+ {
+       EVERGREEN_CRTC0_REGISTER_OFFSET,
+       EVERGREEN_CRTC1_REGISTER_OFFSET,
+       EVERGREEN_CRTC2_REGISTER_OFFSET,
+       EVERGREEN_CRTC3_REGISTER_OFFSET,
+       EVERGREEN_CRTC4_REGISTER_OFFSET,
+       EVERGREEN_CRTC5_REGISTER_OFFSET
+ };
  static void evergreen_gpu_init(struct radeon_device *rdev);
  void evergreen_fini(struct radeon_device *rdev);
  void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
@@@ -77,9 -87,13 +87,9 @@@ void evergreen_tiling_fields(unsigned t
  void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)
  {
        u16 ctl, v;
 -      int cap, err;
 +      int err;
  
 -      cap = pci_pcie_cap(rdev->pdev);
 -      if (!cap)
 -              return;
 -
 -      err = pci_read_config_word(rdev->pdev, cap + PCI_EXP_DEVCTL, &ctl);
 +      err = pcie_capability_read_word(rdev->pdev, PCI_EXP_DEVCTL, &ctl);
        if (err)
                return;
  
        if ((v == 0) || (v == 6) || (v == 7)) {
                ctl &= ~PCI_EXP_DEVCTL_READRQ;
                ctl |= (2 << 12);
 -              pci_write_config_word(rdev->pdev, cap + PCI_EXP_DEVCTL, ctl);
 +              pcie_capability_write_word(rdev->pdev, PCI_EXP_DEVCTL, ctl);
        }
  }
  
   */
  void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc)
  {
-       struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
        int i;
  
-       if (RREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_MASTER_EN) {
+       if (crtc >= rdev->num_crtc)
+               return;
+       if (RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[crtc]) & EVERGREEN_CRTC_MASTER_EN) {
                for (i = 0; i < rdev->usec_timeout; i++) {
-                       if (!(RREG32(EVERGREEN_CRTC_STATUS + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_V_BLANK))
+                       if (!(RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK))
                                break;
                        udelay(1);
                }
                for (i = 0; i < rdev->usec_timeout; i++) {
-                       if (RREG32(EVERGREEN_CRTC_STATUS + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_V_BLANK)
+                       if (RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK)
                                break;
                        udelay(1);
                }
@@@ -310,6 -326,64 +322,64 @@@ void sumo_pm_init_profile(struct radeon
  }
  
  /**
+  * btc_pm_init_profile - Initialize power profiles callback.
+  *
+  * @rdev: radeon_device pointer
+  *
+  * Initialize the power states used in profile mode
+  * (BTC, cayman).
+  * Used for profile mode only.
+  */
+ void btc_pm_init_profile(struct radeon_device *rdev)
+ {
+       int idx;
+       /* default */
+       rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+       rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+       rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2;
+       /* starting with BTC, there is one state that is used for both
+        * MH and SH.  Difference is that we always use the high clock index for
+        * mclk.
+        */
+       if (rdev->flags & RADEON_IS_MOBILITY)
+               idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0);
+       else
+               idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
+       /* low sh */
+       rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0;
+       /* mid sh */
+       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1;
+       /* high sh */
+       rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2;
+       /* low mh */
+       rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0;
+       /* mid mh */
+       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1;
+       /* high mh */
+       rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2;
+ }
+ /**
   * evergreen_pm_misc - set additional pm hw parameters callback.
   *
   * @rdev: radeon_device pointer
@@@ -1105,7 -1179,7 +1175,7 @@@ void evergreen_pcie_gart_tlb_flush(stru
        }
  }
  
- int evergreen_pcie_gart_enable(struct radeon_device *rdev)
static int evergreen_pcie_gart_enable(struct radeon_device *rdev)
  {
        u32 tmp;
        int r;
        return 0;
  }
  
- void evergreen_pcie_gart_disable(struct radeon_device *rdev)
static void evergreen_pcie_gart_disable(struct radeon_device *rdev)
  {
        u32 tmp;
  
        radeon_gart_table_vram_unpin(rdev);
  }
  
- void evergreen_pcie_gart_fini(struct radeon_device *rdev)
static void evergreen_pcie_gart_fini(struct radeon_device *rdev)
  {
        evergreen_pcie_gart_disable(rdev);
        radeon_gart_table_vram_free(rdev);
  }
  
  
- void evergreen_agp_enable(struct radeon_device *rdev)
static void evergreen_agp_enable(struct radeon_device *rdev)
  {
        u32 tmp;
  
  
  void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
  {
+       u32 crtc_enabled, tmp, frame_count, blackout;
+       int i, j;
        save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
        save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
  
-       /* Stop all video */
+       /* disable VGA render */
        WREG32(VGA_RENDER_CONTROL, 0);
-       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
-       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
-       if (rdev->num_crtc >= 4) {
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
-       }
-       if (rdev->num_crtc >= 6) {
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
-       }
-       WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
-       WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
-       if (rdev->num_crtc >= 4) {
-               WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
-               WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
-       }
-       if (rdev->num_crtc >= 6) {
-               WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
-               WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
-       }
-       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
-       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
-       if (rdev->num_crtc >= 4) {
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
-       }
-       if (rdev->num_crtc >= 6) {
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+       /* blank the display controllers */
+       for (i = 0; i < rdev->num_crtc; i++) {
+               crtc_enabled = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]) & EVERGREEN_CRTC_MASTER_EN;
+               if (crtc_enabled) {
+                       save->crtc_enabled[i] = true;
+                       if (ASIC_IS_DCE6(rdev)) {
+                               tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]);
+                               if (!(tmp & EVERGREEN_CRTC_BLANK_DATA_EN)) {
+                                       radeon_wait_for_vblank(rdev, i);
+                                       tmp |= EVERGREEN_CRTC_BLANK_DATA_EN;
+                                       WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp);
+                               }
+                       } else {
+                               tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
+                               if (!(tmp & EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE)) {
+                                       radeon_wait_for_vblank(rdev, i);
+                                       tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE;
+                                       WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp);
+                               }
+                       }
+                       /* wait for the next frame */
+                       frame_count = radeon_get_vblank_counter(rdev, i);
+                       for (j = 0; j < rdev->usec_timeout; j++) {
+                               if (radeon_get_vblank_counter(rdev, i) != frame_count)
+                                       break;
+                               udelay(1);
+                       }
+               }
        }
  
-       WREG32(D1VGA_CONTROL, 0);
-       WREG32(D2VGA_CONTROL, 0);
-       if (rdev->num_crtc >= 4) {
-               WREG32(EVERGREEN_D3VGA_CONTROL, 0);
-               WREG32(EVERGREEN_D4VGA_CONTROL, 0);
-       }
-       if (rdev->num_crtc >= 6) {
-               WREG32(EVERGREEN_D5VGA_CONTROL, 0);
-               WREG32(EVERGREEN_D6VGA_CONTROL, 0);
+       radeon_mc_wait_for_idle(rdev);
+       blackout = RREG32(MC_SHARED_BLACKOUT_CNTL);
+       if ((blackout & BLACKOUT_MODE_MASK) != 1) {
+               /* Block CPU access */
+               WREG32(BIF_FB_EN, 0);
+               /* blackout the MC */
+               blackout &= ~BLACKOUT_MODE_MASK;
+               WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1);
        }
  }
  
  void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save)
  {
-       WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET,
-              upper_32_bits(rdev->mc.vram_start));
-       WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET,
-              upper_32_bits(rdev->mc.vram_start));
-       WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET,
-              (u32)rdev->mc.vram_start);
-       WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET,
-              (u32)rdev->mc.vram_start);
-       WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET,
-              upper_32_bits(rdev->mc.vram_start));
-       WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET,
-              upper_32_bits(rdev->mc.vram_start));
-       WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET,
-              (u32)rdev->mc.vram_start);
-       WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET,
-              (u32)rdev->mc.vram_start);
-       if (rdev->num_crtc >= 4) {
-               WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
-                      upper_32_bits(rdev->mc.vram_start));
-               WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
-                      upper_32_bits(rdev->mc.vram_start));
-               WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET,
-                      (u32)rdev->mc.vram_start);
-               WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET,
-                      (u32)rdev->mc.vram_start);
-               WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET,
-                      upper_32_bits(rdev->mc.vram_start));
-               WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET,
-                      upper_32_bits(rdev->mc.vram_start));
-               WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET,
-                      (u32)rdev->mc.vram_start);
-               WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET,
-                      (u32)rdev->mc.vram_start);
-       }
-       if (rdev->num_crtc >= 6) {
-               WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
-                      upper_32_bits(rdev->mc.vram_start));
-               WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
-                      upper_32_bits(rdev->mc.vram_start));
-               WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
-                      (u32)rdev->mc.vram_start);
-               WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
-                      (u32)rdev->mc.vram_start);
+       u32 tmp, frame_count;
+       int i, j;
  
-               WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
+       /* update crtc base addresses */
+       for (i = 0; i < rdev->num_crtc; i++) {
+               WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
                       upper_32_bits(rdev->mc.vram_start));
-               WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
+               WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
                       upper_32_bits(rdev->mc.vram_start));
-               WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
+               WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i],
                       (u32)rdev->mc.vram_start);
-               WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
+               WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i],
                       (u32)rdev->mc.vram_start);
        }
        WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start));
        WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start);
-       /* Unlock host access */
+       /* unblackout the MC */
+       tmp = RREG32(MC_SHARED_BLACKOUT_CNTL);
+       tmp &= ~BLACKOUT_MODE_MASK;
+       WREG32(MC_SHARED_BLACKOUT_CNTL, tmp);
+       /* allow CPU access */
+       WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
+       for (i = 0; i < rdev->num_crtc; i++) {
+               if (save->crtc_enabled) {
+                       if (ASIC_IS_DCE6(rdev)) {
+                               tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]);
+                               tmp |= EVERGREEN_CRTC_BLANK_DATA_EN;
+                               WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp);
+                       } else {
+                               tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
+                               tmp &= ~EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE;
+                               WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp);
+                       }
+                       /* wait for the next frame */
+                       frame_count = radeon_get_vblank_counter(rdev, i);
+                       for (j = 0; j < rdev->usec_timeout; j++) {
+                               if (radeon_get_vblank_counter(rdev, i) != frame_count)
+                                       break;
+                               udelay(1);
+                       }
+               }
+       }
+       /* Unlock vga access */
        WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);
        mdelay(1);
        WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
@@@ -1553,7 -1614,7 +1610,7 @@@ static int evergreen_cp_start(struct ra
        return 0;
  }
  
- int evergreen_cp_resume(struct radeon_device *rdev)
static int evergreen_cp_resume(struct radeon_device *rdev)
  {
        struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
        u32 tmp;
@@@ -2329,22 -2390,10 +2386,10 @@@ int evergreen_asic_reset(struct radeon_
  
  u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc)
  {
-       switch (crtc) {
-       case 0:
-               return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC0_REGISTER_OFFSET);
-       case 1:
-               return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC1_REGISTER_OFFSET);
-       case 2:
-               return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC2_REGISTER_OFFSET);
-       case 3:
-               return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC3_REGISTER_OFFSET);
-       case 4:
-               return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC4_REGISTER_OFFSET);
-       case 5:
-               return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC5_REGISTER_OFFSET);
-       default:
+       if (crtc >= rdev->num_crtc)
                return 0;
-       }
+       else
+               return RREG32(CRTC_STATUS_FRAME_COUNT + crtc_offsets[crtc]);
  }
  
  void evergreen_disable_interrupt_state(struct radeon_device *rdev)
@@@ -2537,10 -2586,6 +2582,6 @@@ int evergreen_irq_set(struct radeon_dev
                DRM_DEBUG("evergreen_irq_set: hdmi 5\n");
                afmt6 |= AFMT_AZ_FORMAT_WTRIG_MASK;
        }
-       if (rdev->irq.gui_idle) {
-               DRM_DEBUG("gui idle\n");
-               grbm_int_cntl |= GUI_IDLE_INT_ENABLE;
-       }
  
        if (rdev->family >= CHIP_CAYMAN) {
                cayman_cp_int_cntl_setup(rdev, 0, cp_int_cntl);
@@@ -2722,7 -2767,7 +2763,7 @@@ static void evergreen_irq_ack(struct ra
        }
  }
  
- void evergreen_irq_disable(struct radeon_device *rdev)
static void evergreen_irq_disable(struct radeon_device *rdev)
  {
        r600_disable_interrupts(rdev);
        /* Wait and acknowledge irq */
@@@ -3075,7 -3120,6 +3116,6 @@@ restart_ih
                        break;
                case 233: /* GUI IDLE */
                        DRM_DEBUG("IH: GUI idle\n");
-                       wake_up(&rdev->irq.idle_queue);
                        break;
                default:
                        DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@@ -25,7 -25,7 +25,7 @@@
   *          Alex Deucher
   *          Jerome Glisse
   */
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "radeon.h"
  #include "evergreend.h"
  #include "evergreen_reg_safe.h"
@@@ -846,6 -846,16 +846,16 @@@ static int evergreen_cs_track_validate_
                return -EINVAL;
        }
  
+       if (!mipmap) {
+               if (llevel) {
+                       dev_warn(p->dev, "%s:%i got NULL MIP_ADDRESS relocation\n",
+                                __func__, __LINE__);
+                       return -EINVAL;
+               } else {
+                       return 0; /* everything's ok */
+               }
+       }
        /* check mipmap size */
        for (i = 1; i <= llevel; i++) {
                unsigned w, h, d;
@@@ -995,7 -1005,7 +1005,7 @@@ static int evergreen_cs_track_check(str
   * Assume that chunk_ib_index is properly set. Will return -EINVAL
   * if packet is bigger than remaining ib size. or if packets is unknown.
   **/
- int evergreen_cs_packet_parse(struct radeon_cs_parser *p,
static int evergreen_cs_packet_parse(struct radeon_cs_parser *p,
                              struct radeon_cs_packet *pkt,
                              unsigned idx)
  {
@@@ -1081,6 -1091,27 +1091,27 @@@ static int evergreen_cs_packet_next_rel
  }
  
  /**
+  * evergreen_cs_packet_next_is_pkt3_nop() - test if the next packet is NOP
+  * @p:                structure holding the parser context.
+  *
+  * Check if the next packet is a relocation packet3.
+  **/
+ static bool evergreen_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p)
+ {
+       struct radeon_cs_packet p3reloc;
+       int r;
+       r = evergreen_cs_packet_parse(p, &p3reloc, p->idx);
+       if (r) {
+               return false;
+       }
+       if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) {
+               return false;
+       }
+       return true;
+ }
+ /**
   * evergreen_cs_packet_next_vline() - parse userspace VLINE packet
   * @parser:           parser structure holding parsing context.
   *
@@@ -2330,7 -2361,7 +2361,7 @@@ static int evergreen_packet3_check(stru
                for (i = 0; i < (pkt->count / 8); i++) {
                        struct radeon_bo *texture, *mipmap;
                        u32 toffset, moffset;
-                       u32 size, offset;
+                       u32 size, offset, mip_address, tex_dim;
  
                        switch (G__SQ_CONSTANT_TYPE(radeon_get_ib_value(p, idx+1+(i*8)+7))) {
                        case SQ_TEX_VTX_VALID_TEXTURE:
                                }
                                texture = reloc->robj;
                                toffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
                                /* tex mip base */
-                               r = evergreen_cs_packet_next_reloc(p, &reloc);
-                               if (r) {
-                                       DRM_ERROR("bad SET_RESOURCE (tex)\n");
-                                       return -EINVAL;
+                               tex_dim = ib[idx+1+(i*8)+0] & 0x7;
+                               mip_address = ib[idx+1+(i*8)+3];
+                               if ((tex_dim == SQ_TEX_DIM_2D_MSAA || tex_dim == SQ_TEX_DIM_2D_ARRAY_MSAA) &&
+                                   !mip_address &&
+                                   !evergreen_cs_packet_next_is_pkt3_nop(p)) {
+                                       /* MIP_ADDRESS should point to FMASK for an MSAA texture.
+                                        * It should be 0 if FMASK is disabled. */
+                                       moffset = 0;
+                                       mipmap = NULL;
+                               } else {
+                                       r = evergreen_cs_packet_next_reloc(p, &reloc);
+                                       if (r) {
+                                               DRM_ERROR("bad SET_RESOURCE (tex)\n");
+                                               return -EINVAL;
+                                       }
+                                       moffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+                                       mipmap = reloc->robj;
                                }
-                               moffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
-                               mipmap = reloc->robj;
                                r = evergreen_cs_track_validate_texture(p, texture, mipmap, idx+1+(i*8));
                                if (r)
                                        return r;
  #include <linux/platform_device.h>
  #include <linux/slab.h>
  #include <linux/module.h>
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "radeon.h"
  #include "radeon_asic.h"
 -#include "radeon_drm.h"
 +#include <drm/radeon_drm.h>
  #include "nid.h"
  #include "atom.h"
  #include "ni_reg.h"
@@@ -726,7 -726,7 +726,7 @@@ void cayman_pcie_gart_tlb_flush(struct 
        WREG32(VM_INVALIDATE_REQUEST, 1);
  }
  
- int cayman_pcie_gart_enable(struct radeon_device *rdev)
static int cayman_pcie_gart_enable(struct radeon_device *rdev)
  {
        int i, r;
  
               (u32)(rdev->dummy_page.addr >> 12));
        WREG32(VM_CONTEXT1_CNTL2, 0);
        WREG32(VM_CONTEXT1_CNTL, 0);
-       WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) |
+       WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) |
                                RANGE_PROTECTION_FAULT_ENABLE_DEFAULT);
  
        cayman_pcie_gart_tlb_flush(rdev);
        return 0;
  }
  
- void cayman_pcie_gart_disable(struct radeon_device *rdev)
static void cayman_pcie_gart_disable(struct radeon_device *rdev)
  {
        /* Disable all tables */
        WREG32(VM_CONTEXT0_CNTL, 0);
        radeon_gart_table_vram_unpin(rdev);
  }
  
- void cayman_pcie_gart_fini(struct radeon_device *rdev)
static void cayman_pcie_gart_fini(struct radeon_device *rdev)
  {
        cayman_pcie_gart_disable(rdev);
        radeon_gart_table_vram_free(rdev);
@@@ -879,12 -879,13 +879,13 @@@ void cayman_ring_ib_execute(struct rade
  #endif
                          (ib->gpu_addr & 0xFFFFFFFC));
        radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFF);
-       radeon_ring_write(ring, ib->length_dw | (ib->vm_id << 24));
+       radeon_ring_write(ring, ib->length_dw | 
+                         (ib->vm ? (ib->vm->id << 24) : 0));
  
        /* flush read cache over gart for this vmid */
        radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
        radeon_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START) >> 2);
-       radeon_ring_write(ring, ib->vm_id);
+       radeon_ring_write(ring, ib->vm ? ib->vm->id : 0);
        radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
        radeon_ring_write(ring, PACKET3_TC_ACTION_ENA | PACKET3_SH_ACTION_ENA);
        radeon_ring_write(ring, 0xFFFFFFFF);
@@@ -1004,7 -1005,7 +1005,7 @@@ static void cayman_cp_fini(struct radeo
        radeon_scratch_free(rdev, ring->rptr_save_reg);
  }
  
- int cayman_cp_resume(struct radeon_device *rdev)
static int cayman_cp_resume(struct radeon_device *rdev)
  {
        static const int ridx[] = {
                RADEON_RING_TYPE_GFX_INDEX,
@@@ -1496,53 -1497,16 +1497,16 @@@ void cayman_vm_fini(struct radeon_devic
  {
  }
  
- int cayman_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id)
- {
-       WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (id << 2), 0);
-       WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (id << 2), vm->last_pfn);
-       WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (id << 2), vm->pt_gpu_addr >> 12);
-       /* flush hdp cache */
-       WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
-       /* bits 0-7 are the VM contexts0-7 */
-       WREG32(VM_INVALIDATE_REQUEST, 1 << id);
-       return 0;
- }
- void cayman_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm)
- {
-       WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (vm->id << 2), 0);
-       WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (vm->id << 2), 0);
-       WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2), 0);
-       /* flush hdp cache */
-       WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
-       /* bits 0-7 are the VM contexts0-7 */
-       WREG32(VM_INVALIDATE_REQUEST, 1 << vm->id);
- }
- void cayman_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm)
- {
-       if (vm->id == -1)
-               return;
-       /* flush hdp cache */
-       WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
-       /* bits 0-7 are the VM contexts0-7 */
-       WREG32(VM_INVALIDATE_REQUEST, 1 << vm->id);
- }
- #define R600_PTE_VALID     (1 << 0)
+ #define R600_ENTRY_VALID   (1 << 0)
  #define R600_PTE_SYSTEM    (1 << 1)
  #define R600_PTE_SNOOPED   (1 << 2)
  #define R600_PTE_READABLE  (1 << 5)
  #define R600_PTE_WRITEABLE (1 << 6)
  
- uint32_t cayman_vm_page_flags(struct radeon_device *rdev,
-                             struct radeon_vm *vm,
-                             uint32_t flags)
+ uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags)
  {
        uint32_t r600_flags = 0;
-       r600_flags |= (flags & RADEON_VM_PAGE_VALID) ? R600_PTE_VALID : 0;
+       r600_flags |= (flags & RADEON_VM_PAGE_VALID) ? R600_ENTRY_VALID : 0;
        r600_flags |= (flags & RADEON_VM_PAGE_READABLE) ? R600_PTE_READABLE : 0;
        r600_flags |= (flags & RADEON_VM_PAGE_WRITEABLE) ? R600_PTE_WRITEABLE : 0;
        if (flags & RADEON_VM_PAGE_SYSTEM) {
        return r600_flags;
  }
  
- void cayman_vm_set_page(struct radeon_device *rdev, struct radeon_vm *vm,
-                       unsigned pfn, uint64_t addr, uint32_t flags)
+ /**
+  * cayman_vm_set_page - update the page tables using the CP
+  *
+  * @rdev: radeon_device pointer
+  * @pe: addr of the page entry
+  * @addr: dst addr to write into pe
+  * @count: number of page entries to update
+  * @incr: increase next addr by incr bytes
+  * @flags: access flags
+  *
+  * Update the page tables using the CP (cayman-si).
+  */
+ void cayman_vm_set_page(struct radeon_device *rdev, uint64_t pe,
+                       uint64_t addr, unsigned count,
+                       uint32_t incr, uint32_t flags)
+ {
+       struct radeon_ring *ring = &rdev->ring[rdev->asic->vm.pt_ring_index];
+       uint32_t r600_flags = cayman_vm_page_flags(rdev, flags);
+       int i;
+       radeon_ring_write(ring, PACKET3(PACKET3_ME_WRITE, 1 + count * 2));
+       radeon_ring_write(ring, pe);
+       radeon_ring_write(ring, upper_32_bits(pe) & 0xff);
+       for (i = 0; i < count; ++i) {
+               uint64_t value = 0;
+               if (flags & RADEON_VM_PAGE_SYSTEM) {
+                       value = radeon_vm_map_gart(rdev, addr);
+                       value &= 0xFFFFFFFFFFFFF000ULL;
+                       addr += incr;
+               } else if (flags & RADEON_VM_PAGE_VALID) {
+                       value = addr;
+                       addr += incr;
+               }
+               value |= r600_flags;
+               radeon_ring_write(ring, value);
+               radeon_ring_write(ring, upper_32_bits(value));
+       }
+ }
+ /**
+  * cayman_vm_flush - vm flush using the CP
+  *
+  * @rdev: radeon_device pointer
+  *
+  * Update the page table base and flush the VM TLB
+  * using the CP (cayman-si).
+  */
+ void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
  {
-       void __iomem *ptr = (void *)vm->pt;
+       struct radeon_ring *ring = &rdev->ring[ridx];
+       if (vm == NULL)
+               return;
+       radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (vm->id << 2), 0));
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (vm->id << 2), 0));
+       radeon_ring_write(ring, vm->last_pfn);
  
-       addr = addr & 0xFFFFFFFFFFFFF000ULL;
-       addr |= flags;
-       writeq(addr, ptr + (pfn * 8));
+       radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2), 0));
+       radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
+       /* flush hdp cache */
+       radeon_ring_write(ring, PACKET0(HDP_MEM_COHERENCY_FLUSH_CNTL, 0));
+       radeon_ring_write(ring, 0x1);
+       /* bits 0-7 are the VM contexts0-7 */
+       radeon_ring_write(ring, PACKET0(VM_INVALIDATE_REQUEST, 0));
+       radeon_ring_write(ring, 1 << vm->id);
  }
@@@ -27,8 -27,9 +27,8 @@@
   */
  #include <linux/seq_file.h>
  #include <linux/slab.h>
 -#include "drmP.h"
 -#include "drm.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon_reg.h"
  #include "radeon.h"
  #include "radeon_asic.h"
@@@ -79,10 -80,12 +79,12 @@@ MODULE_FIRMWARE(FIRMWARE_R520)
   */
  void r100_wait_for_vblank(struct radeon_device *rdev, int crtc)
  {
-       struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
        int i;
  
-       if (radeon_crtc->crtc_id == 0) {
+       if (crtc >= rdev->num_crtc)
+               return;
+       if (crtc == 0) {
                if (RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN) {
                        for (i = 0; i < rdev->usec_timeout; i++) {
                                if (!(RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR))
@@@ -697,9 -700,6 +699,6 @@@ int r100_irq_set(struct radeon_device *
        if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
                tmp |= RADEON_SW_INT_ENABLE;
        }
-       if (rdev->irq.gui_idle) {
-               tmp |= RADEON_GUI_IDLE_MASK;
-       }
        if (rdev->irq.crtc_vblank_int[0] ||
            atomic_read(&rdev->irq.pflip[0])) {
                tmp |= RADEON_CRTC_VBLANK_MASK;
@@@ -736,12 -736,6 +735,6 @@@ static uint32_t r100_irq_ack(struct rad
                RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT |
                RADEON_FP_DETECT_STAT | RADEON_FP2_DETECT_STAT;
  
-       /* the interrupt works, but the status bit is permanently asserted */
-       if (rdev->irq.gui_idle && radeon_gui_idle(rdev)) {
-               if (!rdev->irq.gui_idle_acked)
-                       irq_mask |= RADEON_GUI_IDLE_STAT;
-       }
        if (irqs) {
                WREG32(RADEON_GEN_INT_STATUS, irqs);
        }
@@@ -753,9 -747,6 +746,6 @@@ int r100_irq_process(struct radeon_devi
        uint32_t status, msi_rearm;
        bool queue_hotplug = false;
  
-       /* reset gui idle ack.  the status bit is broken */
-       rdev->irq.gui_idle_acked = false;
        status = r100_irq_ack(rdev);
        if (!status) {
                return IRQ_NONE;
                if (status & RADEON_SW_INT_TEST) {
                        radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
                }
-               /* gui idle interrupt */
-               if (status & RADEON_GUI_IDLE_STAT) {
-                       rdev->irq.gui_idle_acked = true;
-                       wake_up(&rdev->irq.idle_queue);
-               }
                /* Vertical blank interrupts */
                if (status & RADEON_CRTC_VBLANK_STAT) {
                        if (rdev->irq.crtc_vblank_int[0]) {
                }
                status = r100_irq_ack(rdev);
        }
-       /* reset gui idle ack.  the status bit is broken */
-       rdev->irq.gui_idle_acked = false;
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
        if (rdev->msi_enabled) {
@@@ -2529,7 -2513,7 +2512,7 @@@ void r100_cs_track_clear(struct radeon_
  /*
   * Global GPU functions
   */
- void r100_errata(struct radeon_device *rdev)
static void r100_errata(struct radeon_device *rdev)
  {
        rdev->pll_errata = 0;
  
        }
  }
  
- /* Wait for vertical sync on primary CRTC */
- void r100_gpu_wait_for_vsync(struct radeon_device *rdev)
- {
-       uint32_t crtc_gen_cntl, tmp;
-       int i;
-       crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL);
-       if ((crtc_gen_cntl & RADEON_CRTC_DISP_REQ_EN_B) ||
-           !(crtc_gen_cntl & RADEON_CRTC_EN)) {
-               return;
-       }
-       /* Clear the CRTC_VBLANK_SAVE bit */
-       WREG32(RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE_CLEAR);
-       for (i = 0; i < rdev->usec_timeout; i++) {
-               tmp = RREG32(RADEON_CRTC_STATUS);
-               if (tmp & RADEON_CRTC_VBLANK_SAVE) {
-                       return;
-               }
-               DRM_UDELAY(1);
-       }
- }
- /* Wait for vertical sync on secondary CRTC */
- void r100_gpu_wait_for_vsync2(struct radeon_device *rdev)
- {
-       uint32_t crtc2_gen_cntl, tmp;
-       int i;
-       crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
-       if ((crtc2_gen_cntl & RADEON_CRTC2_DISP_REQ_EN_B) ||
-           !(crtc2_gen_cntl & RADEON_CRTC2_EN))
-               return;
-       /* Clear the CRTC_VBLANK_SAVE bit */
-       WREG32(RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE_CLEAR);
-       for (i = 0; i < rdev->usec_timeout; i++) {
-               tmp = RREG32(RADEON_CRTC2_STATUS);
-               if (tmp & RADEON_CRTC2_VBLANK_SAVE) {
-                       return;
-               }
-               DRM_UDELAY(1);
-       }
- }
- int r100_rbbm_fifo_wait_for_entry(struct radeon_device *rdev, unsigned n)
+ static int r100_rbbm_fifo_wait_for_entry(struct radeon_device *rdev, unsigned n)
  {
        unsigned i;
        uint32_t tmp;
@@@ -2949,7 -2889,7 +2888,7 @@@ void r100_vga_set_state(struct radeon_d
        WREG32(RADEON_CONFIG_CNTL, temp);
  }
  
- void r100_mc_init(struct radeon_device *rdev)
static void r100_mc_init(struct radeon_device *rdev)
  {
        u64 base;
  
@@@ -3021,7 -2961,7 +2960,7 @@@ void r100_pll_wreg(struct radeon_devic
        r100_pll_errata_after_data(rdev);
  }
  
- void r100_set_safe_registers(struct radeon_device *rdev)
static void r100_set_safe_registers(struct radeon_device *rdev)
  {
        if (ASIC_IS_RN50(rdev)) {
                rdev->config.r100.reg_safe_bm = rn50_reg_safe_bm;
@@@ -3816,9 -3756,10 +3755,10 @@@ int r100_ib_test(struct radeon_device *
                return r;
        }
        WREG32(scratch, 0xCAFEDEAD);
-       r = radeon_ib_get(rdev, RADEON_RING_TYPE_GFX_INDEX, &ib, 256);
+       r = radeon_ib_get(rdev, RADEON_RING_TYPE_GFX_INDEX, &ib, NULL, 256);
        if (r) {
-               return r;
+               DRM_ERROR("radeon: failed to get ib (%d).\n", r);
+               goto free_scratch;
        }
        ib.ptr[0] = PACKET0(scratch, 0);
        ib.ptr[1] = 0xDEADBEEF;
        ib.length_dw = 8;
        r = radeon_ib_schedule(rdev, &ib, NULL);
        if (r) {
-               radeon_scratch_free(rdev, scratch);
-               radeon_ib_free(rdev, &ib);
-               return r;
+               DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
+               goto free_ib;
        }
        r = radeon_fence_wait(ib.fence, false);
        if (r) {
-               return r;
+               DRM_ERROR("radeon: fence wait failed (%d).\n", r);
+               goto free_ib;
        }
        for (i = 0; i < rdev->usec_timeout; i++) {
                tmp = RREG32(scratch);
                          scratch, tmp);
                r = -EINVAL;
        }
-       radeon_scratch_free(rdev, scratch);
+ free_ib:
        radeon_ib_free(rdev, &ib);
+ free_scratch:
+       radeon_scratch_free(rdev, scratch);
        return r;
  }
  
@@@ -3963,7 -3906,7 +3905,7 @@@ static void r100_mc_program(struct rade
        r100_mc_resume(rdev, &save);
  }
  
- void r100_clock_startup(struct radeon_device *rdev)
static void r100_clock_startup(struct radeon_device *rdev)
  {
        u32 tmp;
  
@@@ -33,7 -33,7 +33,7 @@@
  #include "radeon_reg.h"
  #include "radeon.h"
  #include "radeon_asic.h"
 -#include "radeon_drm.h"
 +#include <drm/radeon_drm.h>
  #include "r100_track.h"
  #include "r300d.h"
  #include "rv350d.h"
@@@ -296,7 -296,7 +296,7 @@@ void r300_ring_start(struct radeon_devi
        radeon_ring_unlock_commit(rdev, ring);
  }
  
- void r300_errata(struct radeon_device *rdev)
static void r300_errata(struct radeon_device *rdev)
  {
        rdev->pll_errata = 0;
  
@@@ -322,7 -322,7 +322,7 @@@ int r300_mc_wait_for_idle(struct radeon
        return -1;
  }
  
- void r300_gpu_init(struct radeon_device *rdev)
static void r300_gpu_init(struct radeon_device *rdev)
  {
        uint32_t gb_tile_config, tmp;
  
@@@ -25,7 -25,7 +25,7 @@@
   *          Alex Deucher
   *          Jerome Glisse
   */
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "radeon.h"
  #include "radeon_asic.h"
  #include "atom.h"
@@@ -119,7 -119,7 +119,7 @@@ static void r520_vram_get_type(struct r
                rdev->mc.vram_width *= 2;
  }
  
- void r520_mc_init(struct radeon_device *rdev)
static void r520_mc_init(struct radeon_device *rdev)
  {
  
        r520_vram_get_type(rdev);
        radeon_update_bandwidth_info(rdev);
  }
  
- void r520_mc_program(struct radeon_device *rdev)
static void r520_mc_program(struct radeon_device *rdev)
  {
        struct rv515_mc_save save;
  
@@@ -30,8 -30,8 +30,8 @@@
  #include <linux/firmware.h>
  #include <linux/platform_device.h>
  #include <linux/module.h>
 -#include "drmP.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  #include "radeon_asic.h"
  #include "radeon_mode.h"
@@@ -98,7 -98,7 +98,7 @@@ int r600_debugfs_mc_info_init(struct ra
  
  /* r600,rv610,rv630,rv620,rv635,rv670 */
  int r600_mc_wait_for_idle(struct radeon_device *rdev);
- void r600_gpu_init(struct radeon_device *rdev);
static void r600_gpu_init(struct radeon_device *rdev);
  void r600_fini(struct radeon_device *rdev);
  void r600_irq_disable(struct radeon_device *rdev);
  static void r600_pcie_gen2_enable(struct radeon_device *rdev);
@@@ -881,7 -881,7 +881,7 @@@ int r600_pcie_gart_init(struct radeon_d
        return radeon_gart_table_vram_alloc(rdev);
  }
  
- int r600_pcie_gart_enable(struct radeon_device *rdev)
static int r600_pcie_gart_enable(struct radeon_device *rdev)
  {
        u32 tmp;
        int r, i;
        return 0;
  }
  
- void r600_pcie_gart_disable(struct radeon_device *rdev)
static void r600_pcie_gart_disable(struct radeon_device *rdev)
  {
        u32 tmp;
        int i;
        radeon_gart_table_vram_unpin(rdev);
  }
  
- void r600_pcie_gart_fini(struct radeon_device *rdev)
static void r600_pcie_gart_fini(struct radeon_device *rdev)
  {
        radeon_gart_fini(rdev);
        r600_pcie_gart_disable(rdev);
        radeon_gart_table_vram_free(rdev);
  }
  
- void r600_agp_enable(struct radeon_device *rdev)
static void r600_agp_enable(struct radeon_device *rdev)
  {
        u32 tmp;
        int i;
@@@ -1158,7 -1158,7 +1158,7 @@@ static void r600_vram_gtt_location(stru
        }
  }
  
- int r600_mc_init(struct radeon_device *rdev)
static int r600_mc_init(struct radeon_device *rdev)
  {
        u32 tmp;
        int chansize, numchan;
@@@ -1258,7 -1258,7 +1258,7 @@@ void r600_vram_scratch_fini(struct rade
   * reset, it's up to the caller to determine if the GPU needs one. We
   * might add an helper function to check that.
   */
- int r600_gpu_soft_reset(struct radeon_device *rdev)
static int r600_gpu_soft_reset(struct radeon_device *rdev)
  {
        struct rv515_mc_save save;
        u32 grbm_busy_mask = S_008010_VC_BUSY(1) | S_008010_VGT_BUSY_NO_DMA(1) |
@@@ -1433,7 -1433,7 +1433,7 @@@ int r600_count_pipe_bits(uint32_t val
        return ret;
  }
  
- void r600_gpu_init(struct radeon_device *rdev)
static void r600_gpu_init(struct radeon_device *rdev)
  {
        u32 tiling_config;
        u32 ramcfg;
@@@ -2347,7 -2347,7 +2347,7 @@@ void r600_clear_surface_reg(struct rade
        /* FIXME: implement */
  }
  
- int r600_startup(struct radeon_device *rdev)
static int r600_startup(struct radeon_device *rdev)
  {
        struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
        int r;
@@@ -2635,10 -2635,10 +2635,10 @@@ int r600_ib_test(struct radeon_device *
                return r;
        }
        WREG32(scratch, 0xCAFEDEAD);
-       r = radeon_ib_get(rdev, ring->idx, &ib, 256);
+       r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256);
        if (r) {
                DRM_ERROR("radeon: failed to get ib (%d).\n", r);
-               return r;
+               goto free_scratch;
        }
        ib.ptr[0] = PACKET3(PACKET3_SET_CONFIG_REG, 1);
        ib.ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
        ib.length_dw = 3;
        r = radeon_ib_schedule(rdev, &ib, NULL);
        if (r) {
-               radeon_scratch_free(rdev, scratch);
-               radeon_ib_free(rdev, &ib);
                DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
-               return r;
+               goto free_ib;
        }
        r = radeon_fence_wait(ib.fence, false);
        if (r) {
                DRM_ERROR("radeon: fence wait failed (%d).\n", r);
-               return r;
+               goto free_ib;
        }
        for (i = 0; i < rdev->usec_timeout; i++) {
                tmp = RREG32(scratch);
                          scratch, tmp);
                r = -EINVAL;
        }
-       radeon_scratch_free(rdev, scratch);
+ free_ib:
        radeon_ib_free(rdev, &ib);
+ free_scratch:
+       radeon_scratch_free(rdev, scratch);
        return r;
  }
  
@@@ -3088,10 -3088,6 +3088,6 @@@ int r600_irq_set(struct radeon_device *
                DRM_DEBUG("r600_irq_set: hdmi 0\n");
                hdmi1 |= HDMI0_AZ_FORMAT_WTRIG_MASK;
        }
-       if (rdev->irq.gui_idle) {
-               DRM_DEBUG("gui idle\n");
-               grbm_int_cntl |= GUI_IDLE_INT_ENABLE;
-       }
  
        WREG32(CP_INT_CNTL, cp_int_cntl);
        WREG32(DxMODE_INT_MASK, mode_int);
@@@ -3475,7 -3471,6 +3471,6 @@@ restart_ih
                        break;
                case 233: /* GUI IDLE */
                        DRM_DEBUG("IH: GUI idle\n");
-                       wake_up(&rdev->irq.idle_queue);
                        break;
                default:
                        DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@@ -23,8 -23,9 +23,8 @@@
   * Authors:
   *     Alex Deucher <alexander.deucher@amd.com>
   */
 -#include "drmP.h"
 -#include "drm.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon_drv.h"
  
  #include "r600_blit_shaders.h"
@@@ -488,31 -489,36 +488,36 @@@ set_default_state(drm_radeon_private_t 
        ADVANCE_RING();
  }
  
- static uint32_t i2f(uint32_t input)
+ /* 23 bits of float fractional data */
+ #define I2F_FRAC_BITS  23
+ #define I2F_MASK ((1 << I2F_FRAC_BITS) - 1)
+ /*
+  * Converts unsigned integer into 32-bit IEEE floating point representation.
+  * Will be exact from 0 to 2^24.  Above that, we round towards zero
+  * as the fractional bits will not fit in a float.  (It would be better to
+  * round towards even as the fpu does, but that is slower.)
+  */
+ __pure uint32_t int2float(uint32_t x)
  {
-       u32 result, i, exponent, fraction;
-       if ((input & 0x3fff) == 0)
-               result = 0; /* 0 is a special case */
-       else {
-               exponent = 140; /* exponent biased by 127; */
-               fraction = (input & 0x3fff) << 10; /* cheat and only
-                                                     handle numbers below 2^^15 */
-               for (i = 0; i < 14; i++) {
-                       if (fraction & 0x800000)
-                               break;
-                       else {
-                               fraction = fraction << 1; /* keep
-                                                            shifting left until top bit = 1 */
-                               exponent = exponent - 1;
-                       }
-               }
-               result = exponent << 23 | (fraction & 0x7fffff); /* mask
-                                                                   off top bit; assumed 1 */
-       }
-       return result;
- }
+       uint32_t msb, exponent, fraction;
+       /* Zero is special */
+       if (!x) return 0;
+       /* Get location of the most significant bit */
+       msb = __fls(x);
  
+       /*
+        * Use a rotate instead of a shift because that works both leftwards
+        * and rightwards due to the mod(32) behaviour.  This means we don't
+        * need to check to see if we are above 2^24 or not.
+        */
+       fraction = ror32(x, (msb - I2F_FRAC_BITS) & 0x1f) & I2F_MASK;
+       exponent = (127 + msb) << I2F_FRAC_BITS;
+       return fraction + exponent;
+ }
  
  static int r600_nomm_get_vb(struct drm_device *dev)
  {
@@@ -631,20 -637,20 +636,20 @@@ r600_blit_copy(struct drm_device *dev
                                vb = r600_nomm_get_vb_ptr(dev);
                        }
  
-                       vb[0] = i2f(dst_x);
+                       vb[0] = int2float(dst_x);
                        vb[1] = 0;
-                       vb[2] = i2f(src_x);
+                       vb[2] = int2float(src_x);
                        vb[3] = 0;
  
-                       vb[4] = i2f(dst_x);
-                       vb[5] = i2f(h);
-                       vb[6] = i2f(src_x);
-                       vb[7] = i2f(h);
+                       vb[4] = int2float(dst_x);
+                       vb[5] = int2float(h);
+                       vb[6] = int2float(src_x);
+                       vb[7] = int2float(h);
  
-                       vb[8] = i2f(dst_x + cur_size);
-                       vb[9] = i2f(h);
-                       vb[10] = i2f(src_x + cur_size);
-                       vb[11] = i2f(h);
+                       vb[8] = int2float(dst_x + cur_size);
+                       vb[9] = int2float(h);
+                       vb[10] = int2float(src_x + cur_size);
+                       vb[11] = int2float(h);
  
                        /* src */
                        set_tex_resource(dev_priv, FMT_8,
                                vb = r600_nomm_get_vb_ptr(dev);
                        }
  
-                       vb[0] = i2f(dst_x / 4);
+                       vb[0] = int2float(dst_x / 4);
                        vb[1] = 0;
-                       vb[2] = i2f(src_x / 4);
+                       vb[2] = int2float(src_x / 4);
                        vb[3] = 0;
  
-                       vb[4] = i2f(dst_x / 4);
-                       vb[5] = i2f(h);
-                       vb[6] = i2f(src_x / 4);
-                       vb[7] = i2f(h);
+                       vb[4] = int2float(dst_x / 4);
+                       vb[5] = int2float(h);
+                       vb[6] = int2float(src_x / 4);
+                       vb[7] = int2float(h);
  
-                       vb[8] = i2f((dst_x + cur_size) / 4);
-                       vb[9] = i2f(h);
-                       vb[10] = i2f((src_x + cur_size) / 4);
-                       vb[11] = i2f(h);
+                       vb[8] = int2float((dst_x + cur_size) / 4);
+                       vb[9] = int2float(h);
+                       vb[10] = int2float((src_x + cur_size) / 4);
+                       vb[11] = int2float(h);
  
                        /* src */
                        set_tex_resource(dev_priv, FMT_8_8_8_8,
@@@ -803,20 -809,20 +808,20 @@@ r600_blit_swap(struct drm_device *dev
        dx2 = dx + w;
        dy2 = dy + h;
  
-       vb[0] = i2f(dx);
-       vb[1] = i2f(dy);
-       vb[2] = i2f(sx);
-       vb[3] = i2f(sy);
+       vb[0] = int2float(dx);
+       vb[1] = int2float(dy);
+       vb[2] = int2float(sx);
+       vb[3] = int2float(sy);
  
-       vb[4] = i2f(dx);
-       vb[5] = i2f(dy2);
-       vb[6] = i2f(sx);
-       vb[7] = i2f(sy2);
+       vb[4] = int2float(dx);
+       vb[5] = int2float(dy2);
+       vb[6] = int2float(sx);
+       vb[7] = int2float(sy2);
  
-       vb[8] = i2f(dx2);
-       vb[9] = i2f(dy2);
-       vb[10] = i2f(sx2);
-       vb[11] = i2f(sy2);
+       vb[8] = int2float(dx2);
+       vb[9] = int2float(dy2);
+       vb[10] = int2float(sx2);
+       vb[11] = int2float(sy2);
  
        switch(cpp) {
        case 4:
@@@ -23,8 -23,9 +23,8 @@@
   *
   */
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  
  #include "r600d.h"
@@@ -454,46 -455,6 +454,6 @@@ set_default_state(struct radeon_device 
        radeon_ring_write(ring, sq_stack_resource_mgmt_2);
  }
  
- #define I2F_MAX_BITS 15
- #define I2F_MAX_INPUT  ((1 << I2F_MAX_BITS) - 1)
- #define I2F_SHIFT (24 - I2F_MAX_BITS)
- /*
-  * Converts unsigned integer into 32-bit IEEE floating point representation.
-  * Conversion is not universal and only works for the range from 0
-  * to 2^I2F_MAX_BITS-1. Currently we only use it with inputs between
-  * 0 and 16384 (inclusive), so I2F_MAX_BITS=15 is enough. If necessary,
-  * I2F_MAX_BITS can be increased, but that will add to the loop iterations
-  * and slow us down. Conversion is done by shifting the input and counting
-  * down until the first 1 reaches bit position 23. The resulting counter
-  * and the shifted input are, respectively, the exponent and the fraction.
-  * The sign is always zero.
-  */
- static uint32_t i2f(uint32_t input)
- {
-       u32 result, i, exponent, fraction;
-       WARN_ON_ONCE(input > I2F_MAX_INPUT);
-       if ((input & I2F_MAX_INPUT) == 0)
-               result = 0;
-       else {
-               exponent = 126 + I2F_MAX_BITS;
-               fraction = (input & I2F_MAX_INPUT) << I2F_SHIFT;
-               for (i = 0; i < I2F_MAX_BITS; i++) {
-                       if (fraction & 0x800000)
-                               break;
-                       else {
-                               fraction = fraction << 1;
-                               exponent = exponent - 1;
-                       }
-               }
-               result = exponent << 23 | (fraction & 0x7fffff);
-       }
-       return result;
- }
  int r600_blit_init(struct radeon_device *rdev)
  {
        u32 obj_size;
@@@ -765,14 -726,14 +725,14 @@@ void r600_kms_blit_copy(struct radeon_d
                vb_cpu_addr[3] = 0;
  
                vb_cpu_addr[4] = 0;
-               vb_cpu_addr[5] = i2f(h);
+               vb_cpu_addr[5] = int2float(h);
                vb_cpu_addr[6] = 0;
-               vb_cpu_addr[7] = i2f(h);
+               vb_cpu_addr[7] = int2float(h);
  
-               vb_cpu_addr[8] = i2f(w);
-               vb_cpu_addr[9] = i2f(h);
-               vb_cpu_addr[10] = i2f(w);
-               vb_cpu_addr[11] = i2f(h);
+               vb_cpu_addr[8] = int2float(w);
+               vb_cpu_addr[9] = int2float(h);
+               vb_cpu_addr[10] = int2float(w);
+               vb_cpu_addr[11] = int2float(h);
  
                rdev->r600_blit.primitives.set_tex_resource(rdev, FMT_8_8_8_8,
                                                            w, h, w, src_gpu_addr, size_in_bytes);
@@@ -26,7 -26,7 +26,7 @@@
   *          Jerome Glisse
   */
  #include <linux/kernel.h>
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "radeon.h"
  #include "r600d.h"
  #include "r600_reg_safe.h"
@@@ -847,7 -847,7 +847,7 @@@ static int r600_cs_track_check(struct r
   * Assume that chunk_ib_index is properly set. Will return -EINVAL
   * if packet is bigger than remaining ib size. or if packets is unknown.
   **/
- int r600_cs_packet_parse(struct radeon_cs_parser *p,
static int r600_cs_packet_parse(struct radeon_cs_parser *p,
                        struct radeon_cs_packet *pkt,
                        unsigned idx)
  {
@@@ -2180,7 -2180,8 +2180,8 @@@ static int r600_packet3_check(struct ra
                }
                break;
        case PACKET3_STRMOUT_BASE_UPDATE:
-               if (p->family < CHIP_RV770) {
+               /* RS780 and RS880 also need this */
+               if (p->family < CHIP_RS780) {
                        DRM_ERROR("STRMOUT_BASE_UPDATE only supported on 7xx\n");
                        return -EINVAL;
                }
@@@ -23,8 -23,8 +23,8 @@@
   *
   * Authors: Christian König
   */
 -#include "drmP.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  #include "radeon_asic.h"
  #include "r600d.h"
@@@ -53,7 -53,7 +53,7 @@@ enum r600_hdmi_iec_status_bits 
        AUDIO_STATUS_LEVEL        = 0x80
  };
  
- struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = {
+ static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = {
      /*             32kHz        44.1kHz       48kHz    */
      /* Clock      N     CTS      N     CTS      N     CTS */
      {  25174,  4576,  28125,  7007,  31250,  6864,  28125 }, /*  25,20/1.001 MHz */
+ /*
+  * Copyright 2012 Advanced Micro Devices, Inc.
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+  * copy of this software and associated documentation files (the "Software"),
+  * to deal in the Software without restriction, including without limitation
+  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+  * and/or sell copies of the Software, and to permit persons to whom the
+  * Software is furnished to do so, subject to the following conditions:
+  *
+  * The above copyright notice and this permission notice shall be included in
+  * all copies or substantial portions of the Software.
+  *
+  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  * OTHER DEALINGS IN THE SOFTWARE.
+  *
+  */
  #include <linux/pci.h>
  #include <linux/acpi.h>
  #include <linux/slab.h>
+ #include <linux/power_supply.h>
  #include <acpi/acpi_drivers.h>
  #include <acpi/acpi_bus.h>
+ #include <acpi/video.h>
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_sarea.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
  #include "radeon.h"
+ #include "radeon_acpi.h"
+ #include "atom.h"
  
  #include <linux/vga_switcheroo.h>
  
+ #define ACPI_AC_CLASS           "ac_adapter"
+ extern void radeon_pm_acpi_event_handler(struct radeon_device *rdev);
+ struct atif_verify_interface {
+       u16 size;               /* structure size in bytes (includes size field) */
+       u16 version;            /* version */
+       u32 notification_mask;  /* supported notifications mask */
+       u32 function_bits;      /* supported functions bit vector */
+ } __packed;
+ struct atif_system_params {
+       u16 size;               /* structure size in bytes (includes size field) */
+       u32 valid_mask;         /* valid flags mask */
+       u32 flags;              /* flags */
+       u8 command_code;        /* notify command code */
+ } __packed;
+ struct atif_sbios_requests {
+       u16 size;               /* structure size in bytes (includes size field) */
+       u32 pending;            /* pending sbios requests */
+       u8 panel_exp_mode;      /* panel expansion mode */
+       u8 thermal_gfx;         /* thermal state: target gfx controller */
+       u8 thermal_state;       /* thermal state: state id (0: exit state, non-0: state) */
+       u8 forced_power_gfx;    /* forced power state: target gfx controller */
+       u8 forced_power_state;  /* forced power state: state id */
+       u8 system_power_src;    /* system power source */
+       u8 backlight_level;     /* panel backlight level (0-255) */
+ } __packed;
+ #define ATIF_NOTIFY_MASK      0x3
+ #define ATIF_NOTIFY_NONE      0
+ #define ATIF_NOTIFY_81                1
+ #define ATIF_NOTIFY_N         2
+ struct atcs_verify_interface {
+       u16 size;               /* structure size in bytes (includes size field) */
+       u16 version;            /* version */
+       u32 function_bits;      /* supported functions bit vector */
+ } __packed;
  /* Call the ATIF method
+  */
+ /**
+  * radeon_atif_call - call an ATIF method
   *
-  * Note: currently we discard the output
+  * @handle: acpi handle
+  * @function: the ATIF function to execute
+  * @params: ATIF function params
+  *
+  * Executes the requested ATIF function (all asics).
+  * Returns a pointer to the acpi output buffer.
   */
- static int radeon_atif_call(acpi_handle handle)
+ static union acpi_object *radeon_atif_call(acpi_handle handle, int function,
+               struct acpi_buffer *params)
  {
        acpi_status status;
        union acpi_object atif_arg_elements[2];
        struct acpi_object_list atif_arg;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
  
        atif_arg.count = 2;
        atif_arg.pointer = &atif_arg_elements[0];
  
        atif_arg_elements[0].type = ACPI_TYPE_INTEGER;
-       atif_arg_elements[0].integer.value = 0;
-       atif_arg_elements[1].type = ACPI_TYPE_INTEGER;
-       atif_arg_elements[1].integer.value = 0;
+       atif_arg_elements[0].integer.value = function;
+       if (params) {
+               atif_arg_elements[1].type = ACPI_TYPE_BUFFER;
+               atif_arg_elements[1].buffer.length = params->length;
+               atif_arg_elements[1].buffer.pointer = params->pointer;
+       } else {
+               /* We need a second fake parameter */
+               atif_arg_elements[1].type = ACPI_TYPE_INTEGER;
+               atif_arg_elements[1].integer.value = 0;
+       }
  
        status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer);
  
                DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n",
                                 acpi_format_exception(status));
                kfree(buffer.pointer);
-               return 1;
+               return NULL;
        }
  
-       kfree(buffer.pointer);
-       return 0;
+       return buffer.pointer;
+ }
+ /**
+  * radeon_atif_parse_notification - parse supported notifications
+  *
+  * @n: supported notifications struct
+  * @mask: supported notifications mask from ATIF
+  *
+  * Use the supported notifications mask from ATIF function
+  * ATIF_FUNCTION_VERIFY_INTERFACE to determine what notifications
+  * are supported (all asics).
+  */
+ static void radeon_atif_parse_notification(struct radeon_atif_notifications *n, u32 mask)
+ {
+       n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED;
+       n->expansion_mode_change = mask & ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED;
+       n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED;
+       n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED;
+       n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED;
+       n->display_conf_change = mask & ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED;
+       n->px_gfx_switch = mask & ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED;
+       n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED;
+       n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED;
+ }
+ /**
+  * radeon_atif_parse_functions - parse supported functions
+  *
+  * @f: supported functions struct
+  * @mask: supported functions mask from ATIF
+  *
+  * Use the supported functions mask from ATIF function
+  * ATIF_FUNCTION_VERIFY_INTERFACE to determine what functions
+  * are supported (all asics).
+  */
+ static void radeon_atif_parse_functions(struct radeon_atif_functions *f, u32 mask)
+ {
+       f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED;
+       f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED;
+       f->select_active_disp = mask & ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED;
+       f->lid_state = mask & ATIF_GET_LID_STATE_SUPPORTED;
+       f->get_tv_standard = mask & ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED;
+       f->set_tv_standard = mask & ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED;
+       f->get_panel_expansion_mode = mask & ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED;
+       f->set_panel_expansion_mode = mask & ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED;
+       f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED;
+       f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED;
+ }
+ /**
+  * radeon_atif_verify_interface - verify ATIF
+  *
+  * @handle: acpi handle
+  * @atif: radeon atif struct
+  *
+  * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function
+  * to initialize ATIF and determine what features are supported
+  * (all asics).
+  * returns 0 on success, error on failure.
+  */
+ static int radeon_atif_verify_interface(acpi_handle handle,
+               struct radeon_atif *atif)
+ {
+       union acpi_object *info;
+       struct atif_verify_interface output;
+       size_t size;
+       int err = 0;
+       info = radeon_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL);
+       if (!info)
+               return -EIO;
+       memset(&output, 0, sizeof(output));
+       size = *(u16 *) info->buffer.pointer;
+       if (size < 12) {
+               DRM_INFO("ATIF buffer is too small: %lu\n", size);
+               err = -EINVAL;
+               goto out;
+       }
+       size = min(sizeof(output), size);
+       memcpy(&output, info->buffer.pointer, size);
+       /* TODO: check version? */
+       DRM_DEBUG_DRIVER("ATIF version %u\n", output.version);
+       radeon_atif_parse_notification(&atif->notifications, output.notification_mask);
+       radeon_atif_parse_functions(&atif->functions, output.function_bits);
+ out:
+       kfree(info);
+       return err;
+ }
+ /**
+  * radeon_atif_get_notification_params - determine notify configuration
+  *
+  * @handle: acpi handle
+  * @n: atif notification configuration struct
+  *
+  * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function
+  * to determine if a notifier is used and if so which one
+  * (all asics).  This is either Notify(VGA, 0x81) or Notify(VGA, n)
+  * where n is specified in the result if a notifier is used.
+  * Returns 0 on success, error on failure.
+  */
+ static int radeon_atif_get_notification_params(acpi_handle handle,
+               struct radeon_atif_notification_cfg *n)
+ {
+       union acpi_object *info;
+       struct atif_system_params params;
+       size_t size;
+       int err = 0;
+       info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, NULL);
+       if (!info) {
+               err = -EIO;
+               goto out;
+       }
+       size = *(u16 *) info->buffer.pointer;
+       if (size < 10) {
+               err = -EINVAL;
+               goto out;
+       }
+       memset(&params, 0, sizeof(params));
+       size = min(sizeof(params), size);
+       memcpy(&params, info->buffer.pointer, size);
+       DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n",
+                       params.flags, params.valid_mask);
+       params.flags = params.flags & params.valid_mask;
+       if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) {
+               n->enabled = false;
+               n->command_code = 0;
+       } else if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_81) {
+               n->enabled = true;
+               n->command_code = 0x81;
+       } else {
+               if (size < 11) {
+                       err = -EINVAL;
+                       goto out;
+               }
+               n->enabled = true;
+               n->command_code = params.command_code;
+       }
+ out:
+       DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n",
+                       (n->enabled ? "enabled" : "disabled"),
+                       n->command_code);
+       kfree(info);
+       return err;
+ }
+ /**
+  * radeon_atif_get_sbios_requests - get requested sbios event
+  *
+  * @handle: acpi handle
+  * @req: atif sbios request struct
+  *
+  * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function
+  * to determine what requests the sbios is making to the driver
+  * (all asics).
+  * Returns 0 on success, error on failure.
+  */
+ static int radeon_atif_get_sbios_requests(acpi_handle handle,
+               struct atif_sbios_requests *req)
+ {
+       union acpi_object *info;
+       size_t size;
+       int count = 0;
+       info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, NULL);
+       if (!info)
+               return -EIO;
+       size = *(u16 *)info->buffer.pointer;
+       if (size < 0xd) {
+               count = -EINVAL;
+               goto out;
+       }
+       memset(req, 0, sizeof(*req));
+       size = min(sizeof(*req), size);
+       memcpy(req, info->buffer.pointer, size);
+       DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending);
+       count = hweight32(req->pending);
+ out:
+       kfree(info);
+       return count;
+ }
+ /**
+  * radeon_atif_handler - handle ATIF notify requests
+  *
+  * @rdev: radeon_device pointer
+  * @event: atif sbios request struct
+  *
+  * Checks the acpi event and if it matches an atif event,
+  * handles it.
+  * Returns NOTIFY code
+  */
+ int radeon_atif_handler(struct radeon_device *rdev,
+               struct acpi_bus_event *event)
+ {
+       struct radeon_atif *atif = &rdev->atif;
+       struct atif_sbios_requests req;
+       acpi_handle handle;
+       int count;
+       DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n",
+                       event->device_class, event->type);
+       if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0)
+               return NOTIFY_DONE;
+       if (!atif->notification_cfg.enabled ||
+                       event->type != atif->notification_cfg.command_code)
+               /* Not our event */
+               return NOTIFY_DONE;
+       /* Check pending SBIOS requests */
+       handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev);
+       count = radeon_atif_get_sbios_requests(handle, &req);
+       if (count <= 0)
+               return NOTIFY_DONE;
+       DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count);
+       if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) {
+               struct radeon_encoder *enc = atif->encoder_for_bl;
+               if (enc) {
+                       DRM_DEBUG_DRIVER("Changing brightness to %d\n",
+                                       req.backlight_level);
+                       radeon_set_backlight_level(rdev, enc, req.backlight_level);
+                       if (rdev->is_atom_bios) {
+                               struct radeon_encoder_atom_dig *dig = enc->enc_priv;
+                               backlight_force_update(dig->bl_dev,
+                                                      BACKLIGHT_UPDATE_HOTKEY);
+                       } else {
+                               struct radeon_encoder_lvds *dig = enc->enc_priv;
+                               backlight_force_update(dig->bl_dev,
+                                                      BACKLIGHT_UPDATE_HOTKEY);
+                       }
+               }
+       }
+       /* TODO: check other events */
+       /* We've handled the event, stop the notifier chain. The ACPI interface
+        * overloads ACPI_VIDEO_NOTIFY_PROBE, we don't want to send that to
+        * userspace if the event was generated only to signal a SBIOS
+        * request.
+        */
+       return NOTIFY_BAD;
+ }
+ /* Call the ATCS method
+  */
+ /**
+  * radeon_atcs_call - call an ATCS method
+  *
+  * @handle: acpi handle
+  * @function: the ATCS function to execute
+  * @params: ATCS function params
+  *
+  * Executes the requested ATCS function (all asics).
+  * Returns a pointer to the acpi output buffer.
+  */
+ static union acpi_object *radeon_atcs_call(acpi_handle handle, int function,
+                                          struct acpi_buffer *params)
+ {
+       acpi_status status;
+       union acpi_object atcs_arg_elements[2];
+       struct acpi_object_list atcs_arg;
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       atcs_arg.count = 2;
+       atcs_arg.pointer = &atcs_arg_elements[0];
+       atcs_arg_elements[0].type = ACPI_TYPE_INTEGER;
+       atcs_arg_elements[0].integer.value = function;
+       if (params) {
+               atcs_arg_elements[1].type = ACPI_TYPE_BUFFER;
+               atcs_arg_elements[1].buffer.length = params->length;
+               atcs_arg_elements[1].buffer.pointer = params->pointer;
+       } else {
+               /* We need a second fake parameter */
+               atcs_arg_elements[1].type = ACPI_TYPE_INTEGER;
+               atcs_arg_elements[1].integer.value = 0;
+       }
+       status = acpi_evaluate_object(handle, "ATCS", &atcs_arg, &buffer);
+       /* Fail only if calling the method fails and ATIF is supported */
+       if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+               DRM_DEBUG_DRIVER("failed to evaluate ATCS got %s\n",
+                                acpi_format_exception(status));
+               kfree(buffer.pointer);
+               return NULL;
+       }
+       return buffer.pointer;
+ }
+ /**
+  * radeon_atcs_parse_functions - parse supported functions
+  *
+  * @f: supported functions struct
+  * @mask: supported functions mask from ATCS
+  *
+  * Use the supported functions mask from ATCS function
+  * ATCS_FUNCTION_VERIFY_INTERFACE to determine what functions
+  * are supported (all asics).
+  */
+ static void radeon_atcs_parse_functions(struct radeon_atcs_functions *f, u32 mask)
+ {
+       f->get_ext_state = mask & ATCS_GET_EXTERNAL_STATE_SUPPORTED;
+       f->pcie_perf_req = mask & ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED;
+       f->pcie_dev_rdy = mask & ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED;
+       f->pcie_bus_width = mask & ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED;
+ }
+ /**
+  * radeon_atcs_verify_interface - verify ATCS
+  *
+  * @handle: acpi handle
+  * @atcs: radeon atcs struct
+  *
+  * Execute the ATCS_FUNCTION_VERIFY_INTERFACE ATCS function
+  * to initialize ATCS and determine what features are supported
+  * (all asics).
+  * returns 0 on success, error on failure.
+  */
+ static int radeon_atcs_verify_interface(acpi_handle handle,
+                                       struct radeon_atcs *atcs)
+ {
+       union acpi_object *info;
+       struct atcs_verify_interface output;
+       size_t size;
+       int err = 0;
+       info = radeon_atcs_call(handle, ATCS_FUNCTION_VERIFY_INTERFACE, NULL);
+       if (!info)
+               return -EIO;
+       memset(&output, 0, sizeof(output));
+       size = *(u16 *) info->buffer.pointer;
+       if (size < 8) {
+               DRM_INFO("ATCS buffer is too small: %lu\n", size);
+               err = -EINVAL;
+               goto out;
+       }
+       size = min(sizeof(output), size);
+       memcpy(&output, info->buffer.pointer, size);
+       /* TODO: check version? */
+       DRM_DEBUG_DRIVER("ATCS version %u\n", output.version);
+       radeon_atcs_parse_functions(&atcs->functions, output.function_bits);
+ out:
+       kfree(info);
+       return err;
+ }
+ /**
+  * radeon_acpi_event - handle notify events
+  *
+  * @nb: notifier block
+  * @val: val
+  * @data: acpi event
+  *
+  * Calls relevant radeon functions in response to various
+  * acpi events.
+  * Returns NOTIFY code
+  */
+ static int radeon_acpi_event(struct notifier_block *nb,
+                            unsigned long val,
+                            void *data)
+ {
+       struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb);
+       struct acpi_bus_event *entry = (struct acpi_bus_event *)data;
+       if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) {
+               if (power_supply_is_system_supplied() > 0)
+                       DRM_DEBUG_DRIVER("pm: AC\n");
+               else
+                       DRM_DEBUG_DRIVER("pm: DC\n");
+               radeon_pm_acpi_event_handler(rdev);
+       }
+       /* Check for pending SBIOS requests */
+       return radeon_atif_handler(rdev, entry);
  }
  
  /* Call all ACPI methods here */
+ /**
+  * radeon_acpi_init - init driver acpi support
+  *
+  * @rdev: radeon_device pointer
+  *
+  * Verifies the AMD ACPI interfaces and registers with the acpi
+  * notifier chain (all asics).
+  * Returns 0 on success, error on failure.
+  */
  int radeon_acpi_init(struct radeon_device *rdev)
  {
        acpi_handle handle;
+       struct radeon_atif *atif = &rdev->atif;
+       struct radeon_atcs *atcs = &rdev->atcs;
        int ret;
  
        /* Get the device handle */
        if (!ASIC_IS_AVIVO(rdev) || !rdev->bios || !handle)
                return 0;
  
+       /* Call the ATCS method */
+       ret = radeon_atcs_verify_interface(handle, atcs);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret);
+       }
        /* Call the ATIF method */
-       ret = radeon_atif_call(handle);
-       if (ret)
-               return ret;
+       ret = radeon_atif_verify_interface(handle, atif);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret);
+               goto out;
+       }
+       if (atif->notifications.brightness_change) {
+               struct drm_encoder *tmp;
+               struct radeon_encoder *target = NULL;
+               /* Find the encoder controlling the brightness */
+               list_for_each_entry(tmp, &rdev->ddev->mode_config.encoder_list,
+                               head) {
+                       struct radeon_encoder *enc = to_radeon_encoder(tmp);
+                       if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) &&
+                           enc->enc_priv) {
+                               if (rdev->is_atom_bios) {
+                                       struct radeon_encoder_atom_dig *dig = enc->enc_priv;
+                                       if (dig->bl_dev) {
+                                               target = enc;
+                                               break;
+                                       }
+                               } else {
+                                       struct radeon_encoder_lvds *dig = enc->enc_priv;
+                                       if (dig->bl_dev) {
+                                               target = enc;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               atif->encoder_for_bl = target;
+               if (!target) {
+                       /* Brightness change notification is enabled, but we
+                        * didn't find a backlight controller, this should
+                        * never happen.
+                        */
+                       DRM_ERROR("Cannot find a backlight controller\n");
+               }
+       }
  
-       return 0;
+       if (atif->functions.sbios_requests && !atif->functions.system_params) {
+               /* XXX check this workraround, if sbios request function is
+                * present we have to see how it's configured in the system
+                * params
+                */
+               atif->functions.system_params = true;
+       }
+       if (atif->functions.system_params) {
+               ret = radeon_atif_get_notification_params(handle,
+                               &atif->notification_cfg);
+               if (ret) {
+                       DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n",
+                                       ret);
+                       /* Disable notification */
+                       atif->notification_cfg.enabled = false;
+               }
+       }
+ out:
+       rdev->acpi_nb.notifier_call = radeon_acpi_event;
+       register_acpi_notifier(&rdev->acpi_nb);
+       return ret;
  }
  
+ /**
+  * radeon_acpi_fini - tear down driver acpi support
+  *
+  * @rdev: radeon_device pointer
+  *
+  * Unregisters with the acpi notifier chain (all asics).
+  */
+ void radeon_acpi_fini(struct radeon_device *rdev)
+ {
+       unregister_acpi_notifier(&rdev->acpi_nb);
+ }
@@@ -23,8 -23,8 +23,8 @@@
   * Authors: Dave Airlie
   *          Alex Deucher
   */
 -#include "drmP.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  
  #include "atom.h"
@@@ -1254,6 -1254,10 +1254,10 @@@ bool radeon_atom_get_clock_info(struct 
                if (rdev->clock.max_pixel_clock == 0)
                        rdev->clock.max_pixel_clock = 40000;
  
+               /* not technically a clock, but... */
+               rdev->mode_info.firmware_flags =
+                       le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess);
                return true;
        }
  
@@@ -2005,7 -2009,8 +2009,8 @@@ static int radeon_atombios_parse_power_
        power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
  
        /* add the i2c bus for thermal/fan chip */
-       if (power_info->info.ucOverdriveThermalController > 0) {
+       if ((power_info->info.ucOverdriveThermalController > 0) &&
+           (power_info->info.ucOverdriveThermalController < ARRAY_SIZE(thermal_controller_names))) {
                DRM_INFO("Possible %s thermal controller at 0x%02x\n",
                         thermal_controller_names[power_info->info.ucOverdriveThermalController],
                         power_info->info.ucOverdriveControllerAddress >> 1);
@@@ -2209,7 -2214,7 +2214,7 @@@ static void radeon_atombios_add_pplib_t
                           (controller->ucType ==
                            ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL)) {
                        DRM_INFO("Special thermal controller config\n");
-               } else {
+               } else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) {
                        DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n",
                                 pp_lib_thermal_controller_names[controller->ucType],
                                 controller->ucI2cAddress >> 1,
                                strlcpy(info.type, name, sizeof(info.type));
                                i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
                        }
+               } else {
+                       DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n",
+                                controller->ucType,
+                                controller->ucI2cAddress >> 1,
+                                (controller->ucFanParameters &
+                                 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
                }
        }
  }
@@@ -24,8 -24,8 +24,8 @@@
   * Authors: Dave Airlie
   *          Alex Deucher
   */
 -#include "drmP.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  #include "atom.h"
  
@@@ -3319,15 -3319,6 +3319,6 @@@ static void combios_write_ram_size(stru
        WREG32(RADEON_CONFIG_MEMSIZE, mem_size);
  }
  
- void radeon_combios_dyn_clk_setup(struct drm_device *dev, int enable)
- {
-       uint16_t dyn_clk_info =
-           combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE);
-       if (dyn_clk_info)
-               combios_parse_pll_table(dev, dyn_clk_info);
- }
  void radeon_combios_asic_init(struct drm_device *dev)
  {
        struct radeon_device *rdev = dev->dev_private;
   * Authors: Dave Airlie
   *          Alex Deucher
   */
 -#include "drmP.h"
 -#include "drm_edid.h"
 -#include "drm_crtc_helper.h"
 -#include "drm_fb_helper.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_edid.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/drm_fb_helper.h>
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  #include "atom.h"
  
@@@ -40,10 -40,6 +40,6 @@@ radeon_atombios_connected_scratch_regs(
                                       struct drm_encoder *encoder,
                                       bool connected);
  
- extern void
- radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
-                            struct drm_connector *drm_connector);
  void radeon_connector_hotplug(struct drm_connector *connector)
  {
        struct drm_device *dev = connector->dev;
@@@ -198,7 -194,7 +194,7 @@@ radeon_connector_update_scratch_regs(st
        }
  }
  
- struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, int encoder_type)
+ static struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, int encoder_type)
  {
        struct drm_mode_object *obj;
        struct drm_encoder *encoder;
        return NULL;
  }
  
- struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector)
+ static struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector)
  {
        int enc_id = connector->encoder_ids[0];
        struct drm_mode_object *obj;
@@@ -370,7 -366,7 +366,7 @@@ static void radeon_add_common_modes(str
        }
  }
  
- int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property,
static int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property,
                                  uint64_t val)
  {
        struct drm_device *dev = connector->dev;
@@@ -691,13 -687,13 +687,13 @@@ static int radeon_lvds_set_property(str
  }
  
  
- struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = {
+ static const struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = {
        .get_modes = radeon_lvds_get_modes,
        .mode_valid = radeon_lvds_mode_valid,
        .best_encoder = radeon_best_single_encoder,
  };
  
- struct drm_connector_funcs radeon_lvds_connector_funcs = {
+ static const struct drm_connector_funcs radeon_lvds_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
        .detect = radeon_lvds_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
@@@ -809,13 -805,13 +805,13 @@@ radeon_vga_detect(struct drm_connector 
        return ret;
  }
  
- struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = {
+ static const struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = {
        .get_modes = radeon_vga_get_modes,
        .mode_valid = radeon_vga_mode_valid,
        .best_encoder = radeon_best_single_encoder,
  };
  
- struct drm_connector_funcs radeon_vga_connector_funcs = {
+ static const struct drm_connector_funcs radeon_vga_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
        .detect = radeon_vga_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
@@@ -879,13 -875,13 +875,13 @@@ radeon_tv_detect(struct drm_connector *
        return ret;
  }
  
- struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = {
+ static const struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = {
        .get_modes = radeon_tv_get_modes,
        .mode_valid = radeon_tv_mode_valid,
        .best_encoder = radeon_best_single_encoder,
  };
  
- struct drm_connector_funcs radeon_tv_connector_funcs = {
+ static const struct drm_connector_funcs radeon_tv_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
        .detect = radeon_tv_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
@@@ -1089,7 -1085,7 +1085,7 @@@ out
  }
  
  /* okay need to be smart in here about which encoder to pick */
- struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
+ static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
  {
        int enc_id = connector->encoder_ids[0];
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@@ -1179,13 -1175,13 +1175,13 @@@ static int radeon_dvi_mode_valid(struc
        return MODE_OK;
  }
  
- struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = {
+ static const struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = {
        .get_modes = radeon_dvi_get_modes,
        .mode_valid = radeon_dvi_mode_valid,
        .best_encoder = radeon_dvi_encoder,
  };
  
- struct drm_connector_funcs radeon_dvi_connector_funcs = {
+ static const struct drm_connector_funcs radeon_dvi_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
        .detect = radeon_dvi_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
@@@ -1462,13 -1458,13 +1458,13 @@@ static int radeon_dp_mode_valid(struct 
        }
  }
  
- struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = {
+ static const struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = {
        .get_modes = radeon_dp_get_modes,
        .mode_valid = radeon_dp_mode_valid,
        .best_encoder = radeon_dvi_encoder,
  };
  
- struct drm_connector_funcs radeon_dp_connector_funcs = {
+ static const struct drm_connector_funcs radeon_dp_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
        .detect = radeon_dp_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
@@@ -2008,15 -2004,4 +2004,4 @@@ radeon_add_legacy_connector(struct drm_
                connector->polled = DRM_CONNECTOR_POLL_HPD;
        connector->display_info.subpixel_order = subpixel_order;
        drm_sysfs_connector_add(connector);
-       if (connector_type == DRM_MODE_CONNECTOR_LVDS) {
-               struct drm_encoder *drm_encoder;
-               list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) {
-                       struct radeon_encoder *radeon_encoder;
-                       radeon_encoder = to_radeon_encoder(drm_encoder);
-                       if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_LVDS)
-                               radeon_legacy_backlight_init(radeon_encoder, connector);
-               }
-       }
  }
   * Authors:
   *    Jerome Glisse <glisse@freedesktop.org>
   */
 -#include "drmP.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon_reg.h"
  #include "radeon.h"
  
  void r100_cs_dump_packet(struct radeon_cs_parser *p,
                         struct radeon_cs_packet *pkt);
  
- int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
  {
        struct drm_device *ddev = p->rdev->ddev;
        struct radeon_cs_chunk *chunk;
@@@ -115,19 -115,27 +115,27 @@@ static int radeon_cs_get_ring(struct ra
        return 0;
  }
  
+ static void radeon_cs_sync_to(struct radeon_cs_parser *p,
+                             struct radeon_fence *fence)
+ {
+       struct radeon_fence *other;
+       if (!fence)
+               return;
+       other = p->ib.sync_to[fence->ring];
+       p->ib.sync_to[fence->ring] = radeon_fence_later(fence, other);
+ }
  static void radeon_cs_sync_rings(struct radeon_cs_parser *p)
  {
        int i;
  
        for (i = 0; i < p->nrelocs; i++) {
-               struct radeon_fence *a, *b;
-               if (!p->relocs[i].robj || !p->relocs[i].robj->tbo.sync_obj)
+               if (!p->relocs[i].robj)
                        continue;
  
-               a = p->relocs[i].robj->tbo.sync_obj;
-               b = p->ib.sync_to[a->ring];
-               p->ib.sync_to[a->ring] = radeon_fence_later(a, b);
+               radeon_cs_sync_to(p, p->relocs[i].robj->tbo.sync_obj);
        }
  }
  
@@@ -278,30 -286,6 +286,6 @@@ int radeon_cs_parser_init(struct radeon
        return 0;
  }
  
- static void radeon_bo_vm_fence_va(struct radeon_cs_parser *parser,
-                                 struct radeon_fence *fence)
- {
-       struct radeon_fpriv *fpriv = parser->filp->driver_priv;
-       struct radeon_vm *vm = &fpriv->vm;
-       struct radeon_bo_list *lobj;
-       if (parser->chunk_ib_idx == -1) {
-               return;
-       }
-       if ((parser->cs_flags & RADEON_CS_USE_VM) == 0) {
-               return;
-       }
-       list_for_each_entry(lobj, &parser->validated, tv.head) {
-               struct radeon_bo_va *bo_va;
-               struct radeon_bo *rbo = lobj->bo;
-               bo_va = radeon_bo_va(rbo, vm);
-               radeon_fence_unref(&bo_va->fence);
-               bo_va->fence = radeon_fence_ref(fence);
-       }
- }
  /**
   * cs_parser_fini() - clean parser states
   * @parser:   parser structure holding parsing context.
@@@ -315,8 -299,6 +299,6 @@@ static void radeon_cs_parser_fini(struc
        unsigned i;
  
        if (!error) {
-               /* fence all bo va before ttm_eu_fence_buffer_objects so bo are still reserved */
-               radeon_bo_vm_fence_va(parser, parser->ib.fence);
                ttm_eu_fence_buffer_objects(&parser->validated,
                                            parser->ib.fence);
        } else {
@@@ -363,7 -345,7 +345,7 @@@ static int radeon_cs_ib_chunk(struct ra
         * uncached).
         */
        r =  radeon_ib_get(rdev, parser->ring, &parser->ib,
-                          ib_chunk->length_dw * 4);
+                          NULL, ib_chunk->length_dw * 4);
        if (r) {
                DRM_ERROR("Failed to get ib !\n");
                return r;
                return r;
        }
        radeon_cs_sync_rings(parser);
-       parser->ib.vm_id = 0;
        r = radeon_ib_schedule(rdev, &parser->ib, NULL);
        if (r) {
                DRM_ERROR("Failed to schedule IB !\n");
  static int radeon_bo_vm_update_pte(struct radeon_cs_parser *parser,
                                   struct radeon_vm *vm)
  {
+       struct radeon_device *rdev = parser->rdev;
        struct radeon_bo_list *lobj;
        struct radeon_bo *bo;
        int r;
  
+       r = radeon_vm_bo_update_pte(rdev, vm, rdev->ring_tmp_bo.bo, &rdev->ring_tmp_bo.bo->tbo.mem);
+       if (r) {
+               return r;
+       }
        list_for_each_entry(lobj, &parser->validated, tv.head) {
                bo = lobj->bo;
                r = radeon_vm_bo_update_pte(parser->rdev, vm, bo, &bo->tbo.mem);
@@@ -426,7 -412,7 +412,7 @@@ static int radeon_cs_ib_vm_chunk(struc
                        return -EINVAL;
                }
                r =  radeon_ib_get(rdev, parser->ring, &parser->const_ib,
-                                  ib_chunk->length_dw * 4);
+                                  vm, ib_chunk->length_dw * 4);
                if (r) {
                        DRM_ERROR("Failed to get const ib !\n");
                        return r;
                return -EINVAL;
        }
        r =  radeon_ib_get(rdev, parser->ring, &parser->ib,
-                          ib_chunk->length_dw * 4);
+                          vm, ib_chunk->length_dw * 4);
        if (r) {
                DRM_ERROR("Failed to get ib !\n");
                return r;
  
        mutex_lock(&rdev->vm_manager.lock);
        mutex_lock(&vm->mutex);
-       r = radeon_vm_bind(rdev, vm);
+       r = radeon_vm_alloc_pt(rdev, vm);
        if (r) {
                goto out;
        }
                goto out;
        }
        radeon_cs_sync_rings(parser);
-       parser->ib.vm_id = vm->id;
-       /* ib pool is bind at 0 in virtual address space,
-        * so gpu_addr is the offset inside the pool bo
-        */
-       parser->ib.gpu_addr = parser->ib.sa_bo->soffset;
+       radeon_cs_sync_to(parser, vm->fence);
+       radeon_cs_sync_to(parser, radeon_vm_grab_id(rdev, vm, parser->ring));
  
        if ((rdev->family >= CHIP_TAHITI) &&
            (parser->chunk_const_ib_idx != -1)) {
-               parser->const_ib.vm_id = vm->id;
-               /* ib pool is bind at 0 in virtual address space,
-                * so gpu_addr is the offset inside the pool bo
-                */
-               parser->const_ib.gpu_addr = parser->const_ib.sa_bo->soffset;
                r = radeon_ib_schedule(rdev, &parser->ib, &parser->const_ib);
        } else {
                r = radeon_ib_schedule(rdev, &parser->ib, NULL);
        }
  
- out:
        if (!r) {
-               if (vm->fence) {
-                       radeon_fence_unref(&vm->fence);
-               }
-               vm->fence = radeon_fence_ref(parser->ib.fence);
+               radeon_vm_fence(rdev, vm, parser->ib.fence);
        }
+ out:
        mutex_unlock(&vm->mutex);
        mutex_unlock(&rdev->vm_manager.lock);
        return r;
   * OTHER DEALINGS IN THE SOFTWARE.
   */
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon_drv.h"
  
 -#include "drm_pciids.h"
 +#include <drm/drm_pciids.h>
  #include <linux/console.h>
  #include <linux/module.h>
  
   *   2.20.0 - r600-si: RADEON_INFO_TIMESTAMP query
   *   2.21.0 - r600-r700: FMASK and CMASK
   *   2.22.0 - r600 only: RESOLVE_BOX allowed
+  *   2.23.0 - allow STRMOUT_BASE_UPDATE on RS780 and RS880
+  *   2.24.0 - eg only: allow MIP_ADDRESS=0 for MSAA textures
   */
  #define KMS_DRIVER_MAJOR      2
- #define KMS_DRIVER_MINOR      22
+ #define KMS_DRIVER_MINOR      24
  #define KMS_DRIVER_PATCHLEVEL 0
  int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
  int radeon_driver_unload_kms(struct drm_device *dev);
   * Authors: Dave Airlie
   *          Alex Deucher
   */
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  #include "atom.h"
  
+ extern void
+ radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
+                            struct drm_connector *drm_connector);
+ extern void
+ radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,
+                          struct drm_connector *drm_connector);
  static uint32_t radeon_encoder_clones(struct drm_encoder *encoder)
  {
        struct drm_device *dev = encoder->dev;
@@@ -153,6 -161,7 +161,7 @@@ radeon_get_encoder_enum(struct drm_devi
  void
  radeon_link_encoder_connector(struct drm_device *dev)
  {
+       struct radeon_device *rdev = dev->dev_private;
        struct drm_connector *connector;
        struct radeon_connector *radeon_connector;
        struct drm_encoder *encoder;
                radeon_connector = to_radeon_connector(connector);
                list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                        radeon_encoder = to_radeon_encoder(encoder);
-                       if (radeon_encoder->devices & radeon_connector->devices)
+                       if (radeon_encoder->devices & radeon_connector->devices) {
                                drm_mode_connector_attach_encoder(connector, encoder);
+                               if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+                                       if (rdev->is_atom_bios)
+                                               radeon_atom_backlight_init(radeon_encoder, connector);
+                                       else
+                                               radeon_legacy_backlight_init(radeon_encoder, connector);
+                                       rdev->mode_info.bl_encoder = radeon_encoder;
+                               }
+                       }
                }
        }
  }
  #include <linux/slab.h>
  #include <linux/fb.h>
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 -#include "drm_crtc_helper.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  
 -#include "drm_fb_helper.h"
 +#include <drm/drm_fb_helper.h>
  
  #include <linux/vga_switcheroo.h>
  
@@@ -315,22 -316,6 +315,6 @@@ static int radeon_fb_find_or_create_sin
        return new_fb;
  }
  
- static char *mode_option;
- int radeon_parse_options(char *options)
- {
-       char *this_opt;
-       if (!options || !*options)
-               return 0;
-       while ((this_opt = strsep(&options, ",")) != NULL) {
-               if (!*this_opt)
-                       continue;
-               mode_option = this_opt;
-       }
-       return 0;
- }
  void radeon_fb_output_poll_changed(struct radeon_device *rdev)
  {
        drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper);
@@@ -34,7 -34,8 +34,7 @@@
  #include <linux/list.h>
  #include <linux/kref.h>
  #include <linux/slab.h>
 -#include "drmP.h"
 -#include "drm.h"
 +#include <drm/drmP.h>
  #include "radeon_reg.h"
  #include "radeon.h"
  #include "radeon_trace.h"
@@@ -398,7 -399,7 +398,7 @@@ int radeon_fence_wait(struct radeon_fen
        return 0;
  }
  
- bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq)
static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq)
  {
        unsigned i;
  
@@@ -25,8 -25,8 +25,8 @@@
   *          Alex Deucher
   *          Jerome Glisse
   */
 -#include "drmP.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  #include "radeon_reg.h"
  
@@@ -423,6 -423,18 +423,18 @@@ void radeon_gart_fini(struct radeon_dev
   */
  
  /**
+  * radeon_vm_directory_size - returns the size of the page directory in bytes
+  *
+  * @rdev: radeon_device pointer
+  *
+  * Calculate the size of the page directory in bytes (cayman+).
+  */
+ static unsigned radeon_vm_directory_size(struct radeon_device *rdev)
+ {
+       return (rdev->vm_manager.max_pfn >> RADEON_VM_BLOCK_SIZE) * 8;
+ }
+ /**
   * radeon_vm_manager_init - init the vm manager
   *
   * @rdev: radeon_device pointer
@@@ -435,12 -447,15 +447,15 @@@ int radeon_vm_manager_init(struct radeo
        struct radeon_vm *vm;
        struct radeon_bo_va *bo_va;
        int r;
+       unsigned size;
  
        if (!rdev->vm_manager.enabled) {
-               /* mark first vm as always in use, it's the system one */
                /* allocate enough for 2 full VM pts */
+               size = RADEON_GPU_PAGE_ALIGN(radeon_vm_directory_size(rdev));
+               size += RADEON_GPU_PAGE_ALIGN(rdev->vm_manager.max_pfn * 8);
+               size *= 2;
                r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager,
-                                             rdev->vm_manager.max_pfn * 8 * 2,
+                                             size,
                                              RADEON_GEM_DOMAIN_VRAM);
                if (r) {
                        dev_err(rdev->dev, "failed to allocate vm bo (%dKB)\n",
                        return r;
                }
  
-               r = rdev->vm_manager.funcs->init(rdev);
+               r = radeon_asic_vm_init(rdev);
                if (r)
                        return r;
-       
                rdev->vm_manager.enabled = true;
  
                r = radeon_sa_bo_manager_start(rdev, &rdev->vm_manager.sa_manager);
  
        /* restore page table */
        list_for_each_entry(vm, &rdev->vm_manager.lru_vm, list) {
-               if (vm->id == -1)
+               if (vm->sa_bo == NULL)
                        continue;
  
                list_for_each_entry(bo_va, &vm->va, vm_list) {
-                       struct ttm_mem_reg *mem = NULL;
-                       if (bo_va->valid)
-                               mem = &bo_va->bo->tbo.mem;
                        bo_va->valid = false;
-                       r = radeon_vm_bo_update_pte(rdev, vm, bo_va->bo, mem);
-                       if (r) {
-                               DRM_ERROR("Failed to update pte for vm %d!\n", vm->id);
-                       }
-               }
-               r = rdev->vm_manager.funcs->bind(rdev, vm, vm->id);
-               if (r) {
-                       DRM_ERROR("Failed to bind vm %d!\n", vm->id);
                }
        }
        return 0;
  }
  
- /* global mutex must be lock */
  /**
-  * radeon_vm_unbind_locked - unbind a specific vm
+  * radeon_vm_free_pt - free the page table for a specific vm
   *
   * @rdev: radeon_device pointer
   * @vm: vm to unbind
   *
-  * Unbind the requested vm (cayman+).
-  * Wait for use of the VM to finish, then unbind the page table,
-  * and free the page table memory.
+  * Free the page table of a specific vm (cayman+).
+  *
+  * Global and local mutex must be lock!
   */
- static void radeon_vm_unbind_locked(struct radeon_device *rdev,
+ static void radeon_vm_free_pt(struct radeon_device *rdev,
                                    struct radeon_vm *vm)
  {
        struct radeon_bo_va *bo_va;
  
-       if (vm->id == -1) {
+       if (!vm->sa_bo)
                return;
-       }
  
-       /* wait for vm use to end */
-       while (vm->fence) {
-               int r;
-               r = radeon_fence_wait(vm->fence, false);
-               if (r)
-                       DRM_ERROR("error while waiting for fence: %d\n", r);
-               if (r == -EDEADLK) {
-                       mutex_unlock(&rdev->vm_manager.lock);
-                       r = radeon_gpu_reset(rdev);
-                       mutex_lock(&rdev->vm_manager.lock);
-                       if (!r)
-                               continue;
-               }
-               break;
-       }
-       radeon_fence_unref(&vm->fence);
-       /* hw unbind */
-       rdev->vm_manager.funcs->unbind(rdev, vm);
-       rdev->vm_manager.use_bitmap &= ~(1 << vm->id);
        list_del_init(&vm->list);
-       vm->id = -1;
-       radeon_sa_bo_free(rdev, &vm->sa_bo, NULL);
-       vm->pt = NULL;
+       radeon_sa_bo_free(rdev, &vm->sa_bo, vm->fence);
  
        list_for_each_entry(bo_va, &vm->va, vm_list) {
                bo_va->valid = false;
  void radeon_vm_manager_fini(struct radeon_device *rdev)
  {
        struct radeon_vm *vm, *tmp;
+       int i;
  
        if (!rdev->vm_manager.enabled)
                return;
  
        mutex_lock(&rdev->vm_manager.lock);
-       /* unbind all active vm */
+       /* free all allocated page tables */
        list_for_each_entry_safe(vm, tmp, &rdev->vm_manager.lru_vm, list) {
-               radeon_vm_unbind_locked(rdev, vm);
+               mutex_lock(&vm->mutex);
+               radeon_vm_free_pt(rdev, vm);
+               mutex_unlock(&vm->mutex);
        }
-       rdev->vm_manager.funcs->fini(rdev);
+       for (i = 0; i < RADEON_NUM_VM; ++i) {
+               radeon_fence_unref(&rdev->vm_manager.active[i]);
+       }
+       radeon_asic_vm_fini(rdev);
        mutex_unlock(&rdev->vm_manager.lock);
  
        radeon_sa_bo_manager_suspend(rdev, &rdev->vm_manager.sa_manager);
        rdev->vm_manager.enabled = false;
  }
  
- /* global mutex must be locked */
  /**
-  * radeon_vm_unbind - locked version of unbind
-  *
-  * @rdev: radeon_device pointer
-  * @vm: vm to unbind
-  *
-  * Locked version that wraps radeon_vm_unbind_locked (cayman+).
-  */
- void radeon_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm)
- {
-       mutex_lock(&vm->mutex);
-       radeon_vm_unbind_locked(rdev, vm);
-       mutex_unlock(&vm->mutex);
- }
- /* global and local mutex must be locked */
- /**
-  * radeon_vm_bind - bind a page table to a VMID
+  * radeon_vm_alloc_pt - allocates a page table for a VM
   *
   * @rdev: radeon_device pointer
   * @vm: vm to bind
   *
-  * Bind the requested vm (cayman+).
-  * Suballocate memory for the page table, allocate a VMID
-  * and bind the page table to it, and finally start to populate
-  * the page table.
+  * Allocate a page table for the requested vm (cayman+).
+  * Also starts to populate the page table.
   * Returns 0 for success, error for failure.
+  *
+  * Global and local mutex must be locked!
   */
- int radeon_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm)
+ int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm)
  {
        struct radeon_vm *vm_evict;
-       unsigned i;
-       int id = -1, r;
+       int r;
+       u64 *pd_addr;
+       int tables_size;
  
        if (vm == NULL) {
                return -EINVAL;
        }
  
-       if (vm->id != -1) {
+       /* allocate enough to cover the current VM size */
+       tables_size = RADEON_GPU_PAGE_ALIGN(radeon_vm_directory_size(rdev));
+       tables_size += RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8);
+       if (vm->sa_bo != NULL) {
                /* update lru */
                list_del_init(&vm->list);
                list_add_tail(&vm->list, &rdev->vm_manager.lru_vm);
  
  retry:
        r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, &vm->sa_bo,
-                            RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8),
-                            RADEON_GPU_PAGE_SIZE, false);
-       if (r) {
+                            tables_size, RADEON_GPU_PAGE_SIZE, false);
+       if (r == -ENOMEM) {
                if (list_empty(&rdev->vm_manager.lru_vm)) {
                        return r;
                }
                vm_evict = list_first_entry(&rdev->vm_manager.lru_vm, struct radeon_vm, list);
-               radeon_vm_unbind(rdev, vm_evict);
+               mutex_lock(&vm_evict->mutex);
+               radeon_vm_free_pt(rdev, vm_evict);
+               mutex_unlock(&vm_evict->mutex);
                goto retry;
+       } else if (r) {
+               return r;
        }
-       vm->pt = radeon_sa_bo_cpu_addr(vm->sa_bo);
-       vm->pt_gpu_addr = radeon_sa_bo_gpu_addr(vm->sa_bo);
-       memset(vm->pt, 0, RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8));
  
- retry_id:
-       /* search for free vm */
-       for (i = 0; i < rdev->vm_manager.nvm; i++) {
-               if (!(rdev->vm_manager.use_bitmap & (1 << i))) {
-                       id = i;
-                       break;
+       pd_addr = radeon_sa_bo_cpu_addr(vm->sa_bo);
+       vm->pd_gpu_addr = radeon_sa_bo_gpu_addr(vm->sa_bo);
+       memset(pd_addr, 0, tables_size);
+       list_add_tail(&vm->list, &rdev->vm_manager.lru_vm);
+       return radeon_vm_bo_update_pte(rdev, vm, rdev->ring_tmp_bo.bo,
+                                      &rdev->ring_tmp_bo.bo->tbo.mem);
+ }
+ /**
+  * radeon_vm_grab_id - allocate the next free VMID
+  *
+  * @rdev: radeon_device pointer
+  * @vm: vm to allocate id for
+  * @ring: ring we want to submit job to
+  *
+  * Allocate an id for the vm (cayman+).
+  * Returns the fence we need to sync to (if any).
+  *
+  * Global and local mutex must be locked!
+  */
+ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
+                                      struct radeon_vm *vm, int ring)
+ {
+       struct radeon_fence *best[RADEON_NUM_RINGS] = {};
+       unsigned choices[2] = {};
+       unsigned i;
+       /* check if the id is still valid */
+       if (vm->fence && vm->fence == rdev->vm_manager.active[vm->id])
+               return NULL;
+       /* we definately need to flush */
+       radeon_fence_unref(&vm->last_flush);
+       /* skip over VMID 0, since it is the system VM */
+       for (i = 1; i < rdev->vm_manager.nvm; ++i) {
+               struct radeon_fence *fence = rdev->vm_manager.active[i];
+               if (fence == NULL) {
+                       /* found a free one */
+                       vm->id = i;
+                       return NULL;
+               }
+               if (radeon_fence_is_earlier(fence, best[fence->ring])) {
+                       best[fence->ring] = fence;
+                       choices[fence->ring == ring ? 0 : 1] = i;
                }
        }
-       /* evict vm if necessary */
-       if (id == -1) {
-               vm_evict = list_first_entry(&rdev->vm_manager.lru_vm, struct radeon_vm, list);
-               radeon_vm_unbind(rdev, vm_evict);
-               goto retry_id;
+       for (i = 0; i < 2; ++i) {
+               if (choices[i]) {
+                       vm->id = choices[i];
+                       return rdev->vm_manager.active[choices[i]];
+               }
        }
  
-       /* do hw bind */
-       r = rdev->vm_manager.funcs->bind(rdev, vm, id);
-       if (r) {
-               radeon_sa_bo_free(rdev, &vm->sa_bo, NULL);
-               return r;
+       /* should never happen */
+       BUG();
+       return NULL;
+ }
+ /**
+  * radeon_vm_fence - remember fence for vm
+  *
+  * @rdev: radeon_device pointer
+  * @vm: vm we want to fence
+  * @fence: fence to remember
+  *
+  * Fence the vm (cayman+).
+  * Set the fence used to protect page table and id.
+  *
+  * Global and local mutex must be locked!
+  */
+ void radeon_vm_fence(struct radeon_device *rdev,
+                    struct radeon_vm *vm,
+                    struct radeon_fence *fence)
+ {
+       radeon_fence_unref(&rdev->vm_manager.active[vm->id]);
+       rdev->vm_manager.active[vm->id] = radeon_fence_ref(fence);
+       radeon_fence_unref(&vm->fence);
+       vm->fence = radeon_fence_ref(fence);
+ }
+ /**
+  * radeon_vm_bo_find - find the bo_va for a specific vm & bo
+  *
+  * @vm: requested vm
+  * @bo: requested buffer object
+  *
+  * Find @bo inside the requested vm (cayman+).
+  * Search inside the @bos vm list for the requested vm
+  * Returns the found bo_va or NULL if none is found
+  *
+  * Object has to be reserved!
+  */
+ struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm,
+                                      struct radeon_bo *bo)
+ {
+       struct radeon_bo_va *bo_va;
+       list_for_each_entry(bo_va, &bo->va, bo_list) {
+               if (bo_va->vm == vm) {
+                       return bo_va;
+               }
        }
-       rdev->vm_manager.use_bitmap |= 1 << id;
-       vm->id = id;
-       list_add_tail(&vm->list, &rdev->vm_manager.lru_vm);
-       return radeon_vm_bo_update_pte(rdev, vm, rdev->ring_tmp_bo.bo,
-                                      &rdev->ring_tmp_bo.bo->tbo.mem);
+       return NULL;
  }
  
- /* object have to be reserved */
  /**
   * radeon_vm_bo_add - add a bo to a specific vm
   *
   * @rdev: radeon_device pointer
   * @vm: requested vm
   * @bo: radeon buffer object
-  * @offset: requested offset of the buffer in the VM address space
-  * @flags: attributes of pages (read/write/valid/etc.)
   *
   * Add @bo into the requested vm (cayman+).
-  * Add @bo to the list of bos associated with the vm and validate
-  * the offset requested within the vm address space.
-  * Returns 0 for success, error for failure.
+  * Add @bo to the list of bos associated with the vm
+  * Returns newly added bo_va or NULL for failure
+  *
+  * Object has to be reserved!
   */
- int radeon_vm_bo_add(struct radeon_device *rdev,
-                    struct radeon_vm *vm,
-                    struct radeon_bo *bo,
-                    uint64_t offset,
-                    uint32_t flags)
+ struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev,
+                                     struct radeon_vm *vm,
+                                     struct radeon_bo *bo)
  {
-       struct radeon_bo_va *bo_va, *tmp;
-       struct list_head *head;
-       uint64_t size = radeon_bo_size(bo), last_offset = 0;
-       unsigned last_pfn;
+       struct radeon_bo_va *bo_va;
  
        bo_va = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL);
        if (bo_va == NULL) {
-               return -ENOMEM;
+               return NULL;
        }
        bo_va->vm = vm;
        bo_va->bo = bo;
-       bo_va->soffset = offset;
-       bo_va->eoffset = offset + size;
-       bo_va->flags = flags;
+       bo_va->soffset = 0;
+       bo_va->eoffset = 0;
+       bo_va->flags = 0;
        bo_va->valid = false;
+       bo_va->ref_count = 1;
        INIT_LIST_HEAD(&bo_va->bo_list);
        INIT_LIST_HEAD(&bo_va->vm_list);
-       /* make sure object fit at this offset */
-       if (bo_va->soffset >= bo_va->eoffset) {
-               kfree(bo_va);
-               return -EINVAL;
-       }
  
-       last_pfn = bo_va->eoffset / RADEON_GPU_PAGE_SIZE;
-       if (last_pfn > rdev->vm_manager.max_pfn) {
-               kfree(bo_va);
-               dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n",
-                       last_pfn, rdev->vm_manager.max_pfn);
-               return -EINVAL;
+       mutex_lock(&vm->mutex);
+       list_add(&bo_va->vm_list, &vm->va);
+       list_add_tail(&bo_va->bo_list, &bo->va);
+       mutex_unlock(&vm->mutex);
+       return bo_va;
+ }
+ /**
+  * radeon_vm_bo_set_addr - set bos virtual address inside a vm
+  *
+  * @rdev: radeon_device pointer
+  * @bo_va: bo_va to store the address
+  * @soffset: requested offset of the buffer in the VM address space
+  * @flags: attributes of pages (read/write/valid/etc.)
+  *
+  * Set offset of @bo_va (cayman+).
+  * Validate and set the offset requested within the vm address space.
+  * Returns 0 for success, error for failure.
+  *
+  * Object has to be reserved!
+  */
+ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
+                         struct radeon_bo_va *bo_va,
+                         uint64_t soffset,
+                         uint32_t flags)
+ {
+       uint64_t size = radeon_bo_size(bo_va->bo);
+       uint64_t eoffset, last_offset = 0;
+       struct radeon_vm *vm = bo_va->vm;
+       struct radeon_bo_va *tmp;
+       struct list_head *head;
+       unsigned last_pfn;
+       if (soffset) {
+               /* make sure object fit at this offset */
+               eoffset = soffset + size;
+               if (soffset >= eoffset) {
+                       return -EINVAL;
+               }
+               last_pfn = eoffset / RADEON_GPU_PAGE_SIZE;
+               if (last_pfn > rdev->vm_manager.max_pfn) {
+                       dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n",
+                               last_pfn, rdev->vm_manager.max_pfn);
+                       return -EINVAL;
+               }
+       } else {
+               eoffset = last_pfn = 0;
        }
  
        mutex_lock(&vm->mutex);
                if (last_pfn > vm->last_pfn) {
                        /* grow va space 32M by 32M */
                        unsigned align = ((32 << 20) >> 12) - 1;
-                       radeon_vm_unbind_locked(rdev, vm);
+                       radeon_vm_free_pt(rdev, vm);
                        vm->last_pfn = (last_pfn + align) & ~align;
                }
                mutex_unlock(&rdev->vm_manager.lock);
        head = &vm->va;
        last_offset = 0;
        list_for_each_entry(tmp, &vm->va, vm_list) {
-               if (bo_va->soffset >= last_offset && bo_va->eoffset < tmp->soffset) {
+               if (bo_va == tmp) {
+                       /* skip over currently modified bo */
+                       continue;
+               }
+               if (soffset >= last_offset && eoffset <= tmp->soffset) {
                        /* bo can be added before this one */
                        break;
                }
-               if (bo_va->soffset >= tmp->soffset && bo_va->soffset < tmp->eoffset) {
+               if (eoffset > tmp->soffset && soffset < tmp->eoffset) {
                        /* bo and tmp overlap, invalid offset */
                        dev_err(rdev->dev, "bo %p va 0x%08X conflict with (bo %p 0x%08X 0x%08X)\n",
-                               bo, (unsigned)bo_va->soffset, tmp->bo,
+                               bo_va->bo, (unsigned)bo_va->soffset, tmp->bo,
                                (unsigned)tmp->soffset, (unsigned)tmp->eoffset);
-                       kfree(bo_va);
                        mutex_unlock(&vm->mutex);
                        return -EINVAL;
                }
                last_offset = tmp->eoffset;
                head = &tmp->vm_list;
        }
-       list_add(&bo_va->vm_list, head);
-       list_add_tail(&bo_va->bo_list, &bo->va);
+       bo_va->soffset = soffset;
+       bo_va->eoffset = eoffset;
+       bo_va->flags = flags;
+       bo_va->valid = false;
+       list_move(&bo_va->vm_list, head);
        mutex_unlock(&vm->mutex);
        return 0;
  }
  
  /**
-  * radeon_vm_get_addr - get the physical address of the page
+  * radeon_vm_map_gart - get the physical address of a gart page
   *
   * @rdev: radeon_device pointer
-  * @mem: ttm mem
-  * @pfn: pfn
+  * @addr: the unmapped addr
   *
   * Look up the physical address of the page that the pte resolves
   * to (cayman+).
   * Returns the physical address of the page.
   */
- static u64 radeon_vm_get_addr(struct radeon_device *rdev,
-                             struct ttm_mem_reg *mem,
-                             unsigned pfn)
+ uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr)
  {
-       u64 addr = 0;
-       switch (mem->mem_type) {
-       case TTM_PL_VRAM:
-               addr = (mem->start << PAGE_SHIFT);
-               addr += pfn * RADEON_GPU_PAGE_SIZE;
-               addr += rdev->vm_manager.vram_base_offset;
-               break;
-       case TTM_PL_TT:
-               /* offset inside page table */
-               addr = mem->start << PAGE_SHIFT;
-               addr += pfn * RADEON_GPU_PAGE_SIZE;
-               addr = addr >> PAGE_SHIFT;
-               /* page table offset */
-               addr = rdev->gart.pages_addr[addr];
-               /* in case cpu page size != gpu page size*/
-               addr += (pfn * RADEON_GPU_PAGE_SIZE) & (~PAGE_MASK);
-               break;
-       default:
-               break;
-       }
-       return addr;
+       uint64_t result;
+       /* page table offset */
+       result = rdev->gart.pages_addr[addr >> PAGE_SHIFT];
+       /* in case cpu page size != gpu page size*/
+       result |= addr & (~PAGE_MASK);
+       return result;
  }
  
- /* object have to be reserved & global and local mutex must be locked */
  /**
   * radeon_vm_bo_update_pte - map a bo into the vm page table
   *
   *
   * Fill in the page table entries for @bo (cayman+).
   * Returns 0 for success, -EINVAL for failure.
+  *
+  * Object have to be reserved & global and local mutex must be locked!
   */
  int radeon_vm_bo_update_pte(struct radeon_device *rdev,
                            struct radeon_vm *vm,
                            struct radeon_bo *bo,
                            struct ttm_mem_reg *mem)
  {
+       unsigned ridx = rdev->asic->vm.pt_ring_index;
+       struct radeon_ring *ring = &rdev->ring[ridx];
+       struct radeon_semaphore *sem = NULL;
        struct radeon_bo_va *bo_va;
-       unsigned ngpu_pages, i;
-       uint64_t addr = 0, pfn;
-       uint32_t flags;
+       unsigned nptes, npdes, ndw;
+       uint64_t pe, addr;
+       uint64_t pfn;
+       int r;
  
        /* nothing to do if vm isn't bound */
-       if (vm->id == -1)
+       if (vm->sa_bo == NULL)
                return 0;
  
-       bo_va = radeon_bo_va(bo, vm);
+       bo_va = radeon_vm_bo_find(vm, bo);
        if (bo_va == NULL) {
                dev_err(rdev->dev, "bo %p not in vm %p\n", bo, vm);
                return -EINVAL;
        }
  
-       if (bo_va->valid && mem)
+       if (!bo_va->soffset) {
+               dev_err(rdev->dev, "bo %p don't has a mapping in vm %p\n",
+                       bo, vm);
+               return -EINVAL;
+       }
+       if ((bo_va->valid && mem) || (!bo_va->valid && mem == NULL))
                return 0;
  
-       ngpu_pages = radeon_bo_ngpu_pages(bo);
        bo_va->flags &= ~RADEON_VM_PAGE_VALID;
        bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM;
        if (mem) {
+               addr = mem->start << PAGE_SHIFT;
                if (mem->mem_type != TTM_PL_SYSTEM) {
                        bo_va->flags |= RADEON_VM_PAGE_VALID;
                        bo_va->valid = true;
                }
                if (mem->mem_type == TTM_PL_TT) {
                        bo_va->flags |= RADEON_VM_PAGE_SYSTEM;
+               } else {
+                       addr += rdev->vm_manager.vram_base_offset;
                }
+       } else {
+               addr = 0;
+               bo_va->valid = false;
        }
-       pfn = bo_va->soffset / RADEON_GPU_PAGE_SIZE;
-       flags = rdev->vm_manager.funcs->page_flags(rdev, bo_va->vm, bo_va->flags);
-       for (i = 0, addr = 0; i < ngpu_pages; i++) {
-               if (mem && bo_va->valid) {
-                       addr = radeon_vm_get_addr(rdev, mem, i);
+       if (vm->fence && radeon_fence_signaled(vm->fence)) {
+               radeon_fence_unref(&vm->fence);
+       }
+       if (vm->fence && vm->fence->ring != ridx) {
+               r = radeon_semaphore_create(rdev, &sem);
+               if (r) {
+                       return r;
                }
-               rdev->vm_manager.funcs->set_page(rdev, bo_va->vm, i + pfn, addr, flags);
        }
-       rdev->vm_manager.funcs->tlb_flush(rdev, bo_va->vm);
+       /* estimate number of dw needed */
+       /* reserve space for 32-bit padding */
+       ndw = 32;
+       nptes = radeon_bo_ngpu_pages(bo);
+       pfn = (bo_va->soffset / RADEON_GPU_PAGE_SIZE);
+       /* handle cases where a bo spans several pdes  */
+       npdes = (ALIGN(pfn + nptes, RADEON_VM_PTE_COUNT) -
+                (pfn & ~(RADEON_VM_PTE_COUNT - 1))) >> RADEON_VM_BLOCK_SIZE;
+       /* reserve space for one header for every 2k dwords */
+       ndw += (nptes >> 11) * 3;
+       /* reserve space for pte addresses */
+       ndw += nptes * 2;
+       /* reserve space for one header for every 2k dwords */
+       ndw += (npdes >> 11) * 3;
+       /* reserve space for pde addresses */
+       ndw += npdes * 2;
+       r = radeon_ring_lock(rdev, ring, ndw);
+       if (r) {
+               return r;
+       }
+       if (sem && radeon_fence_need_sync(vm->fence, ridx)) {
+               radeon_semaphore_sync_rings(rdev, sem, vm->fence->ring, ridx);
+               radeon_fence_note_sync(vm->fence, ridx);
+       }
+       /* update page table entries */
+       pe = vm->pd_gpu_addr;
+       pe += radeon_vm_directory_size(rdev);
+       pe += (bo_va->soffset / RADEON_GPU_PAGE_SIZE) * 8;
+       radeon_asic_vm_set_page(rdev, pe, addr, nptes,
+                               RADEON_GPU_PAGE_SIZE, bo_va->flags);
+       /* update page directory entries */
+       addr = pe;
+       pe = vm->pd_gpu_addr;
+       pe += ((bo_va->soffset / RADEON_GPU_PAGE_SIZE) >> RADEON_VM_BLOCK_SIZE) * 8;
+       radeon_asic_vm_set_page(rdev, pe, addr, npdes,
+                               RADEON_VM_PTE_COUNT * 8, RADEON_VM_PAGE_VALID);
+       radeon_fence_unref(&vm->fence);
+       r = radeon_fence_emit(rdev, &vm->fence, ridx);
+       if (r) {
+               radeon_ring_unlock_undo(rdev, ring);
+               return r;
+       }
+       radeon_ring_unlock_commit(rdev, ring);
+       radeon_semaphore_free(rdev, &sem, vm->fence);
+       radeon_fence_unref(&vm->last_flush);
        return 0;
  }
  
- /* object have to be reserved */
  /**
   * radeon_vm_bo_rmv - remove a bo to a specific vm
   *
   * @rdev: radeon_device pointer
-  * @vm: requested vm
-  * @bo: radeon buffer object
+  * @bo_va: requested bo_va
   *
-  * Remove @bo from the requested vm (cayman+).
-  * Remove @bo from the list of bos associated with the vm and
-  * remove the ptes for @bo in the page table.
+  * Remove @bo_va->bo from the requested vm (cayman+).
+  * Remove @bo_va->bo from the list of bos associated with the bo_va->vm and
+  * remove the ptes for @bo_va in the page table.
   * Returns 0 for success.
+  *
+  * Object have to be reserved!
   */
  int radeon_vm_bo_rmv(struct radeon_device *rdev,
-                    struct radeon_vm *vm,
-                    struct radeon_bo *bo)
+                    struct radeon_bo_va *bo_va)
  {
-       struct radeon_bo_va *bo_va;
        int r;
  
-       bo_va = radeon_bo_va(bo, vm);
-       if (bo_va == NULL)
-               return 0;
-       /* wait for va use to end */
-       while (bo_va->fence) {
-               r = radeon_fence_wait(bo_va->fence, false);
-               if (r) {
-                       DRM_ERROR("error while waiting for fence: %d\n", r);
-               }
-               if (r == -EDEADLK) {
-                       r = radeon_gpu_reset(rdev);
-                       if (!r)
-                               continue;
-               }
-               break;
-       }
-       radeon_fence_unref(&bo_va->fence);
        mutex_lock(&rdev->vm_manager.lock);
-       mutex_lock(&vm->mutex);
-       radeon_vm_bo_update_pte(rdev, vm, bo, NULL);
+       mutex_lock(&bo_va->vm->mutex);
+       r = radeon_vm_bo_update_pte(rdev, bo_va->vm, bo_va->bo, NULL);
        mutex_unlock(&rdev->vm_manager.lock);
        list_del(&bo_va->vm_list);
-       mutex_unlock(&vm->mutex);
+       mutex_unlock(&bo_va->vm->mutex);
        list_del(&bo_va->bo_list);
  
        kfree(bo_va);
-       return 0;
+       return r;
  }
  
  /**
@@@ -925,27 -1063,23 +1063,23 @@@ void radeon_vm_bo_invalidate(struct rad
   */
  int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
  {
+       struct radeon_bo_va *bo_va;
        int r;
  
-       vm->id = -1;
+       vm->id = 0;
        vm->fence = NULL;
+       vm->last_pfn = 0;
        mutex_init(&vm->mutex);
        INIT_LIST_HEAD(&vm->list);
        INIT_LIST_HEAD(&vm->va);
-       /* SI requires equal sized PTs for all VMs, so always set
-        * last_pfn to max_pfn.  cayman allows variable sized
-        * pts so we can grow then as needed.  Once we switch
-        * to two level pts we can unify this again.
-        */
-       if (rdev->family >= CHIP_TAHITI)
-               vm->last_pfn = rdev->vm_manager.max_pfn;
-       else
-               vm->last_pfn = 0;
        /* map the ib pool buffer at 0 in virtual address space, set
         * read only
         */
-       r = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo, 0,
-                            RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED);
+       bo_va = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo);
+       r = radeon_vm_bo_set_addr(rdev, bo_va, RADEON_VA_IB_OFFSET,
+                                 RADEON_VM_PAGE_READABLE |
+                                 RADEON_VM_PAGE_SNOOPED);
        return r;
  }
  
@@@ -965,7 -1099,7 +1099,7 @@@ void radeon_vm_fini(struct radeon_devic
  
        mutex_lock(&rdev->vm_manager.lock);
        mutex_lock(&vm->mutex);
-       radeon_vm_unbind_locked(rdev, vm);
+       radeon_vm_free_pt(rdev, vm);
        mutex_unlock(&rdev->vm_manager.lock);
  
        /* remove all bo at this point non are busy any more because unbind
         */
        r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);
        if (!r) {
-               bo_va = radeon_bo_va(rdev->ring_tmp_bo.bo, vm);
+               bo_va = radeon_vm_bo_find(vm, rdev->ring_tmp_bo.bo);
                list_del_init(&bo_va->bo_list);
                list_del_init(&bo_va->vm_list);
-               radeon_fence_unref(&bo_va->fence);
                radeon_bo_unreserve(rdev->ring_tmp_bo.bo);
                kfree(bo_va);
        }
                r = radeon_bo_reserve(bo_va->bo, false);
                if (!r) {
                        list_del_init(&bo_va->bo_list);
-                       radeon_fence_unref(&bo_va->fence);
                        radeon_bo_unreserve(bo_va->bo);
                        kfree(bo_va);
                }
        }
+       radeon_fence_unref(&vm->fence);
+       radeon_fence_unref(&vm->last_flush);
        mutex_unlock(&vm->mutex);
  }
@@@ -25,8 -25,9 +25,8 @@@
   *          Alex Deucher
   *          Jerome Glisse
   */
 -#include "drmP.h"
 -#include "drm.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  
  int radeon_gem_object_init(struct drm_gem_object *obj)
@@@ -123,6 -124,30 +123,30 @@@ void radeon_gem_fini(struct radeon_devi
   */
  int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv)
  {
+       struct radeon_bo *rbo = gem_to_radeon_bo(obj);
+       struct radeon_device *rdev = rbo->rdev;
+       struct radeon_fpriv *fpriv = file_priv->driver_priv;
+       struct radeon_vm *vm = &fpriv->vm;
+       struct radeon_bo_va *bo_va;
+       int r;
+       if (rdev->family < CHIP_CAYMAN) {
+               return 0;
+       }
+       r = radeon_bo_reserve(rbo, false);
+       if (r) {
+               return r;
+       }
+       bo_va = radeon_vm_bo_find(vm, rbo);
+       if (!bo_va) {
+               bo_va = radeon_vm_bo_add(rdev, vm, rbo);
+       } else {
+               ++bo_va->ref_count;
+       }
+       radeon_bo_unreserve(rbo);
        return 0;
  }
  
@@@ -133,16 -158,25 +157,25 @@@ void radeon_gem_object_close(struct drm
        struct radeon_device *rdev = rbo->rdev;
        struct radeon_fpriv *fpriv = file_priv->driver_priv;
        struct radeon_vm *vm = &fpriv->vm;
+       struct radeon_bo_va *bo_va;
+       int r;
  
        if (rdev->family < CHIP_CAYMAN) {
                return;
        }
  
-       if (radeon_bo_reserve(rbo, false)) {
-               dev_err(rdev->dev, "leaking bo va because we fail to reserve bo\n");
+       r = radeon_bo_reserve(rbo, true);
+       if (r) {
+               dev_err(rdev->dev, "leaking bo va because "
+                       "we fail to reserve bo (%d)\n", r);
                return;
        }
-       radeon_vm_bo_rmv(rdev, vm, rbo);
+       bo_va = radeon_vm_bo_find(vm, rbo);
+       if (bo_va) {
+               if (--bo_va->ref_count == 0) {
+                       radeon_vm_bo_rmv(rdev, bo_va);
+               }
+       }
        radeon_bo_unreserve(rbo);
  }
  
@@@ -458,19 -492,24 +491,24 @@@ int radeon_gem_va_ioctl(struct drm_devi
                drm_gem_object_unreference_unlocked(gobj);
                return r;
        }
+       bo_va = radeon_vm_bo_find(&fpriv->vm, rbo);
+       if (!bo_va) {
+               args->operation = RADEON_VA_RESULT_ERROR;
+               drm_gem_object_unreference_unlocked(gobj);
+               return -ENOENT;
+       }
        switch (args->operation) {
        case RADEON_VA_MAP:
-               bo_va = radeon_bo_va(rbo, &fpriv->vm);
-               if (bo_va) {
+               if (bo_va->soffset) {
                        args->operation = RADEON_VA_RESULT_VA_EXIST;
                        args->offset = bo_va->soffset;
                        goto out;
                }
-               r = radeon_vm_bo_add(rdev, &fpriv->vm, rbo,
-                                    args->offset, args->flags);
+               r = radeon_vm_bo_set_addr(rdev, bo_va, args->offset, args->flags);
                break;
        case RADEON_VA_UNMAP:
-               r = radeon_vm_bo_rmv(rdev, &fpriv->vm, rbo);
+               r = radeon_vm_bo_set_addr(rdev, bo_va, 0, 0);
                break;
        default:
                break;
@@@ -29,8 -29,9 +29,8 @@@
   */
  #include <linux/compat.h>
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon_drv.h"
  
  typedef struct drm_radeon_init32 {
@@@ -368,7 -369,7 +368,7 @@@ static int compat_radeon_cp_setparam(st
  #define compat_radeon_cp_setparam NULL
  #endif /* X86_64 || IA64 */
  
- drm_ioctl_compat_t *radeon_compat_ioctls[] = {
static drm_ioctl_compat_t *radeon_compat_ioctls[] = {
        [DRM_RADEON_CP_INIT] = compat_radeon_cp_init,
        [DRM_RADEON_CLEAR] = compat_radeon_cp_clear,
        [DRM_RADEON_STIPPLE] = compat_radeon_cp_stipple,
@@@ -25,9 -25,9 +25,9 @@@
   *          Alex Deucher
   *          Jerome Glisse
   */
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/radeon_drm.h>
  #include "radeon_reg.h"
  #include "radeon.h"
  #include "atom.h"
@@@ -99,7 -99,6 +99,6 @@@ void radeon_driver_irq_preinstall_kms(s
        /* Disable *all* interrupts */
        for (i = 0; i < RADEON_NUM_RINGS; i++)
                atomic_set(&rdev->irq.ring_int[i], 0);
-       rdev->irq.gui_idle = false;
        for (i = 0; i < RADEON_MAX_HPD_PINS; i++)
                rdev->irq.hpd[i] = false;
        for (i = 0; i < RADEON_MAX_CRTCS; i++) {
@@@ -147,7 -146,6 +146,6 @@@ void radeon_driver_irq_uninstall_kms(st
        /* Disable *all* interrupts */
        for (i = 0; i < RADEON_NUM_RINGS; i++)
                atomic_set(&rdev->irq.ring_int[i], 0);
-       rdev->irq.gui_idle = false;
        for (i = 0; i < RADEON_MAX_HPD_PINS; i++)
                rdev->irq.hpd[i] = false;
        for (i = 0; i < RADEON_MAX_CRTCS; i++) {
@@@ -204,6 -202,16 +202,16 @@@ static bool radeon_msi_ok(struct radeon
            (rdev->pdev->subsystem_device == 0x01fd))
                return true;
  
+       /* Gateway RS690 only seems to work with MSIs. */
+       if ((rdev->pdev->device == 0x791f) &&
+           (rdev->pdev->subsystem_vendor == 0x107b) &&
+           (rdev->pdev->subsystem_device == 0x0185))
+               return true;
+       /* try and enable MSIs by default on all RS690s */
+       if (rdev->family == CHIP_RS690)
+               return true;
        /* RV515 seems to have MSI issues where it loses
         * MSI rearms occasionally. This leads to lockups and freezes.
         * disable it by default.
@@@ -277,7 -285,7 +285,7 @@@ void radeon_irq_kms_fini(struct radeon_
                if (rdev->msi_enabled)
                        pci_disable_msi(rdev->pdev);
        }
 -      flush_work_sync(&rdev->hotplug_work);
 +      flush_work(&rdev->hotplug_work);
  }
  
  /**
@@@ -457,34 -465,3 +465,3 @@@ void radeon_irq_kms_disable_hpd(struct 
        spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
  }
  
- /**
-  * radeon_irq_kms_wait_gui_idle - waits for drawing engine to be idle
-  *
-  * @rdev: radeon device pointer
-  *
-  * Enabled the GUI idle interrupt and waits for it to fire (r6xx+).
-  * This is currently used to make sure the 3D engine is idle for power
-  * management, but should be replaces with proper fence waits.
-  * GUI idle interrupts don't work very well on pre-r6xx hw and it also
-  * does not take into account other aspects of the chip that may be busy.
-  * DO NOT USE GOING FORWARD.
-  */
- int radeon_irq_kms_wait_gui_idle(struct radeon_device *rdev)
- {
-       unsigned long irqflags;
-       int r;
-       spin_lock_irqsave(&rdev->irq.lock, irqflags);
-       rdev->irq.gui_idle = true;
-       radeon_irq_set(rdev);
-       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
-       r = wait_event_timeout(rdev->irq.idle_queue, radeon_gui_idle(rdev),
-                              msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT));
-       spin_lock_irqsave(&rdev->irq.lock, irqflags);
-       rdev->irq.gui_idle = false;
-       radeon_irq_set(rdev);
-       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
-       return r;
- }
   *          Alex Deucher
   *          Jerome Glisse
   */
 -#include "drmP.h"
 -#include "drm_sarea.h"
 +#include <drm/drmP.h>
  #include "radeon.h"
 -#include "radeon_drm.h"
 +#include <drm/radeon_drm.h>
  #include "radeon_asic.h"
  
  #include <linux/vga_switcheroo.h>
@@@ -50,6 -51,7 +50,7 @@@ int radeon_driver_unload_kms(struct drm
  
        if (rdev == NULL)
                return 0;
+       radeon_acpi_fini(rdev);
        radeon_modeset_fini(rdev);
        radeon_device_fini(rdev);
        kfree(rdev);
@@@ -102,11 -104,6 +103,6 @@@ int radeon_driver_load_kms(struct drm_d
                goto out;
        }
  
-       /* Call ACPI methods */
-       acpi_status = radeon_acpi_init(rdev);
-       if (acpi_status)
-               dev_dbg(&dev->pdev->dev, "Error during ACPI methods call\n");
        /* Again modeset_init should fail only on fatal error
         * otherwise it should provide enough functionalities
         * for shadowfb to run
        r = radeon_modeset_init(rdev);
        if (r)
                dev_err(&dev->pdev->dev, "Fatal error during modeset init\n");
+       /* Call ACPI methods: require modeset init
+        * but failure is not fatal
+        */
+       if (!r) {
+               acpi_status = radeon_acpi_init(rdev);
+               if (acpi_status)
+               dev_dbg(&dev->pdev->dev,
+                               "Error during ACPI methods call\n");
+       }
  out:
        if (r)
                radeon_driver_unload_kms(dev);
@@@ -23,9 -23,9 +23,9 @@@
   * Authors: Dave Airlie
   *          Alex Deucher
   */
 -#include "drmP.h"
 -#include "drm_crtc_helper.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  #include "atom.h"
  #include <linux/backlight.h>
@@@ -271,13 -271,6 +271,6 @@@ static const struct drm_encoder_helper_
  
  #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
  
- #define MAX_RADEON_LEVEL 0xFF
- struct radeon_backlight_privdata {
-       struct radeon_encoder *encoder;
-       uint8_t negative;
- };
  static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd)
  {
        struct radeon_backlight_privdata *pdata = bl_get_data(bd);
        /* Convert brightness to hardware level */
        if (bd->props.brightness < 0)
                level = 0;
-       else if (bd->props.brightness > MAX_RADEON_LEVEL)
-               level = MAX_RADEON_LEVEL;
+       else if (bd->props.brightness > RADEON_MAX_BL_LEVEL)
+               level = RADEON_MAX_BL_LEVEL;
        else
                level = bd->props.brightness;
  
        if (pdata->negative)
-               level = MAX_RADEON_LEVEL - level;
+               level = RADEON_MAX_BL_LEVEL - level;
  
        return level;
  }
  
- static int radeon_legacy_backlight_update_status(struct backlight_device *bd)
+ u8
+ radeon_legacy_get_backlight_level(struct radeon_encoder *radeon_encoder)
+ {
+       struct drm_device *dev = radeon_encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       u8 backlight_level;
+       backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
+                          RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+       return backlight_level;
+ }
+ void
+ radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level)
  {
-       struct radeon_backlight_privdata *pdata = bl_get_data(bd);
-       struct radeon_encoder *radeon_encoder = pdata->encoder;
        struct drm_device *dev = radeon_encoder->base.dev;
        struct radeon_device *rdev = dev->dev_private;
        int dpms_mode = DRM_MODE_DPMS_ON;
        if (radeon_encoder->enc_priv) {
                if (rdev->is_atom_bios) {
                        struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
-                       dpms_mode = lvds->dpms_mode;
-                       lvds->backlight_level = radeon_legacy_lvds_level(bd);
+                       if (lvds->backlight_level > 0)
+                               dpms_mode = lvds->dpms_mode;
+                       else
+                               dpms_mode = DRM_MODE_DPMS_OFF;
+                       lvds->backlight_level = level;
                } else {
                        struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
-                       dpms_mode = lvds->dpms_mode;
-                       lvds->backlight_level = radeon_legacy_lvds_level(bd);
+                       if (lvds->backlight_level > 0)
+                               dpms_mode = lvds->dpms_mode;
+                       else
+                               dpms_mode = DRM_MODE_DPMS_OFF;
+                       lvds->backlight_level = level;
                }
        }
  
-       if (bd->props.brightness > 0)
-               radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode);
-       else
-               radeon_legacy_lvds_update(&radeon_encoder->base, DRM_MODE_DPMS_OFF);
+       radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode);
+ }
+ static int radeon_legacy_backlight_update_status(struct backlight_device *bd)
+ {
+       struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+       struct radeon_encoder *radeon_encoder = pdata->encoder;
+       radeon_legacy_set_backlight_level(radeon_encoder,
+                                         radeon_legacy_lvds_level(bd));
  
        return 0;
  }
@@@ -336,7 -353,7 +353,7 @@@ static int radeon_legacy_backlight_get_
        backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
                           RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
  
-       return pdata->negative ? MAX_RADEON_LEVEL - backlight_level : backlight_level;
+       return pdata->negative ? RADEON_MAX_BL_LEVEL - backlight_level : backlight_level;
  }
  
  static const struct backlight_ops radeon_backlight_ops = {
@@@ -370,7 -387,7 +387,7 @@@ void radeon_legacy_backlight_init(struc
        }
  
        memset(&props, 0, sizeof(props));
-       props.max_brightness = MAX_RADEON_LEVEL;
+       props.max_brightness = RADEON_MAX_BL_LEVEL;
        props.type = BACKLIGHT_RAW;
        bd = backlight_device_register("radeon_bl", &drm_connector->kdev,
                                       pdata, &radeon_backlight_ops, &props);
@@@ -449,7 -466,7 +466,7 @@@ static void radeon_legacy_backlight_exi
        }
  
        if (bd) {
-               struct radeon_legacy_backlight_privdata *pdata;
+               struct radeon_backlight_privdata *pdata;
  
                pdata = bl_get_data(bd);
                backlight_device_unregister(bd);
  #ifndef RADEON_MODE_H
  #define RADEON_MODE_H
  
 -#include <drm_crtc.h>
 -#include <drm_mode.h>
 -#include <drm_edid.h>
 -#include <drm_dp_helper.h>
 -#include <drm_fixed.h>
 -#include <drm_crtc_helper.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_edid.h>
 +#include <drm/drm_dp_helper.h>
 +#include <drm/drm_fixed.h>
 +#include <drm/drm_crtc_helper.h>
  #include <linux/i2c.h>
  #include <linux/i2c-algo-bit.h>
  
@@@ -251,8 -252,23 +251,23 @@@ struct radeon_mode_info 
  
        /* pointer to fbdev info structure */
        struct radeon_fbdev *rfbdev;
+       /* firmware flags */
+       u16 firmware_flags;
+       /* pointer to backlight encoder */
+       struct radeon_encoder *bl_encoder;
  };
  
+ #define RADEON_MAX_BL_LEVEL 0xFF
+ #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
+ struct radeon_backlight_privdata {
+       struct radeon_encoder *encoder;
+       uint8_t negative;
+ };
+ #endif
  #define MAX_H_CODE_TIMING_LEN 32
  #define MAX_V_CODE_TIMING_LEN 32
  
@@@ -268,6 -284,18 +283,18 @@@ struct radeon_tv_regs 
        uint16_t v_code_timing[MAX_V_CODE_TIMING_LEN];
  };
  
+ struct radeon_atom_ss {
+       uint16_t percentage;
+       uint8_t type;
+       uint16_t step;
+       uint8_t delay;
+       uint8_t range;
+       uint8_t refdiv;
+       /* asic_ss */
+       uint16_t rate;
+       uint16_t amount;
+ };
  struct radeon_crtc {
        struct drm_crtc base;
        int crtc_id;
        /* page flipping */
        struct radeon_unpin_work *unpin_work;
        int deferred_flip_completion;
+       /* pll sharing */
+       struct radeon_atom_ss ss;
+       bool ss_enabled;
+       u32 adjusted_clock;
+       int bpc;
+       u32 pll_reference_div;
+       u32 pll_post_div;
+       u32 pll_flags;
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
  };
  
  struct radeon_encoder_primary_dac {
@@@ -345,18 -383,6 +382,6 @@@ struct radeon_encoder_ext_tmds 
  };
  
  /* spread spectrum */
- struct radeon_atom_ss {
-       uint16_t percentage;
-       uint8_t type;
-       uint16_t step;
-       uint8_t delay;
-       uint8_t range;
-       uint8_t refdiv;
-       /* asic_ss */
-       uint16_t rate;
-       uint16_t amount;
- };
  struct radeon_encoder_atom_dig {
        bool linkb;
        /* atom dig */
@@@ -32,7 -32,7 +32,7 @@@
  #include <linux/list.h>
  #include <linux/slab.h>
  #include <drm/drmP.h>
 -#include "radeon_drm.h"
 +#include <drm/radeon_drm.h>
  #include "radeon.h"
  #include "radeon_trace.h"
  
@@@ -52,7 -52,7 +52,7 @@@ void radeon_bo_clear_va(struct radeon_b
  
        list_for_each_entry_safe(bo_va, tmp, &bo->va, bo_list) {
                /* remove from all vm address space */
-               radeon_vm_bo_rmv(bo->rdev, bo_va->vm, bo);
+               radeon_vm_bo_rmv(bo->rdev, bo_va);
        }
  }
  
@@@ -627,18 -627,17 +627,17 @@@ int radeon_bo_wait(struct radeon_bo *bo
  /**
   * radeon_bo_reserve - reserve bo
   * @bo:               bo structure
-  * @no_wait:          don't sleep while trying to reserve (return -EBUSY)
+  * @no_intr:  don't return -ERESTARTSYS on pending signal
   *
   * Returns:
-  * -EBUSY: buffer is busy and @no_wait is true
   * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by
   * a signal. Release all buffer reservations and return to user-space.
   */
- int radeon_bo_reserve(struct radeon_bo *bo, bool no_wait)
+ int radeon_bo_reserve(struct radeon_bo *bo, bool no_intr)
  {
        int r;
  
-       r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0);
+       r = ttm_bo_reserve(&bo->tbo, !no_intr, false, false, 0);
        if (unlikely(r != 0)) {
                if (r != -ERESTARTSYS)
                        dev_err(bo->rdev->dev, "%p reserve failed\n", bo);
        }
        return 0;
  }
- /* object have to be reserved */
- struct radeon_bo_va *radeon_bo_va(struct radeon_bo *rbo, struct radeon_vm *vm)
- {
-       struct radeon_bo_va *bo_va;
-       list_for_each_entry(bo_va, &rbo->va, bo_list) {
-               if (bo_va->vm == vm) {
-                       return bo_va;
-               }
-       }
-       return NULL;
- }
   * Authors: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>
   *          Alex Deucher <alexdeucher@gmail.com>
   */
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "radeon.h"
  #include "avivod.h"
  #include "atom.h"
- #ifdef CONFIG_ACPI
- #include <linux/acpi.h>
- #endif
  #include <linux/power_supply.h>
  #include <linux/hwmon.h>
  #include <linux/hwmon-sysfs.h>
@@@ -36,7 -33,7 +33,7 @@@
  #define RADEON_WAIT_VBLANK_TIMEOUT 200
  
  static const char *radeon_pm_state_type_name[5] = {
-       "Default",
+       "",
        "Powersave",
        "Battery",
        "Balanced",
@@@ -50,8 -47,6 +47,6 @@@ static bool radeon_pm_debug_check_in_vb
  static void radeon_pm_update_profile(struct radeon_device *rdev);
  static void radeon_pm_set_clocks(struct radeon_device *rdev);
  
- #define ACPI_AC_CLASS           "ac_adapter"
  int radeon_pm_get_type_index(struct radeon_device *rdev,
                             enum radeon_pm_state_type ps_type,
                             int instance)
        return rdev->pm.default_power_state_index;
  }
  
- #ifdef CONFIG_ACPI
- static int radeon_acpi_event(struct notifier_block *nb,
-                            unsigned long val,
-                            void *data)
+ void radeon_pm_acpi_event_handler(struct radeon_device *rdev)
  {
-       struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb);
-       struct acpi_bus_event *entry = (struct acpi_bus_event *)data;
-       if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) {
-               if (power_supply_is_system_supplied() > 0)
-                       DRM_DEBUG_DRIVER("pm: AC\n");
-               else
-                       DRM_DEBUG_DRIVER("pm: DC\n");
-               if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
-                       if (rdev->pm.profile == PM_PROFILE_AUTO) {
-                               mutex_lock(&rdev->pm.mutex);
-                               radeon_pm_update_profile(rdev);
-                               radeon_pm_set_clocks(rdev);
-                               mutex_unlock(&rdev->pm.mutex);
-                       }
+       if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
+               if (rdev->pm.profile == PM_PROFILE_AUTO) {
+                       mutex_lock(&rdev->pm.mutex);
+                       radeon_pm_update_profile(rdev);
+                       radeon_pm_set_clocks(rdev);
+                       mutex_unlock(&rdev->pm.mutex);
                }
        }
-       return NOTIFY_OK;
  }
- #endif
  
  static void radeon_pm_update_profile(struct radeon_device *rdev)
  {
@@@ -188,8 -167,21 +167,21 @@@ static void radeon_set_power_state(stru
                if (sclk > rdev->pm.default_sclk)
                        sclk = rdev->pm.default_sclk;
  
-               mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
-                       clock_info[rdev->pm.requested_clock_mode_index].mclk;
+               /* starting with BTC, there is one state that is used for both
+                * MH and SH.  Difference is that we always use the high clock index for
+                * mclk.
+                */
+               if ((rdev->pm.pm_method == PM_METHOD_PROFILE) &&
+                   (rdev->family >= CHIP_BARTS) &&
+                   rdev->pm.active_crtc_count &&
+                   ((rdev->pm.profile_index == PM_PROFILE_MID_MH_IDX) ||
+                    (rdev->pm.profile_index == PM_PROFILE_LOW_MH_IDX)))
+                       mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
+                               clock_info[rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx].mclk;
+               else
+                       mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
+                               clock_info[rdev->pm.requested_clock_mode_index].mclk;
                if (mclk > rdev->pm.default_mclk)
                        mclk = rdev->pm.default_mclk;
  
@@@ -253,18 -245,13 +245,13 @@@ static void radeon_pm_set_clocks(struc
        down_write(&rdev->pm.mclk_lock);
        mutex_lock(&rdev->ring_lock);
  
-       /* gui idle int has issues on older chips it seems */
-       if (rdev->family >= CHIP_R600) {
-               if (rdev->irq.installed) {
-                       /* wait for GPU to become idle */
-                       radeon_irq_kms_wait_gui_idle(rdev);
-               }
-       } else {
-               struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
-               if (ring->ready) {
-                       radeon_fence_wait_empty_locked(rdev, RADEON_RING_TYPE_GFX_INDEX);
-               }
+       /* wait for the rings to drain */
+       for (i = 0; i < RADEON_NUM_RINGS; i++) {
+               struct radeon_ring *ring = &rdev->ring[i];
+               if (ring->ready)
+                       radeon_fence_wait_empty_locked(rdev, i);
        }
        radeon_unmap_vram_bos(rdev);
  
        if (rdev->irq.installed) {
@@@ -320,17 -307,15 +307,15 @@@ static void radeon_pm_print_states(stru
                for (j = 0; j < power_state->num_clock_modes; j++) {
                        clock_info = &(power_state->clock_info[j]);
                        if (rdev->flags & RADEON_IS_IGP)
-                               DRM_DEBUG_DRIVER("\t\t%d e: %d%s\n",
-                                       j,
-                                       clock_info->sclk * 10,
-                                       clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : "");
+                               DRM_DEBUG_DRIVER("\t\t%d e: %d\n",
+                                                j,
+                                                clock_info->sclk * 10);
                        else
-                               DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d%s\n",
-                                       j,
-                                       clock_info->sclk * 10,
-                                       clock_info->mclk * 10,
-                                       clock_info->voltage.voltage,
-                                       clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : "");
+                               DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d\n",
+                                                j,
+                                                clock_info->sclk * 10,
+                                                clock_info->mclk * 10,
+                                                clock_info->voltage.voltage);
                }
        }
  }
@@@ -547,7 -532,9 +532,9 @@@ void radeon_pm_suspend(struct radeon_de
  void radeon_pm_resume(struct radeon_device *rdev)
  {
        /* set up the default clocks if the MC ucode is loaded */
-       if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) {
+       if ((rdev->family >= CHIP_BARTS) &&
+           (rdev->family <= CHIP_CAYMAN) &&
+           rdev->mc_fw) {
                if (rdev->pm.default_vddc)
                        radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
                                                SET_VOLTAGE_TYPE_ASIC_VDDC);
@@@ -602,7 -589,9 +589,9 @@@ int radeon_pm_init(struct radeon_devic
                radeon_pm_print_states(rdev);
                radeon_pm_init_profile(rdev);
                /* set up the default clocks if the MC ucode is loaded */
-               if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) {
+               if ((rdev->family >= CHIP_BARTS) &&
+                   (rdev->family <= CHIP_CAYMAN) &&
+                   rdev->mc_fw) {
                        if (rdev->pm.default_vddc)
                                radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
                                                        SET_VOLTAGE_TYPE_ASIC_VDDC);
                if (ret)
                        DRM_ERROR("failed to create device file for power method\n");
  
- #ifdef CONFIG_ACPI
-               rdev->acpi_nb.notifier_call = radeon_acpi_event;
-               register_acpi_notifier(&rdev->acpi_nb);
- #endif
                if (radeon_debugfs_pm_init(rdev)) {
                        DRM_ERROR("Failed to register debugfs file for PM!\n");
                }
@@@ -666,9 -651,6 +651,6 @@@ void radeon_pm_fini(struct radeon_devic
  
                device_remove_file(rdev->dev, &dev_attr_power_profile);
                device_remove_file(rdev->dev, &dev_attr_power_method);
- #ifdef CONFIG_ACPI
-               unregister_acpi_notifier(&rdev->acpi_nb);
- #endif
        }
  
        if (rdev->pm.power_state)
@@@ -28,8 -28,8 +28,8 @@@
   */
  #include <linux/seq_file.h>
  #include <linux/slab.h>
 -#include "drmP.h"
 -#include "radeon_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/radeon_drm.h>
  #include "radeon_reg.h"
  #include "radeon.h"
  #include "atom.h"
@@@ -43,7 -43,7 +43,7 @@@
   * produce command buffers which are send to the kernel and
   * put in IBs for execution by the requested ring.
   */
- int radeon_debugfs_sa_init(struct radeon_device *rdev);
static int radeon_debugfs_sa_init(struct radeon_device *rdev);
  
  /**
   * radeon_ib_get - request an IB (Indirect Buffer)
@@@ -58,7 -58,8 +58,8 @@@
   * Returns 0 on success, error on failure.
   */
  int radeon_ib_get(struct radeon_device *rdev, int ring,
-                 struct radeon_ib *ib, unsigned size)
+                 struct radeon_ib *ib, struct radeon_vm *vm,
+                 unsigned size)
  {
        int i, r;
  
        ib->ring = ring;
        ib->fence = NULL;
        ib->ptr = radeon_sa_bo_cpu_addr(ib->sa_bo);
-       ib->gpu_addr = radeon_sa_bo_gpu_addr(ib->sa_bo);
-       ib->vm_id = 0;
+       ib->vm = vm;
+       if (vm) {
+               /* ib pool is bound at RADEON_VA_IB_OFFSET in virtual address
+                * space and soffset is the offset inside the pool bo
+                */
+               ib->gpu_addr = ib->sa_bo->soffset + RADEON_VA_IB_OFFSET;
+       } else {
+               ib->gpu_addr = radeon_sa_bo_gpu_addr(ib->sa_bo);
+       }
        ib->is_const_ib = false;
        for (i = 0; i < RADEON_NUM_RINGS; ++i)
                ib->sync_to[i] = NULL;
@@@ -152,6 -160,10 +160,10 @@@ int radeon_ib_schedule(struct radeon_de
        if (!need_sync) {
                radeon_semaphore_free(rdev, &ib->semaphore, NULL);
        }
+       /* if we can't remember our last VM flush then flush now! */
+       if (ib->vm && !ib->vm->last_flush) {
+               radeon_ring_vm_flush(rdev, ib->ring, ib->vm);
+       }
        if (const_ib) {
                radeon_ring_ib_execute(rdev, const_ib->ring, const_ib);
                radeon_semaphore_free(rdev, &const_ib->semaphore, NULL);
        if (const_ib) {
                const_ib->fence = radeon_fence_ref(ib->fence);
        }
+       /* we just flushed the VM, remember that */
+       if (ib->vm && !ib->vm->last_flush) {
+               ib->vm->last_flush = radeon_fence_ref(ib->fence);
+       }
        radeon_ring_unlock_commit(rdev, ring);
        return 0;
  }
@@@ -275,7 -291,7 +291,7 @@@ int radeon_ib_ring_tests(struct radeon_
   * wptr.  The GPU then starts fetching commands and executes
   * them until the pointers are equal again.
   */
- int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring);
static int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring);
  
  /**
   * radeon_ring_write - write a value to the ring
@@@ -803,7 -819,7 +819,7 @@@ static struct drm_info_list radeon_debu
  
  #endif
  
- int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring)
static int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring)
  {
  #if defined(CONFIG_DEBUG_FS)
        unsigned i;
        return 0;
  }
  
- int radeon_debugfs_sa_init(struct radeon_device *rdev)
static int radeon_debugfs_sa_init(struct radeon_device *rdev)
  {
  #if defined(CONFIG_DEBUG_FS)
        return radeon_debugfs_add_files(rdev, radeon_debugfs_sa_list, 1);
@@@ -41,7 -41,8 +41,7 @@@
   * If we are asked to block we wait on all the oldest fence of all
   * rings. We just wait for any of those fence to complete.
   */
 -#include "drmP.h"
 -#include "drm.h"
 +#include <drm/drmP.h>
  #include "radeon.h"
  
  static void radeon_sa_bo_remove_locked(struct radeon_sa_bo *sa_bo);
@@@ -315,7 -316,7 +315,7 @@@ int radeon_sa_bo_new(struct radeon_devi
  {
        struct radeon_fence *fences[RADEON_NUM_RINGS];
        unsigned tries[RADEON_NUM_RINGS];
-       int i, r = -ENOMEM;
+       int i, r;
  
        BUG_ON(align > RADEON_GPU_PAGE_SIZE);
        BUG_ON(size > sa_manager->size);
        INIT_LIST_HEAD(&(*sa_bo)->flist);
  
        spin_lock(&sa_manager->wq.lock);
-       while(1) {
+       do {
                for (i = 0; i < RADEON_NUM_RINGS; ++i) {
                        fences[i] = NULL;
                        tries[i] = 0;
                        /* see if we can skip over some allocations */
                } while (radeon_sa_bo_next_hole(sa_manager, fences, tries));
  
-               if (!block) {
-                       break;
-               }
                spin_unlock(&sa_manager->wq.lock);
                r = radeon_fence_wait_any(rdev, fences, false);
                spin_lock(&sa_manager->wq.lock);
                /* if we have nothing to wait for block */
-               if (r == -ENOENT) {
+               if (r == -ENOENT && block) {
                        r = wait_event_interruptible_locked(
                                sa_manager->wq, 
                                radeon_sa_event(sa_manager, size, align)
                        );
+               } else if (r == -ENOENT) {
+                       r = -ENOMEM;
                }
-               if (r) {
-                       goto out_err;
-               }
-       };
  
- out_err:
+       } while (!r);
        spin_unlock(&sa_manager->wq.lock);
        kfree(*sa_bo);
        *sa_bo = NULL;
@@@ -35,7 -35,7 +35,7 @@@
   * close to the one of the R600 family (R600 likely being an evolution
   * of the RS600 GART block).
   */
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "radeon.h"
  #include "radeon_asic.h"
  #include "atom.h"
  
  #include "rs600_reg_safe.h"
  
- void rs600_gpu_init(struct radeon_device *rdev);
static void rs600_gpu_init(struct radeon_device *rdev);
  int rs600_mc_wait_for_idle(struct radeon_device *rdev);
  
+ static const u32 crtc_offsets[2] =
+ {
+       0,
+       AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL
+ };
  void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc)
  {
-       struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
        int i;
  
-       if (RREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset) & AVIVO_CRTC_EN) {
+       if (crtc >= rdev->num_crtc)
+               return;
+       if (RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[crtc]) & AVIVO_CRTC_EN) {
                for (i = 0; i < rdev->usec_timeout; i++) {
-                       if (!(RREG32(AVIVO_D1CRTC_STATUS + radeon_crtc->crtc_offset) & AVIVO_D1CRTC_V_BLANK))
+                       if (!(RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK))
                                break;
                        udelay(1);
                }
                for (i = 0; i < rdev->usec_timeout; i++) {
-                       if (RREG32(AVIVO_D1CRTC_STATUS + radeon_crtc->crtc_offset) & AVIVO_D1CRTC_V_BLANK)
+                       if (RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK)
                                break;
                        udelay(1);
                }
@@@ -424,7 -432,7 +432,7 @@@ void rs600_gart_tlb_flush(struct radeon
        tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
  }
  
- int rs600_gart_init(struct radeon_device *rdev)
static int rs600_gart_init(struct radeon_device *rdev)
  {
        int r;
  
@@@ -506,7 -514,7 +514,7 @@@ static int rs600_gart_enable(struct rad
        return 0;
  }
  
- void rs600_gart_disable(struct radeon_device *rdev)
static void rs600_gart_disable(struct radeon_device *rdev)
  {
        u32 tmp;
  
        radeon_gart_table_vram_unpin(rdev);
  }
  
- void rs600_gart_fini(struct radeon_device *rdev)
static void rs600_gart_fini(struct radeon_device *rdev)
  {
        radeon_gart_fini(rdev);
        rs600_gart_disable(rdev);
@@@ -567,9 -575,6 +575,6 @@@ int rs600_irq_set(struct radeon_device 
        if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
                tmp |= S_000040_SW_INT_EN(1);
        }
-       if (rdev->irq.gui_idle) {
-               tmp |= S_000040_GUI_IDLE(1);
-       }
        if (rdev->irq.crtc_vblank_int[0] ||
            atomic_read(&rdev->irq.pflip[0])) {
                mode_int |= S_006540_D1MODE_VBLANK_INT_MASK(1);
@@@ -602,12 -607,6 +607,6 @@@ static inline u32 rs600_irq_ack(struct 
        uint32_t irq_mask = S_000044_SW_INT(1);
        u32 tmp;
  
-       /* the interrupt works, but the status bit is permanently asserted */
-       if (rdev->irq.gui_idle && radeon_gui_idle(rdev)) {
-               if (!rdev->irq.gui_idle_acked)
-                       irq_mask |= S_000044_GUI_IDLE_STAT(1);
-       }
        if (G_000044_DISPLAY_INT_STAT(irqs)) {
                rdev->irq.stat_regs.r500.disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS);
                if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
@@@ -667,9 -666,6 +666,6 @@@ int rs600_irq_process(struct radeon_dev
        bool queue_hotplug = false;
        bool queue_hdmi = false;
  
-       /* reset gui idle ack.  the status bit is broken */
-       rdev->irq.gui_idle_acked = false;
        status = rs600_irq_ack(rdev);
        if (!status &&
            !rdev->irq.stat_regs.r500.disp_int &&
                if (G_000044_SW_INT(status)) {
                        radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
                }
-               /* GUI idle */
-               if (G_000040_GUI_IDLE(status)) {
-                       rdev->irq.gui_idle_acked = true;
-                       wake_up(&rdev->irq.idle_queue);
-               }
                /* Vertical blank interrupts */
                if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
                        if (rdev->irq.crtc_vblank_int[0]) {
                }
                status = rs600_irq_ack(rdev);
        }
-       /* reset gui idle ack.  the status bit is broken */
-       rdev->irq.gui_idle_acked = false;
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
        if (queue_hdmi)
@@@ -764,7 -753,7 +753,7 @@@ int rs600_mc_wait_for_idle(struct radeo
        return -1;
  }
  
- void rs600_gpu_init(struct radeon_device *rdev)
static void rs600_gpu_init(struct radeon_device *rdev)
  {
        r420_pipes_init(rdev);
        /* Wait for mc idle */
                dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n");
  }
  
- void rs600_mc_init(struct radeon_device *rdev)
static void rs600_mc_init(struct radeon_device *rdev)
  {
        u64 base;
  
@@@ -834,7 -823,7 +823,7 @@@ void rs600_mc_wreg(struct radeon_devic
        WREG32(R_000074_MC_IND_DATA, v);
  }
  
- void rs600_debugfs(struct radeon_device *rdev)
static void rs600_debugfs(struct radeon_device *rdev)
  {
        if (r100_debugfs_rbbm_init(rdev))
                DRM_ERROR("Failed to register debugfs file for RBBM !\n");
@@@ -25,7 -25,7 +25,7 @@@
   *          Alex Deucher
   *          Jerome Glisse
   */
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "radeon.h"
  #include "radeon_asic.h"
  #include "atom.h"
@@@ -145,7 -145,7 +145,7 @@@ void rs690_pm_info(struct radeon_devic
        rdev->pm.sideport_bandwidth.full = dfixed_div(rdev->pm.sideport_bandwidth, tmp);
  }
  
- void rs690_mc_init(struct radeon_device *rdev)
static void rs690_mc_init(struct radeon_device *rdev)
  {
        u64 base;
  
@@@ -224,7 -224,7 +224,7 @@@ struct rs690_watermark 
        fixed20_12 sclk;
  };
  
- void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
                                  struct radeon_crtc *crtc,
                                  struct rs690_watermark *wm)
  {
@@@ -581,7 -581,7 +581,7 @@@ void rs690_mc_wreg(struct radeon_devic
        WREG32(R_000078_MC_INDEX, 0x7F);
  }
  
- void rs690_mc_program(struct radeon_device *rdev)
static void rs690_mc_program(struct radeon_device *rdev)
  {
        struct rv515_mc_save save;
  
@@@ -27,7 -27,7 +27,7 @@@
   */
  #include <linux/seq_file.h>
  #include <linux/slab.h>
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "rv515d.h"
  #include "radeon.h"
  #include "radeon_asic.h"
@@@ -35,9 -35,9 +35,9 @@@
  #include "rv515_reg_safe.h"
  
  /* This files gather functions specifics to: rv515 */
- int rv515_debugfs_pipes_info_init(struct radeon_device *rdev);
- int rv515_debugfs_ga_info_init(struct radeon_device *rdev);
- void rv515_gpu_init(struct radeon_device *rdev);
static int rv515_debugfs_pipes_info_init(struct radeon_device *rdev);
static int rv515_debugfs_ga_info_init(struct radeon_device *rdev);
static void rv515_gpu_init(struct radeon_device *rdev);
  int rv515_mc_wait_for_idle(struct radeon_device *rdev);
  
  void rv515_debugfs(struct radeon_device *rdev)
@@@ -143,7 -143,7 +143,7 @@@ void rv515_vga_render_disable(struct ra
                RREG32(R_000300_VGA_RENDER_CONTROL) & C_000300_VGA_VSTATUS_CNTL);
  }
  
- void rv515_gpu_init(struct radeon_device *rdev)
static void rv515_gpu_init(struct radeon_device *rdev)
  {
        unsigned pipe_select_current, gb_pipe_select, tmp;
  
@@@ -189,7 -189,7 +189,7 @@@ static void rv515_vram_get_type(struct 
        }
  }
  
- void rv515_mc_init(struct radeon_device *rdev)
static void rv515_mc_init(struct radeon_device *rdev)
  {
  
        rv515_vram_get_type(rdev);
@@@ -261,7 -261,7 +261,7 @@@ static struct drm_info_list rv515_ga_in
  };
  #endif
  
- int rv515_debugfs_pipes_info_init(struct radeon_device *rdev)
static int rv515_debugfs_pipes_info_init(struct radeon_device *rdev)
  {
  #if defined(CONFIG_DEBUG_FS)
        return radeon_debugfs_add_files(rdev, rv515_pipes_info_list, 1);
  #endif
  }
  
- int rv515_debugfs_ga_info_init(struct radeon_device *rdev)
static int rv515_debugfs_ga_info_init(struct radeon_device *rdev)
  {
  #if defined(CONFIG_DEBUG_FS)
        return radeon_debugfs_add_files(rdev, rv515_ga_info_list, 1);
@@@ -310,7 -310,7 +310,7 @@@ void rv515_mc_resume(struct radeon_devi
        WREG32(R_000300_VGA_RENDER_CONTROL, save->vga_render_control);
  }
  
- void rv515_mc_program(struct radeon_device *rdev)
static void rv515_mc_program(struct radeon_device *rdev)
  {
        struct rv515_mc_save save;
  
@@@ -787,7 -787,7 +787,7 @@@ struct rv515_watermark 
        fixed20_12 sclk;
  };
  
- void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
                                  struct radeon_crtc *crtc,
                                  struct rv515_watermark *wm)
  {
  #include <linux/firmware.h>
  #include <linux/platform_device.h>
  #include <linux/slab.h>
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "radeon.h"
  #include "radeon_asic.h"
 -#include "radeon_drm.h"
 +#include <drm/radeon_drm.h>
  #include "rv770d.h"
  #include "atom.h"
  #include "avivod.h"
@@@ -124,7 -124,7 +124,7 @@@ void rv770_pm_misc(struct radeon_devic
  /*
   * GART
   */
- int rv770_pcie_gart_enable(struct radeon_device *rdev)
static int rv770_pcie_gart_enable(struct radeon_device *rdev)
  {
        u32 tmp;
        int r, i;
        return 0;
  }
  
- void rv770_pcie_gart_disable(struct radeon_device *rdev)
static void rv770_pcie_gart_disable(struct radeon_device *rdev)
  {
        u32 tmp;
        int i;
        radeon_gart_table_vram_unpin(rdev);
  }
  
- void rv770_pcie_gart_fini(struct radeon_device *rdev)
static void rv770_pcie_gart_fini(struct radeon_device *rdev)
  {
        radeon_gart_fini(rdev);
        rv770_pcie_gart_disable(rdev);
  }
  
  
- void rv770_agp_enable(struct radeon_device *rdev)
static void rv770_agp_enable(struct radeon_device *rdev)
  {
        u32 tmp;
        int i;
@@@ -839,7 -839,7 +839,7 @@@ void r700_vram_gtt_location(struct rade
        }
  }
  
- int rv770_mc_init(struct radeon_device *rdev)
static int rv770_mc_init(struct radeon_device *rdev)
  {
        u32 tmp;
        int chansize, numchan;
  #include <linux/platform_device.h>
  #include <linux/slab.h>
  #include <linux/module.h>
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "radeon.h"
  #include "radeon_asic.h"
 -#include "radeon_drm.h"
 +#include <drm/radeon_drm.h>
  #include "sid.h"
  #include "atom.h"
  #include "si_blit_shaders.h"
@@@ -1806,13 -1806,14 +1806,14 @@@ void si_ring_ib_execute(struct radeon_d
  #endif
                          (ib->gpu_addr & 0xFFFFFFFC));
        radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
-       radeon_ring_write(ring, ib->length_dw | (ib->vm_id << 24));
+       radeon_ring_write(ring, ib->length_dw |
+                         (ib->vm ? (ib->vm->id << 24) : 0));
  
        if (!ib->is_const_ib) {
                /* flush read cache over gart for this vmid */
                radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
                radeon_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START) >> 2);
-               radeon_ring_write(ring, ib->vm_id);
+               radeon_ring_write(ring, ib->vm ? ib->vm->id : 0);
                radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
                radeon_ring_write(ring, PACKET3_TCL1_ACTION_ENA |
                                  PACKET3_TC_ACTION_ENA |
@@@ -2363,7 -2364,7 +2364,7 @@@ void si_pcie_gart_tlb_flush(struct rade
        WREG32(VM_INVALIDATE_REQUEST, 1);
  }
  
- int si_pcie_gart_enable(struct radeon_device *rdev)
static int si_pcie_gart_enable(struct radeon_device *rdev)
  {
        int r, i;
  
        WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR,
               (u32)(rdev->dummy_page.addr >> 12));
        WREG32(VM_CONTEXT1_CNTL2, 0);
-       WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) |
+       WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) |
                                RANGE_PROTECTION_FAULT_ENABLE_DEFAULT);
  
        si_pcie_gart_tlb_flush(rdev);
        return 0;
  }
  
- void si_pcie_gart_disable(struct radeon_device *rdev)
static void si_pcie_gart_disable(struct radeon_device *rdev)
  {
        /* Disable all tables */
        WREG32(VM_CONTEXT0_CNTL, 0);
        radeon_gart_table_vram_unpin(rdev);
  }
  
- void si_pcie_gart_fini(struct radeon_device *rdev)
static void si_pcie_gart_fini(struct radeon_device *rdev)
  {
        si_pcie_gart_disable(rdev);
        radeon_gart_table_vram_free(rdev);
@@@ -2788,41 -2789,84 +2789,84 @@@ void si_vm_fini(struct radeon_device *r
  {
  }
  
- int si_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id)
+ /**
+  * si_vm_set_page - update the page tables using the CP
+  *
+  * @rdev: radeon_device pointer
+  * @pe: addr of the page entry
+  * @addr: dst addr to write into pe
+  * @count: number of page entries to update
+  * @incr: increase next addr by incr bytes
+  * @flags: access flags
+  *
+  * Update the page tables using the CP (cayman-si).
+  */
+ void si_vm_set_page(struct radeon_device *rdev, uint64_t pe,
+                   uint64_t addr, unsigned count,
+                   uint32_t incr, uint32_t flags)
  {
-       if (id < 8)
-               WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (id << 2), vm->pt_gpu_addr >> 12);
-       else
-               WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((id - 8) << 2),
-                      vm->pt_gpu_addr >> 12);
-       /* flush hdp cache */
-       WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
-       /* bits 0-15 are the VM contexts0-15 */
-       WREG32(VM_INVALIDATE_REQUEST, 1 << id);
-       return 0;
+       struct radeon_ring *ring = &rdev->ring[rdev->asic->vm.pt_ring_index];
+       uint32_t r600_flags = cayman_vm_page_flags(rdev, flags);
+       int i;
+       uint64_t value;
+       radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 2 + count * 2));
+       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+                                WRITE_DATA_DST_SEL(1)));
+       radeon_ring_write(ring, pe);
+       radeon_ring_write(ring, upper_32_bits(pe));
+       for (i = 0; i < count; ++i) {
+               if (flags & RADEON_VM_PAGE_SYSTEM) {
+                       value = radeon_vm_map_gart(rdev, addr);
+                       value &= 0xFFFFFFFFFFFFF000ULL;
+               } else if (flags & RADEON_VM_PAGE_VALID)
+                       value = addr;
+               else
+                       value = 0;
+               addr += incr;
+               value |= r600_flags;
+               radeon_ring_write(ring, value);
+               radeon_ring_write(ring, upper_32_bits(value));
+       }
  }
  
- void si_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm)
+ void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
  {
-       if (vm->id < 8)
-               WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2), 0);
-       else
-               WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2), 0);
-       /* flush hdp cache */
-       WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
-       /* bits 0-15 are the VM contexts0-15 */
-       WREG32(VM_INVALIDATE_REQUEST, 1 << vm->id);
- }
+       struct radeon_ring *ring = &rdev->ring[ridx];
  
- void si_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm)
- {
-       if (vm->id == -1)
+       if (vm == NULL)
                return;
  
+       /* write new base address */
+       radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+                                WRITE_DATA_DST_SEL(0)));
+       if (vm->id < 8) {
+               radeon_ring_write(ring,
+                                 (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2);
+       } else {
+               radeon_ring_write(ring,
+                                 (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2);
+       }
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
        /* flush hdp cache */
-       WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
+       radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+                                WRITE_DATA_DST_SEL(0)));
+       radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, 0x1);
        /* bits 0-15 are the VM contexts0-15 */
-       WREG32(VM_INVALIDATE_REQUEST, 1 << vm->id);
+       radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+                                WRITE_DATA_DST_SEL(0)));
+       radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, 1 << vm->id);
  }
  
  /*
@@@ -3199,10 -3243,6 +3243,6 @@@ int si_irq_set(struct radeon_device *rd
                DRM_DEBUG("si_irq_set: hpd 6\n");
                hpd6 |= DC_HPDx_INT_EN;
        }
-       if (rdev->irq.gui_idle) {
-               DRM_DEBUG("gui idle\n");
-               grbm_int_cntl |= GUI_IDLE_INT_ENABLE;
-       }
  
        WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
        WREG32(CP_INT_CNTL_RING1, cp_int_cntl1);
@@@ -3658,7 -3698,6 +3698,6 @@@ restart_ih
                        break;
                case 233: /* GUI IDLE */
                        DRM_DEBUG("IH: GUI idle\n");
-                       wake_up(&rdev->irq.idle_queue);
                        break;
                default:
                        DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@@ -22,8 -22,8 +22,8 @@@
   * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   */
 -#include "drmP.h"
 -#include "savage_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/savage_drm.h>
  #include "savage_drv.h"
  
  /* Need a long timeout for shadow status updates can take a while
@@@ -547,6 -547,8 +547,8 @@@ int savage_driver_load(struct drm_devic
  
        dev_priv->chipset = (enum savage_family)chipset;
  
+       pci_set_master(dev->pdev);
        return 0;
  }
  
@@@ -28,8 -28,8 +28,8 @@@
   * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
   */
  
 -#include "ttm/ttm_bo_driver.h"
 -#include "ttm/ttm_placement.h"
 +#include <drm/ttm/ttm_bo_driver.h>
 +#include <drm/ttm/ttm_placement.h>
  #include <linux/io.h>
  #include <linux/highmem.h>
  #include <linux/wait.h>
@@@ -472,7 -472,7 +472,7 @@@ pgprot_t ttm_io_prot(uint32_t caching_f
        else
                tmp = pgprot_noncached(tmp);
  #endif
- #if defined(__sparc__)
+ #if defined(__sparc__) || defined(__mips__)
        if (!(caching_flags & TTM_PL_FLAG_CACHED))
                tmp = pgprot_noncached(tmp);
  #endif
@@@ -47,8 -47,8 +47,8 @@@
  #include <linux/atomic.h>
  #include <linux/device.h>
  #include <linux/kthread.h>
 -#include "ttm/ttm_bo_driver.h"
 -#include "ttm/ttm_page_alloc.h"
 +#include <drm/ttm/ttm_bo_driver.h>
 +#include <drm/ttm/ttm_page_alloc.h>
  #ifdef TTM_HAS_AGP
  #include <asm/agp.h>
  #endif
@@@ -1060,7 -1060,7 +1060,7 @@@ int ttm_dma_page_alloc_init(struct ttm_
  
        _manager = kzalloc(sizeof(*_manager), GFP_KERNEL);
        if (!_manager)
-               goto err_manager;
+               goto err;
  
        mutex_init(&_manager->lock);
        INIT_LIST_HEAD(&_manager->pools);
        }
        ttm_dma_pool_mm_shrink_init(_manager);
        return 0;
- err_manager:
-       kfree(_manager);
-       _manager = NULL;
  err:
        return ret;
  }
  #include <linux/swap.h>
  #include <linux/slab.h>
  #include <linux/export.h>
 -#include "drm_cache.h"
 -#include "drm_mem_util.h"
 -#include "ttm/ttm_module.h"
 -#include "ttm/ttm_bo_driver.h"
 -#include "ttm/ttm_placement.h"
 -#include "ttm/ttm_page_alloc.h"
 +#include <drm/drm_cache.h>
 +#include <drm/drm_mem_util.h>
 +#include <drm/ttm/ttm_module.h>
 +#include <drm/ttm/ttm_bo_driver.h>
 +#include <drm/ttm/ttm_placement.h>
 +#include <drm/ttm/ttm_page_alloc.h>
  
  /**
   * Allocates storage for pointers to the pages that back the ttm.
@@@ -290,8 -290,6 +290,6 @@@ int ttm_tt_swapin(struct ttm_tt *ttm
        struct file *swap_storage;
        struct page *from_page;
        struct page *to_page;
-       void *from_virtual;
-       void *to_virtual;
        int i;
        int ret = -ENOMEM;
  
                        goto out_err;
  
                preempt_disable();
-               from_virtual = kmap_atomic(from_page);
-               to_virtual = kmap_atomic(to_page);
-               memcpy(to_virtual, from_virtual, PAGE_SIZE);
-               kunmap_atomic(to_virtual);
-               kunmap_atomic(from_virtual);
+               copy_highpage(to_page, from_page);
                preempt_enable();
                page_cache_release(from_page);
        }
@@@ -336,8 -330,6 +330,6 @@@ int ttm_tt_swapout(struct ttm_tt *ttm, 
        struct file *swap_storage;
        struct page *from_page;
        struct page *to_page;
-       void *from_virtual;
-       void *to_virtual;
        int i;
        int ret = -ENOMEM;
  
                        goto out_err;
                }
                preempt_disable();
-               from_virtual = kmap_atomic(from_page);
-               to_virtual = kmap_atomic(to_page);
-               memcpy(to_virtual, from_virtual, PAGE_SIZE);
-               kunmap_atomic(to_virtual);
-               kunmap_atomic(from_virtual);
+               copy_highpage(to_page, from_page);
                preempt_enable();
                set_page_dirty(to_page);
                mark_page_accessed(to_page);
   * more details.
   */
  
 -#include "drmP.h"
 -#include "drm_crtc.h"
 -#include "drm_edid.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_edid.h>
 +#include <drm/drm_crtc_helper.h>
  #include "udl_drv.h"
  
  /* dummy connector to just get EDID,
@@@ -57,11 -57,8 +57,8 @@@ static int udl_get_modes(struct drm_con
  
        edid = (struct edid *)udl_get_edid(udl);
  
-       connector->display_info.raw_edid = (char *)edid;
        drm_mode_connector_update_edid_property(connector, edid);
        ret = drm_add_edid_modes(connector, edid);
-       connector->display_info.raw_edid = NULL;
        kfree(edid);
        return ret;
  }
   * more details.
   */
  
 -#include "drmP.h"
 -#include "drm_crtc.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_crtc_helper.h>
  #include "udl_drv.h"
  
  /* dummy encoder */
- void udl_enc_destroy(struct drm_encoder *encoder)
static void udl_enc_destroy(struct drm_encoder *encoder)
  {
        drm_encoder_cleanup(encoder);
        kfree(encoder);
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <linux/fb.h>
+ #include <linux/dma-buf.h>
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_crtc_helper.h>
  #include "udl_drv.h"
  
 -#include "drm_fb_helper.h"
 +#include <drm/drm_fb_helper.h>
  
  #define DL_DEFIO_WRITE_DELAY    5 /* fb_deferred_io.delay in jiffies */
  
@@@ -355,12 -357,12 +356,12 @@@ static struct fb_ops udlfb_ops = 
        .fb_release = udl_fb_release,
  };
  
- void udl_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
static void udl_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
                           u16 blue, int regno)
  {
  }
  
- void udl_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
static void udl_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
                             u16 *blue, int regno)
  {
        *red = 0;
@@@ -376,16 -378,33 +377,33 @@@ static int udl_user_framebuffer_dirty(s
  {
        struct udl_framebuffer *ufb = to_udl_fb(fb);
        int i;
+       int ret = 0;
  
        if (!ufb->active_16)
                return 0;
  
+       if (ufb->obj->base.import_attach) {
+               ret = dma_buf_begin_cpu_access(ufb->obj->base.import_attach->dmabuf,
+                                              0, ufb->obj->base.size,
+                                              DMA_FROM_DEVICE);
+               if (ret)
+                       return ret;
+       }
        for (i = 0; i < num_clips; i++) {
-               udl_handle_damage(ufb, clips[i].x1, clips[i].y1,
+               ret = udl_handle_damage(ufb, clips[i].x1, clips[i].y1,
                                  clips[i].x2 - clips[i].x1,
                                  clips[i].y2 - clips[i].y1);
+               if (ret)
+                       break;
        }
-       return 0;
+       if (ufb->obj->base.import_attach) {
+               dma_buf_end_cpu_access(ufb->obj->base.import_attach->dmabuf,
+                                      0, ufb->obj->base.size,
+                                      DMA_FROM_DEVICE);
+       }
+       return ret;
  }
  
  static void udl_user_framebuffer_destroy(struct drm_framebuffer *fb)
@@@ -6,7 -6,7 +6,7 @@@
   * more details.
   */
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "udl_drv.h"
  #include <linux/shmem_fs.h>
  #include <linux/dma-buf.h>
@@@ -181,11 -181,6 +181,6 @@@ int udl_gem_vmap(struct udl_gem_object 
        int ret;
  
        if (obj->base.import_attach) {
-               ret = dma_buf_begin_cpu_access(obj->base.import_attach->dmabuf,
-                                              0, obj->base.size, DMA_BIDIRECTIONAL);
-               if (ret)
-                       return -EINVAL;
                obj->vmapping = dma_buf_vmap(obj->base.import_attach->dmabuf);
                if (!obj->vmapping)
                        return -ENOMEM;
@@@ -206,8 -201,6 +201,6 @@@ void udl_gem_vunmap(struct udl_gem_obje
  {
        if (obj->base.import_attach) {
                dma_buf_vunmap(obj->base.import_attach->dmabuf, obj->vmapping);
-               dma_buf_end_cpu_access(obj->base.import_attach->dmabuf, 0,
-                                      obj->base.size, DMA_BIDIRECTIONAL);
                return;
        }
  
@@@ -10,7 -10,7 +10,7 @@@
   * License v2. See the file COPYING in the main directory of this archive for
   * more details.
   */
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "udl_drv.h"
  
  /* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */
@@@ -41,11 -41,8 +41,8 @@@ static int udl_parse_vendor_descriptor(
        total_len = usb_get_descriptor(usbdev, 0x5f, /* vendor specific */
                                    0, desc, MAX_VENDOR_DESCRIPTOR_SIZE);
        if (total_len > 5) {
-               DRM_INFO("vendor descriptor length:%x data:%02x %02x %02x %02x" \
-                       "%02x %02x %02x %02x %02x %02x %02x\n",
-                       total_len, desc[0],
-                       desc[1], desc[2], desc[3], desc[4], desc[5], desc[6],
-                       desc[7], desc[8], desc[9], desc[10]);
+               DRM_INFO("vendor descriptor length:%x data:%*ph\n",
+                       total_len, 11, desc);
  
                if ((desc[0] != total_len) || /* descriptor length */
                    (desc[1] != 0x5f) ||   /* vendor descriptor type */
@@@ -11,9 -11,9 +11,9 @@@
   * more details.
   */
  
 -#include "drmP.h"
 -#include "drm_crtc.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_crtc_helper.h>
  #include "udl_drv.h"
  
  /*
@@@ -391,7 -391,7 +391,7 @@@ static const struct drm_crtc_funcs udl_
        .destroy = udl_crtc_destroy,
  };
  
- int udl_crtc_init(struct drm_device *dev)
static int udl_crtc_init(struct drm_device *dev)
  {
        struct drm_crtc *crtc;
  
@@@ -15,7 -15,7 +15,7 @@@
  #include <linux/fb.h>
  #include <linux/prefetch.h>
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "udl_drv.h"
  
  #define MAX_CMD_PIXELS                255
@@@ -126,10 -126,10 +126,10 @@@ static void udl_compress_hline16
  
        while ((pixel_end > pixel) &&
               (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) {
-               uint8_t *raw_pixels_count_byte = 0;
-               uint8_t *cmd_pixels_count_byte = 0;
-               const u8 *raw_pixel_start = 0;
-               const u8 *cmd_pixel_start, *cmd_pixel_end = 0;
+               uint8_t *raw_pixels_count_byte = NULL;
+               uint8_t *cmd_pixels_count_byte = NULL;
+               const u8 *raw_pixel_start = NULL;
+               const u8 *cmd_pixel_start, *cmd_pixel_end = NULL;
  
                prefetchw((void *) cmd); /* pull in one cache line at least */
  
   **************************************************************************/
  #include <linux/module.h>
  
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "vmwgfx_drv.h"
 -#include "ttm/ttm_placement.h"
 -#include "ttm/ttm_bo_driver.h"
 -#include "ttm/ttm_object.h"
 -#include "ttm/ttm_module.h"
 +#include <drm/ttm/ttm_placement.h>
 +#include <drm/ttm/ttm_bo_driver.h>
 +#include <drm/ttm/ttm_object.h>
 +#include <drm/ttm/ttm_module.h>
  
  #define VMWGFX_DRIVER_NAME "vmwgfx"
  #define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices"
@@@ -438,7 -438,6 +438,6 @@@ static int vmw_driver_load(struct drm_d
                DRM_ERROR("Failed allocating a device private struct.\n");
                return -ENOMEM;
        }
-       memset(dev_priv, 0, sizeof(*dev_priv));
  
        pci_set_master(dev->pdev);
  
diff --combined include/drm/drmP.h
@@@ -72,8 -72,7 +72,8 @@@
  #include <linux/workqueue.h>
  #include <linux/poll.h>
  #include <asm/pgalloc.h>
 -#include "drm.h"
 +#include <drm/drm.h>
 +#include <drm/drm_sarea.h>
  
  #include <linux/idr.h>
  
@@@ -85,9 -84,9 +85,9 @@@ struct module
  struct drm_file;
  struct drm_device;
  
 -#include "drm_os_linux.h"
 -#include "drm_hashtab.h"
 -#include "drm_mm.h"
 +#include <drm/drm_os_linux.h>
 +#include <drm/drm_hashtab.h>
 +#include <drm/drm_mm.h>
  
  #define DRM_UT_CORE           0x01
  #define DRM_UT_DRIVER         0x02
@@@ -427,8 -426,8 +427,8 @@@ struct drm_prime_file_private 
  /** File private data */
  struct drm_file {
        int authenticated;
 -      pid_t pid;
 -      uid_t uid;
 +      struct pid *pid;
 +      kuid_t uid;
        drm_magic_t magic;
        unsigned long ioctl_count;
        struct list_head lhead;
@@@ -676,7 -675,7 +676,7 @@@ struct drm_gem_object 
        struct dma_buf_attachment *import_attach;
  };
  
 -#include "drm_crtc.h"
 +#include <drm/drm_crtc.h>
  
  /* per-master structure */
  struct drm_master {
@@@ -1304,7 -1303,7 +1304,7 @@@ extern void drm_vm_close_locked(struct 
  extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
  
                                /* Memory management support (drm_memory.h) */
 -#include "drm_memory.h"
 +#include <drm/drm_memory.h>
  extern void drm_free_agp(DRM_AGP_MEM * handle, int pages);
  extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start);
  extern DRM_AGP_MEM *drm_agp_bind_pages(struct drm_device *dev,
@@@ -1368,6 -1367,7 +1368,7 @@@ extern int drm_remove_magic(struct drm_
  
  /* Cache management (drm_cache.c) */
  void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
+ void drm_clflush_sg(struct sg_table *st);
  void drm_clflush_virt_range(char *addr, unsigned long length);
  
                                /* Locking IOCTL support (drm_lock.h) */
@@@ -1613,7 -1613,7 +1614,7 @@@ void drm_gem_vm_open(struct vm_area_str
  void drm_gem_vm_close(struct vm_area_struct *vma);
  int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
  
 -#include "drm_global.h"
 +#include <drm/drm_global.h>
  
  static inline void
  drm_gem_object_reference(struct drm_gem_object *obj)
@@@ -1722,7 -1722,7 +1723,7 @@@ static __inline__ void drm_core_dropmap
  {
  }
  
 -#include "drm_mem_util.h"
 +#include <drm/drm_mem_util.h>
  
  extern int drm_fill_in_dev(struct drm_device *dev,
                           const struct pci_device_id *ent,
diff --combined include/drm/drm_crtc.h
@@@ -30,7 -30,6 +30,7 @@@
  #include <linux/types.h>
  #include <linux/idr.h>
  #include <linux/fb.h>
 +#include <drm/drm_mode.h>
  
  #include <drm/drm_fourcc.h>
  
@@@ -216,11 -215,10 +216,10 @@@ struct drm_display_info 
        u32 color_formats;
  
        u8 cea_rev;
-       char *raw_edid; /* if any */
  };
  
  struct drm_framebuffer_funcs {
+       /* note: use drm_framebuffer_remove() */
        void (*destroy)(struct drm_framebuffer *framebuffer);
        int (*create_handle)(struct drm_framebuffer *fb,
                             struct drm_file *file_priv,
  
  struct drm_framebuffer {
        struct drm_device *dev;
+       /*
+        * Note that the fb is refcounted for the benefit of driver internals,
+        * for example some hw, disabling a CRTC/plane is asynchronous, and
+        * scanout does not actually complete until the next vblank.  So some
+        * cleanup (like releasing the reference(s) on the backing GEM bo(s))
+        * should be deferred.  In cases like this, the driver would like to
+        * hold a ref to the fb even though it has already been removed from
+        * userspace perspective.
+        */
+       struct kref refcount;
        struct list_head head;
        struct drm_mode_object base;
        const struct drm_framebuffer_funcs *funcs;
@@@ -360,6 -368,9 +369,9 @@@ struct drm_crtc_funcs 
   * @enabled: is this CRTC enabled?
   * @mode: current mode timings
   * @hwmode: mode timings as programmed to hw regs
+  * @invert_dimensions: for purposes of error checking crtc vs fb sizes,
+  *    invert the width/height of the crtc.  This is used if the driver
+  *    is performing 90 or 270 degree rotated scanout
   * @x: x position on screen
   * @y: y position on screen
   * @funcs: CRTC control functions
@@@ -393,6 -404,8 +405,8 @@@ struct drm_crtc 
         */
        struct drm_display_mode hwmode;
  
+       bool invert_dimensions;
        int x, y;
        const struct drm_crtc_funcs *funcs;
  
@@@ -594,6 -607,7 +608,7 @@@ struct drm_connector 
        int video_latency[2];   /* [0]: progressive, [1]: interlaced */
        int audio_latency[2];
        int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
+       unsigned bad_edid_counter;
  };
  
  /**
@@@ -921,6 -935,9 +936,9 @@@ extern void drm_framebuffer_set_object(
  extern int drm_framebuffer_init(struct drm_device *dev,
                                struct drm_framebuffer *fb,
                                const struct drm_framebuffer_funcs *funcs);
+ extern void drm_framebuffer_unreference(struct drm_framebuffer *fb);
+ extern void drm_framebuffer_reference(struct drm_framebuffer *fb);
+ extern void drm_framebuffer_remove(struct drm_framebuffer *fb);
  extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb);
  extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
  extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
@@@ -1036,7 -1053,7 +1054,7 @@@ extern int drm_add_modes_noedid(struct 
                                int hdisplay, int vdisplay);
  
  extern int drm_edid_header_is_valid(const u8 *raw_edid);
- extern bool drm_edid_block_valid(u8 *raw_edid, int block);
+ extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid);
  extern bool drm_edid_is_valid(struct edid *edid);
  struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
                                           int hsize, int vsize, int fresh,
diff --combined include/drm/drm_sarea.h
  #ifndef _DRM_SAREA_H_
  #define _DRM_SAREA_H_
  
 -#include "drm.h"
 +#include <drm/drm.h>
  
  /* SAREA area needs to be at least a page */
  #if defined(__alpha__)
  #define SAREA_MAX                       0x2000U
+ #elif defined(__mips__)
+ #define SAREA_MAX                       0x4000U
  #elif defined(__ia64__)
  #define SAREA_MAX                       0x10000U      /* 64kB */
  #else
diff --combined include/drm/i915_drm.h
@@@ -27,7 -27,7 +27,7 @@@
  #ifndef _I915_DRM_H_
  #define _I915_DRM_H_
  
 -#include "drm.h"
 +#include <drm/drm.h>
  
  /* Please note that modifications to all structs defined here are
   * subject to backwards-compatibility constraints.
@@@ -203,6 -203,9 +203,9 @@@ typedef struct _drm_i915_sarea 
  #define DRM_I915_GEM_WAIT     0x2c
  #define DRM_I915_GEM_CONTEXT_CREATE   0x2d
  #define DRM_I915_GEM_CONTEXT_DESTROY  0x2e
+ #define DRM_I915_GEM_SET_CACHING      0x2f
+ #define DRM_I915_GEM_GET_CACHING      0x30
+ #define DRM_I915_REG_READ             0x31
  
  #define DRM_IOCTL_I915_INIT           DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
  #define DRM_IOCTL_I915_FLUSH          DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
  #define DRM_IOCTL_I915_GEM_PIN                DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin)
  #define DRM_IOCTL_I915_GEM_UNPIN      DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin)
  #define DRM_IOCTL_I915_GEM_BUSY               DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy)
+ #define DRM_IOCTL_I915_GEM_SET_CACHING                DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_SET_CACHING, struct drm_i915_gem_caching)
+ #define DRM_IOCTL_I915_GEM_GET_CACHING                DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_GET_CACHING, struct drm_i915_gem_caching)
  #define DRM_IOCTL_I915_GEM_THROTTLE   DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE)
  #define DRM_IOCTL_I915_GEM_ENTERVT    DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT)
  #define DRM_IOCTL_I915_GEM_LEAVEVT    DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT)
  #define DRM_IOCTL_I915_GEM_WAIT               DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_WAIT, struct drm_i915_gem_wait)
  #define DRM_IOCTL_I915_GEM_CONTEXT_CREATE     DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create)
  #define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY    DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy)
+ #define DRM_IOCTL_I915_REG_READ                       DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read)
  
  /* Allow drivers to submit batchbuffers directly to hardware, relying
   * on the security mechanisms provided by hardware.
@@@ -305,6 -311,9 +311,9 @@@ typedef struct drm_i915_irq_wait 
  #define I915_PARAM_HAS_LLC                     17
  #define I915_PARAM_HAS_ALIASING_PPGTT  18
  #define I915_PARAM_HAS_WAIT_TIMEOUT    19
+ #define I915_PARAM_HAS_SEMAPHORES      20
+ #define I915_PARAM_HAS_PRIME_VMAP_FLUSH        21
+ #define I915_PARAM_RSVD_FOR_FUTURE_USE         22
  
  typedef struct drm_i915_getparam {
        int param;
@@@ -698,10 -707,31 +707,31 @@@ struct drm_i915_gem_busy 
        /** Handle of the buffer to check for busy */
        __u32 handle;
  
-       /** Return busy status (1 if busy, 0 if idle) */
+       /** Return busy status (1 if busy, 0 if idle).
+        * The high word is used to indicate on which rings the object
+        * currently resides:
+        *  16:31 - busy (r or r/w) rings (16 render, 17 bsd, 18 blt, etc)
+        */
        __u32 busy;
  };
  
+ #define I915_CACHING_NONE             0
+ #define I915_CACHING_CACHED           1
+ struct drm_i915_gem_caching {
+       /**
+        * Handle of the buffer to set/get the caching level of. */
+       __u32 handle;
+       /**
+        * Cacheing level to apply or return value
+        *
+        * bits0-15 are for generic caching control (i.e. the above defined
+        * values). bits16-31 are reserved for platform-specific variations
+        * (e.g. l3$ caching on gen7). */
+       __u32 caching;
+ };
  #define I915_TILING_NONE      0
  #define I915_TILING_X         1
  #define I915_TILING_Y         2
@@@ -918,4 -948,8 +948,8 @@@ struct drm_i915_gem_context_destroy 
        __u32 pad;
  };
  
+ struct drm_i915_reg_read {
+       __u64 offset;
+       __u64 val; /* Return value */
+ };
  #endif                                /* _I915_DRM_H_ */