rpms/kernel/devel drm-nouveau.patch, 1.33, 1.34 kernel.spec, 1.1598, 1.1599

Ben Skeggs bskeggs at fedoraproject.org
Tue Jun 30 03:47:26 UTC 2009


Author: bskeggs

Update of /cvs/pkgs/rpms/kernel/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv15884

Modified Files:
	drm-nouveau.patch kernel.spec 
Log Message:
* Tue Jun 30 2009 Ben Skeggs <bskeggs at redhat.com>
- drm-nouveau.patch: match upstream



drm-nouveau.patch:

Index: drm-nouveau.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/drm-nouveau.patch,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -p -r1.33 -r1.34
--- drm-nouveau.patch	27 Jun 2009 02:28:30 -0000	1.33
+++ drm-nouveau.patch	30 Jun 2009 03:47:25 -0000	1.34
@@ -5373,10 +5373,10 @@ index 0000000..b7e0f32
 +#endif
 diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
 new file mode 100644
-index 0000000..be07b22
+index 0000000..4bd813d
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
-@@ -0,0 +1,424 @@
+@@ -0,0 +1,559 @@
 +/*
 + * Copyright 2007 Dave Airlied
 + * All Rights Reserved.
@@ -5412,6 +5412,140 @@ index 0000000..be07b22
 +#include "nouveau_drv.h"
 +#include "nouveau_dma.h"
 +
++static void
++nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
++{
++	struct nouveau_bo *nvbo = nouveau_bo(bo);
++
++	if (unlikely(nvbo->kmap.virtual))
++		ttm_bo_kunmap(&nvbo->kmap);
++
++	if (unlikely(nvbo->gem))
++		DRM_ERROR("bo %p still attached to GEM object\n", bo);
++	kfree(nvbo);
++}
++
++int
++nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
++	       int size, int align, uint32_t flags, uint32_t tile_mode,
++	       uint32_t tile_flags, bool no_vm, bool mappable,
++	       struct nouveau_bo **pnvbo)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nouveau_bo *nvbo;
++	int ret;
++
++	nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL);
++	if (!nvbo)
++		return -ENOMEM;
++	nvbo->mappable = mappable;
++	nvbo->no_vm = no_vm;
++	nvbo->tile_mode = tile_mode;
++	nvbo->tile_flags = tile_flags;
++
++	if (!nvbo->mappable && (flags & TTM_PL_FLAG_VRAM))
++		flags |= TTM_PL_FLAG_PRIV0;
++
++	align >>= PAGE_SHIFT;
++
++	size = (size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
++	if (dev_priv->card_type == NV_50) {
++		size = (size + 65535) & ~65535;
++		if (align < (65536 / PAGE_SIZE))
++			align = (65536 / PAGE_SIZE);
++	}
++
++	nvbo->channel = chan;
++	ret = ttm_buffer_object_init(&dev_priv->ttm.bdev, &nvbo->bo, size,
++				     ttm_bo_type_device, flags, align,
++				     0, false, NULL, size, nouveau_bo_del_ttm);
++	nvbo->channel = NULL;
++	if (ret) {
++		/* ttm will call nouveau_bo_del_ttm if it fails.. */
++		return ret;
++	}
++
++	*pnvbo = nvbo;
++	return 0;
++}
++
++int
++nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype)
++{
++	struct ttm_buffer_object *bo = &nvbo->bo;
++	int ret;
++
++	if (nvbo->pin_refcnt && !(memtype & (1 << bo->mem.mem_type))) {
++		NV_ERROR(nouveau_bdev(bo->bdev)->dev,
++			 "bo %p pinned elsewhere: 0x%08x vs 0x%08x\n", bo,
++			 1 << bo->mem.mem_type, memtype);
++		return -EINVAL;
++	}
++
++	if (nvbo->pin_refcnt++)
++		return 0;
++
++	bo->proposed_placement &= ~TTM_PL_MASK_MEM;
++	bo->proposed_placement |= (memtype & TTM_PL_MASK_MEM);
++	bo->proposed_placement |= TTM_PL_FLAG_NO_EVICT;
++
++	ret = ttm_bo_reserve(bo, false, false, false, 0);
++	if (ret)
++		goto out;
++
++	ret = ttm_buffer_object_validate(bo, bo->proposed_placement,
++					 false, false);
++	ttm_bo_unreserve(bo);
++out:
++	if (unlikely(ret))
++		nvbo->pin_refcnt--;
++	return ret;
++}
++
++int
++nouveau_bo_unpin(struct nouveau_bo *nvbo)
++{
++	struct ttm_buffer_object *bo = &nvbo->bo;
++	int ret;
++
++	if (--nvbo->pin_refcnt)
++		return 0;
++
++	bo->proposed_placement &= ~TTM_PL_FLAG_NO_EVICT;
++
++	ret = ttm_bo_reserve(bo, false, false, false, 0);
++	if (ret)
++		return ret;
++
++	ret = ttm_buffer_object_validate(bo, bo->proposed_placement,
++					 false, false);
++	ttm_bo_unreserve(bo);
++	return ret;
++}
++
++int
++nouveau_bo_map(struct nouveau_bo *nvbo)
++{
++	int ret;
++
++	ret = ttm_bo_reserve(&nvbo->bo, false, false, false, 0);
++	if (ret)
++		return ret;
++
++	ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, &nvbo->kmap);
++	ttm_bo_unreserve(&nvbo->bo);
++	return ret;
++}
++
++void
++nouveau_bo_unmap(struct nouveau_bo *nvbo)
++{
++	if (nvbo->kmap.virtual) {
++		ttm_bo_kunmap(&nvbo->kmap);
++		nvbo->kmap.virtual = NULL;
++	}
++}
++
 +static struct ttm_backend *
 +nouveau_bo_create_ttm_backend_entry(struct ttm_bo_device *bdev)
 +{
@@ -5742,7 +5876,8 @@ index 0000000..be07b22
 +		return 0;
 +	}
 +
-+	if (dev_priv->card_type == NV_50 && nvbo->tile_flags)
++	if (dev_priv->card_type == NV_50 && (nvbo->tile_flags ||
++	    (dev_priv->sfb_gem && dev_priv->sfb_gem->driver_private == nvbo)))
 +		return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem);
 +
 +	if (new_mem->mem_type == TTM_PL_SYSTEM) {
@@ -6492,10 +6627,10 @@ index 0000000..7df2f63
 +#endif /* __NOUVEAU_CONNECTOR_H__ */
 diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h
 new file mode 100644
-index 0000000..62f273e
+index 0000000..d8f18f9
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h
-@@ -0,0 +1,91 @@
+@@ -0,0 +1,89 @@
 +/*
 + * Copyright (C) 2008 Maarten Maathuis.
 + * All Rights Reserved.
@@ -6567,8 +6702,6 @@ index 0000000..62f273e
 +
 +	int (*set_dither) (struct nouveau_crtc *crtc, bool update);
 +	int (*set_scale) (struct nouveau_crtc *crtc, int mode, bool update);
-+	int (*set_clock) (struct nouveau_crtc *crtc, struct drm_display_mode *);
-+	int (*set_clock_mode) (struct nouveau_crtc *crtc);
 +	int (*destroy) (struct nouveau_crtc *crtc);
 +};
 +#define to_nouveau_crtc(x) container_of((x), struct nouveau_crtc, base)
@@ -7190,10 +7323,10 @@ index 0000000..36a387a
 +MODULE_LICENSE("GPL and additional rights");
 diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
 new file mode 100644
-index 0000000..682e5a2
+index 0000000..d98895d
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
-@@ -0,0 +1,1022 @@
+@@ -0,0 +1,1028 @@
 +/*
 + * Copyright 2005 Stephane Marchesin.
 + * All Rights Reserved.
@@ -7716,6 +7849,8 @@ index 0000000..682e5a2
 +	struct backlight_device *backlight;
 +
 +	struct nv50_evo_channel evo;
++
++	struct drm_gem_object *sfb_gem;
 +};
 +
 +static inline int
@@ -8042,8 +8177,16 @@ index 0000000..682e5a2
 +/* nv04_crtc.c */
 +extern int nv04_crtc_create(struct drm_device *, int index);
 +
-+/* nouveau_buffer.c */
++/* nouveau_bo.c */
 +extern struct ttm_bo_driver nouveau_bo_driver;
++extern int nouveau_bo_new(struct drm_device *, struct nouveau_channel *,
++			  int size, int align, uint32_t flags,
++			  uint32_t tile_mode, uint32_t tile_flags,
++			  bool no_vm, bool mappable, struct nouveau_bo **);
++extern int nouveau_bo_pin(struct nouveau_bo *, uint32_t flags);
++extern int nouveau_bo_unpin(struct nouveau_bo *);
++extern int nouveau_bo_map(struct nouveau_bo *);
++extern void nouveau_bo_unmap(struct nouveau_bo *);
 +
 +/* nouveau_fence.c */
 +struct nouveau_fence;
@@ -8061,16 +8204,12 @@ index 0000000..682e5a2
 +extern void nouveau_fence_handler(struct drm_device *dev, int channel);
 +
 +/* nouveau_gem.c */
++extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *,
++			   int size, int align, uint32_t flags,
++			   uint32_t tile_mode, uint32_t tile_flags,
++			   bool no_vm, bool mappable, 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_bo_new(struct drm_device *, struct nouveau_channel *,
-+			  int size, int align, uint32_t flags,
-+			  uint32_t tile_mode, uint32_t tile_flags,
-+			  bool no_vm, bool mappable, struct nouveau_bo **);
-+extern int nouveau_bo_pin(struct nouveau_bo *, uint32_t flags);
-+extern int nouveau_bo_unpin(struct nouveau_bo *);
-+extern int nouveau_bo_map(struct nouveau_bo *);
-+extern void nouveau_bo_unmap(struct nouveau_bo *);
 +extern int nouveau_gem_ioctl_new(struct drm_device *, void *,
 +				 struct drm_file *);
 +extern int nouveau_gem_ioctl_pushbuf(struct drm_device *, void *,
@@ -8326,10 +8465,10 @@ index 0000000..f28d247
 +#endif /* __NOUVEAU_FB_H__ */
 diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
 new file mode 100644
-index 0000000..24b7140
+index 0000000..075a4a7
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
-@@ -0,0 +1,1023 @@
+@@ -0,0 +1,1016 @@
 +/*
 + * Copyright © 2007 David Airlie
 + *
@@ -8848,8 +8987,8 @@ index 0000000..24b7140
 +	size = mode_cmd.pitch * mode_cmd.height;
 +	size = ALIGN(size, PAGE_SIZE);
 +
-+	ret = nouveau_bo_new(dev, dev_priv->channel, size, 0, TTM_PL_FLAG_VRAM,
-+			     0, 0x0000, false, true, &nvbo);
++	ret = nouveau_gem_new(dev, dev_priv->channel, size, 0, TTM_PL_FLAG_VRAM,
++			      0, 0x0000, false, true, &nvbo);
 +	if (ret) {
 +		NV_ERROR(dev, "failed to allocate framebuffer\n");
 +		goto out;
@@ -8862,13 +9001,6 @@ index 0000000..24b7140
 +		goto out;
 +	}
 +
-+	nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size);
-+	if (!nvbo->gem) {
-+		nouveau_bo_ref(NULL, &nvbo);
-+		goto out;
-+	}
-+	nvbo->gem->driver_private = nvbo;
-+
 +	mutex_lock(&dev->struct_mutex);
 +
 +	fb = nouveau_framebuffer_create(dev, nvbo, &mode_cmd);
@@ -10326,10 +10458,10 @@ index 0000000..fb9024e
 +int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls);
 diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
 new file mode 100644
-index 0000000..9573bd8
+index 0000000..64b5625
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
-@@ -0,0 +1,884 @@
+@@ -0,0 +1,765 @@
 +/*
 + * Copyright (C) 2008 Ben Skeggs.
 + * All Rights Reserved.
@@ -10391,139 +10523,30 @@ index 0000000..9573bd8
 +	ttm_bo_unref(&bo);
 +}
 +
-+static void
-+nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
-+{
-+	struct nouveau_bo *nvbo = nouveau_bo(bo);
-+
-+	if (unlikely(nvbo->kmap.virtual))
-+		ttm_bo_kunmap(&nvbo->kmap);
-+
-+	if (unlikely(nvbo->gem))
-+		DRM_ERROR("bo %p still attached to GEM object\n", bo);
-+	kfree(nvbo);
-+}
-+
 +int
-+nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
-+	       int size, int align, uint32_t flags, uint32_t tile_mode,
-+	       uint32_t tile_flags, bool no_vm, bool mappable,
-+	       struct nouveau_bo **pnvbo)
++nouveau_gem_new(struct drm_device *dev, struct nouveau_channel *chan,
++		int size, int align, uint32_t flags, uint32_t tile_mode,
++		uint32_t tile_flags, bool no_vm, bool mappable,
++		struct nouveau_bo **pnvbo)
 +{
-+	struct drm_nouveau_private *dev_priv = dev->dev_private;
 +	struct nouveau_bo *nvbo;
 +	int ret;
 +
-+	nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL);
-+	if (!nvbo)
-+		return -ENOMEM;
-+	nvbo->mappable = mappable;
-+	nvbo->no_vm = no_vm;
-+	nvbo->tile_mode = tile_mode;
-+	nvbo->tile_flags = tile_flags;
-+
-+	if (!nvbo->mappable && (flags & TTM_PL_FLAG_VRAM))
-+		flags |= TTM_PL_FLAG_PRIV0;
-+
-+	align >>= PAGE_SHIFT;
-+
-+	size = (size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
-+	if (dev_priv->card_type == NV_50) {
-+		size = (size + 65535) & ~65535;
-+		if (align < (65536 / PAGE_SIZE))
-+			align = (65536 / PAGE_SIZE);
-+	}
-+
-+	nvbo->channel = chan;
-+	ret = ttm_buffer_object_init(&dev_priv->ttm.bdev, &nvbo->bo, size,
-+				     ttm_bo_type_device, flags, align,
-+				     0, false, NULL, size, nouveau_bo_del_ttm);
-+	nvbo->channel = NULL;
-+	if (ret) {
-+		/* ttm will call nouveau_bo_del_ttm if it fails.. */
-+		return ret;
-+	}
-+
-+	*pnvbo = nvbo;
-+	return 0;
-+}
-+
-+int
-+nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype)
-+{
-+	struct ttm_buffer_object *bo = &nvbo->bo;
-+	int ret;
-+
-+	if (nvbo->pin_refcnt &&
-+	    (bo->proposed_placement & TTM_PL_MASK_MEM) != memtype) {
-+		NV_ERROR(nouveau_bdev(bo->bdev)->dev,
-+			 "bo %p pinned elsewhere: 0x%08x vs 0x%08x\n", bo,
-+			 bo->proposed_placement, memtype);
-+		return -EINVAL;
-+	}
-+
-+	if (nvbo->pin_refcnt++)
-+		return 0;
-+
-+	bo->proposed_placement &= ~TTM_PL_MASK_MEM;
-+	bo->proposed_placement |= (memtype & TTM_PL_MASK_MEM);
-+	bo->proposed_placement |= TTM_PL_FLAG_NO_EVICT;
-+
-+	ret = ttm_bo_reserve(bo, false, false, false, 0);
-+	if (ret)
-+		goto out;
-+
-+	ret = ttm_buffer_object_validate(bo, bo->proposed_placement,
-+					 false, false);
-+	ttm_bo_unreserve(bo);
-+out:
-+	if (unlikely(ret))
-+		nvbo->pin_refcnt--;
-+	return ret;
-+}
-+
-+int
-+nouveau_bo_unpin(struct nouveau_bo *nvbo)
-+{
-+	struct ttm_buffer_object *bo = &nvbo->bo;
-+	int ret;
-+
-+	if (--nvbo->pin_refcnt)
-+		return 0;
-+
-+	bo->proposed_placement &= ~TTM_PL_FLAG_NO_EVICT;
-+
-+	ret = ttm_bo_reserve(bo, false, false, false, 0);
-+	if (ret)
-+		return ret;
-+
-+	ret = ttm_buffer_object_validate(bo, bo->proposed_placement,
-+					 false, false);
-+	ttm_bo_unreserve(bo);
-+	return ret;
-+}
-+
-+int
-+nouveau_bo_map(struct nouveau_bo *nvbo)
-+{
-+	int ret;
-+
-+	ret = ttm_bo_reserve(&nvbo->bo, false, false, false, 0);
++	ret = nouveau_bo_new(dev, chan, size, align, flags, tile_mode,
++			     tile_flags, no_vm, mappable, pnvbo);
 +	if (ret)
 +		return ret;
++	nvbo = *pnvbo;
 +
-+	ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, &nvbo->kmap);
-+	ttm_bo_unreserve(&nvbo->bo);
-+	return ret;
-+}
-+
-+void
-+nouveau_bo_unmap(struct nouveau_bo *nvbo)
-+{
-+	if (nvbo->kmap.virtual) {
-+		ttm_bo_kunmap(&nvbo->kmap);
-+		nvbo->kmap.virtual = NULL;
++	nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size);
++	if (!nvbo->gem) {
++		nouveau_bo_ref(NULL, pnvbo);
++		return -ENOMEM;
 +	}
++
++	nvbo->bo.persistant_swap_storage = nvbo->gem->filp;
++	nvbo->gem->driver_private = nvbo;
++	return 0;
 +}
 +
 +static int
@@ -10551,7 +10574,6 @@ index 0000000..9573bd8
 +	struct drm_nouveau_private *dev_priv = dev->dev_private;
 +	struct drm_nouveau_gem_new *req = data;
 +	struct nouveau_bo *nvbo = NULL;
-+	struct drm_gem_object *gem;
 +	struct nouveau_channel *chan = NULL;
 +	uint32_t flags = 0;
 +	int ret = 0;
@@ -10589,23 +10611,14 @@ index 0000000..9573bd8
 +		return -EINVAL;
 +	}
 +
-+	ret = nouveau_bo_new(dev, chan, req->info.size, req->align, flags,
-+			     req->info.tile_mode, req->info.tile_flags, false,
-+			     !!(req->info.domain & NOUVEAU_GEM_DOMAIN_MAPPABLE),
-+			     &nvbo);
++	ret = nouveau_gem_new(dev, chan, req->info.size, req->align, flags,
++			      req->info.tile_mode, req->info.tile_flags, false,
++			      (req->info.domain & NOUVEAU_GEM_DOMAIN_MAPPABLE),
++			      &nvbo);
 +	if (ret)
 +		return ret;
 +
-+	gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size);
-+	if (!gem) {
-+		nouveau_bo_ref(NULL, &nvbo);
-+		return -ENOMEM;
-+	}
-+
-+	gem->driver_private = nvbo;
-+	nvbo->gem = gem;
-+
-+	ret = nouveau_gem_info(gem, &req->info);
++	ret = nouveau_gem_info(nvbo->gem, &req->info);
 +	if (ret)
 +		goto out;
 +
@@ -13079,10 +13092,10 @@ index 0000000..f55ae7a
 +}
 diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
 new file mode 100644
-index 0000000..52fc92d
+index 0000000..f065207
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
-@@ -0,0 +1,613 @@
+@@ -0,0 +1,616 @@
 +/*
 + * Copyright (C) 2006 Ben Skeggs.
 + *
@@ -13160,6 +13173,8 @@ index 0000000..52fc92d
 +
 +	if (status)
 +		NV_ERROR(dev, "display irqs still pending: 0x%08x\n", status);
++
++	nv_wr32(NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE);
 +}
 +
 +void
@@ -13686,6 +13701,7 @@ index 0000000..52fc92d
 +
 +	if (status & (NV_PMC_INTR_0_NV50_DISPLAY_PENDING |
 +		      NV_PMC_INTR_0_NV50_I2C_PENDING)) {
++		nv_wr32(NV03_PMC_INTR_EN_0, 0);
 +		schedule_work(&dev_priv->irq_work);
 +		status &= ~(NV_PMC_INTR_0_NV50_DISPLAY_PENDING |
 +			    NV_PMC_INTR_0_NV50_I2C_PENDING);
@@ -15540,10 +15556,10 @@ index 0000000..2465b98
 +}
 diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
 new file mode 100644
-index 0000000..158935b
+index 0000000..310a540
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
-@@ -0,0 +1,841 @@
+@@ -0,0 +1,847 @@
 +
 +
 +#define NV03_BOOT_0                                        0x00100000
@@ -16230,20 +16246,21 @@ index 0000000..158935b
 +#define NV50_PDISPLAY__LEN                                         0x1
 +#define NV50_PDISPLAY__ESIZE                                   0x10000
 +#    define NV50_PDISPLAY_OBJECTS                           0x00610010
-+#    define NV50_PDISPLAY_SUPERVISOR                        0x00610024
-+#        define NV50_PDISPLAY_SUPERVISOR_CRTCn              0x0000000c
-+#        define NV50_PDISPLAY_SUPERVISOR_CRTCn__SHIFT                2
-+#        define NV50_PDISPLAY_SUPERVISOR_CRTC0                  (1<<2)
-+#        define NV50_PDISPLAY_SUPERVISOR_CRTC1                  (1<<3)
-+#        define NV50_PDISPLAY_SUPERVISOR_CLK_MASK           0x00000070
-+#        define NV50_PDISPLAY_SUPERVISOR_CLK_MASK__SHIFT             4
-+#        define NV50_PDISPLAY_SUPERVISOR_CLK_UPDATE             (1<<5)
-+#    define NV50_PDISPLAY_SUPERVISOR_INTR                   0x0061002c
-+#        define NV50_PDISPLAY_SUPERVISOR_INTR_VBLANK_CRTC0      (1<<2)
-+#        define NV50_PDISPLAY_SUPERVISOR_INTR_VBLANK_CRTC1      (1<<3)
-+#        define NV50_PDISPLAY_SUPERVISOR_INTR_UNK1              (1<<4)
-+#        define NV50_PDISPLAY_SUPERVISOR_INTR_CLK_UPDATE        (1<<5)
-+#        define NV50_PDISPLAY_SUPERVISOR_INTR_UNK4              (1<<6)
++#    define NV50_PDISPLAY_INTR                              0x00610024
++#        define NV50_PDISPLAY_INTR_VBLANK_CRTCn             0x0000000c
++#        define NV50_PDISPLAY_INTR_VBLANK_CRTCn__SHIFT               2
++#        define NV50_PDISPLAY_INTR_VBLANK_CRTC(n)     (1 << ((n) + 2))
++#        define NV50_PDISPLAY_INTR_VBLANK_CRTC0                 (1<<2)
++#        define NV50_PDISPLAY_INTR_VBLANK_CRTC1                 (1<<3)
++#        define NV50_PDISPLAY_INTR_CLK_UNK10                    (1<<4)
++#        define NV50_PDISPLAY_INTR_CLK_UNK20                    (1<<5)
++#        define NV50_PDISPLAY_INTR_CLK_UNK40                    (1<<6)
++#    define NV50_PDISPLAY_INTR_EN                           0x0061002c
++#        define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC0              (1<<2)
++#        define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC1              (1<<3)
++#        define NV50_PDISPLAY_INTR_EN_CLK_UNK10                 (1<<4)
++#        define NV50_PDISPLAY_INTR_EN_CLK_UNK20                 (1<<5)
++#        define NV50_PDISPLAY_INTR_EN_CLK_UNK40                 (1<<6)
 +#    define NV50_PDISPLAY_UNK30_CTRL                        0x00610030
 +#        define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK0           (1<<9)
 +#        define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK1          (1<<10)
@@ -16283,58 +16300,63 @@ index 0000000..158935b
 +#    define NV50_PDISPLAY_RAM_AMOUNT                        0x00610384
 +#    define NV50_PDISPLAY_UNK_388                           0x00610388
 +#    define NV50_PDISPLAY_UNK_38C                           0x0061038c
-+#    define NV50_PDISPLAY_CRTC_VAL                          0x00610a00
-+#    define NV50_PDISPLAY_CRTC_VAL__LEN                            0x2
-+#            define NV50_PDISPLAY_CRTC_VAL_UNK_900(i,j) (0x00610a18+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_CLUT_MODE(i,j) (0x00610a24+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_INTERLACE(i,j) (0x00610a48+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_SCALE_CTRL(i,j) (0x00610a50+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_CURSOR_CTRL(i,j) (0x00610a58+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_UNK_904(i,j) (0x00610ab8+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_DEPTH(i,j) (0x00610ac8+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_CLOCK(i,j) (0x00610ad0+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_COLOR_CTRL(i,j) (0x00610ae0+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_SYNC_START_TO_BLANK_END(i,j) (0x00610ae8+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_MODE_UNK1(i,j) (0x00610af0+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_DISPLAY_TOTAL(i,j) (0x00610af8+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_SYNC_DURATION(i,j) (0x00610b00+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_MODE_UNK2(i,j) (0x00610b08+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_UNK_828(i,j) (0x00610b10+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_FB_SIZE(i,j) (0x00610b18+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_FB_PITCH(i,j) (0x00610b20+(i)*0x540+(j)*0x4)
-+#                define NV50_PDISPLAY_CRTC_VAL_FB_PITCH_LINEAR_FB (1<<20)
-+#            define NV50_PDISPLAY_CRTC_VAL_FB_POS(i,j) (0x00610b28+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_SCALE_CENTER_OFFSET(i,j) (0x00610b38+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_REAL_RES(i,j) (0x00610b40+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_SCALE_RES1(i,j) (0x00610b48+(i)*0x540+(j)*0x4)
-+#            define NV50_PDISPLAY_CRTC_VAL_SCALE_RES2(i,j) (0x00610b50+(i)*0x540+(j)*0x4)
-+
-+
-+#            define NV50_PDISPLAY_DAC_VAL_MODE_CTRL(i,j) (0x00610b58+(i)*0x8+(j)*0x4)
-+
-+
-+#            define NV50_PDISPLAY_SOR_VAL_MODE_CTRL(i,j) (0x00610b70+(i)*0x8+(j)*0x4)
-+
-+
-+#            define NV50_PDISPLAY_DAC_VAL_MODE_CTRL2(i,j) (0x00610bdc+(i)*0x8+(j)*0x4)
-+
-+
-+#    define NV50_PDISPLAY_CRTC_CLK                          0x00614000
-+#    define NV50_PDISPLAY_CRTC_CLK__LEN                            0x2
-+#        define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(i) (0x00614100+(i)*0x800)
-+#            define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED 0x00000600
-+#            define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED__SHIFT 9
-+#        define NV50_PDISPLAY_CRTC_CLK_VPLL_A(i) (0x00614104+(i)*0x800)
-+#        define NV50_PDISPLAY_CRTC_CLK_VPLL_B(i) (0x00614108+(i)*0x800)
-+#        define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL2(i) (0x00614200+(i)*0x800)
-+
-+#    define NV50_PDISPLAY_DAC_CLK                           0x00614000
-+#    define NV50_PDISPLAY_DAC_CLK__LEN                             0x3
-+#        define NV50_PDISPLAY_DAC_CLK_CLK_CTRL2(i) (0x00614280+(i)*0x800)
-+
-+#    define NV50_PDISPLAY_SOR_CLK                           0x00614000
-+#    define NV50_PDISPLAY_SOR_CLK__LEN                             0x3
-+#        define NV50_PDISPLAY_SOR_CLK_CLK_CTRL2(i) (0x00614300+(i)*0x800)
++#define NV50_PDISPLAY_CRTC_P(i,r)         ((i) * 0x540 + NV50_PDISPLAY_CRTC_##r)
++#define NV50_PDISPLAY_CRTC_C(i,r)     (4 + (i) * 0x540 + NV50_PDISPLAY_CRTC_##r)
++#define NV50_PDISPLAY_CRTC_UNK_0A18 /* mthd 0x0900 */                0x00610a18
++#define NV50_PDISPLAY_CRTC_CLUT_MODE                                 0x00610a24
++#define NV50_PDISPLAY_CRTC_INTERLACE                                 0x00610a48
++#define NV50_PDISPLAY_CRTC_SCALE_CTRL                                0x00610a50
++#define NV50_PDISPLAY_CRTC_CURSOR_CTRL                               0x00610a58
++#define NV50_PDISPLAY_CRTC_UNK0A78 /* mthd 0x0904 */                 0x00610a78
++#define NV50_PDISPLAY_CRTC_UNK0AB8                                   0x00610ab8
++#define NV50_PDISPLAY_CRTC_DEPTH                                     0x00610ac8
++#define NV50_PDISPLAY_CRTC_CLOCK                                     0x00610ad0
++#define NV50_PDISPLAY_CRTC_COLOR_CTRL                                0x00610ae0
++#define NV50_PDISPLAY_CRTC_SYNC_START_TO_BLANK_END                   0x00610ae8
++#define NV50_PDISPLAY_CRTC_MODE_UNK1                                 0x00610af0
++#define NV50_PDISPLAY_CRTC_DISPLAY_TOTAL                             0x00610af8
++#define NV50_PDISPLAY_CRTC_SYNC_DURATION                             0x00610b00
++#define NV50_PDISPLAY_CRTC_MODE_UNK2                                 0x00610b08
++#define NV50_PDISPLAY_CRTC_UNK_0B10 /* mthd 0x0828 */                0x00610b10
++#define NV50_PDISPLAY_CRTC_FB_SIZE                                   0x00610b18
++#define NV50_PDISPLAY_CRTC_FB_PITCH                                  0x00610b20
++#define NV50_PDISPLAY_CRTC_FB_PITCH_LINEAR                           0x00100000
++#define NV50_PDISPLAY_CRTC_FB_POS                                    0x00610b28
++#define NV50_PDISPLAY_CRTC_SCALE_CENTER_OFFSET                       0x00610b38
++#define NV50_PDISPLAY_CRTC_REAL_RES                                  0x00610b40
++#define NV50_PDISPLAY_CRTC_SCALE_RES1                                0x00610b48
++#define NV50_PDISPLAY_CRTC_SCALE_RES2                                0x00610b50
++
++#define NV50_PDISPLAY_DAC_MODE_CTRL_P(i)                (0x00610b58 + (i) * 0x8)
++#define NV50_PDISPLAY_DAC_MODE_CTRL_C(i)                (0x00610b5c + (i) * 0x8)
++#define NV50_PDISPLAY_SOR_MODE_CTRL_P(i)                (0x00610b70 + (i) * 0x8)
++#define NV50_PDISPLAY_SOR_MODE_CTRL_C(i)                (0x00610b74 + (i) * 0x8)
++#define NV50_PDISPLAY_DAC_MODE_CTRL2_P(i)               (0x00610bdc + (i) * 0x8)
++#define NV50_PDISPLAY_DAC_MODE_CTRL2_C(i)               (0x00610be0 + (i) * 0x8)
++
++#define NV90_PDISPLAY_SOR_MODE_CTRL_P(i)                (0x00610794 + (i) * 0x8)
++#define NV90_PDISPLAY_SOR_MODE_CTRL_C(i)                (0x00610798 + (i) * 0x8)
++#define NV90_PDISPLAY_DAC_MODE_CTRL_P(i)                (0x00610b58 + (i) * 0x8)
++#define NV90_PDISPLAY_DAC_MODE_CTRL_C(i)                (0x00610b5c + (i) * 0x8)
++#define NV90_PDISPLAY_DAC_MODE_CTRL2_P(i)               (0x00610b80 + (i) * 0x8)
++#define NV90_PDISPLAY_DAC_MODE_CTRL2_C(i)               (0x00610b84 + (i) * 0x8)
++
++#define NV50_PDISPLAY_CRTC_CLK                                       0x00614000
++#define NV50_PDISPLAY_CRTC_CLK__LEN                                         0x2
++#define NV50_PDISPLAY_CRTC_CLK_CTRL1(i)                 ((i) * 0x800 + 0x614100)
++#define NV50_PDISPLAY_CRTC_CLK_CTRL1_CONNECTED                       0x00000600
++#define NV50_PDISPLAY_CRTC_CLK_CTRL1_CONNECTED__SHIFT                         9
++#define NV50_PDISPLAY_CRTC_CLK_VPLL_A(i)                ((i) * 0x800 + 0x614104)
++#define NV50_PDISPLAY_CRTC_CLK_VPLL_B(i)                ((i) * 0x800 + 0x614108)
++#define NV50_PDISPLAY_CRTC_CLK_CTRL2(i)                 ((i) * 0x800 + 0x614200)
++
++#define NV50_PDISPLAY_DAC_CLK                                        0x00614000
++#define NV50_PDISPLAY_DAC_CLK__LEN                                          0x3
++#define NV50_PDISPLAY_DAC_CLK_CTRL2(i)                  ((i) * 0x800 + 0x614280)
++
++#define NV50_PDISPLAY_SOR_CLK                                        0x00614000
++#define NV50_PDISPLAY_SOR_CLK__LEN                                          0x3
++#define NV50_PDISPLAY_SOR_CLK_CTRL2(i)                  ((i) * 0x800 + 0x614300)
 +
 +#    define NV50_PDISPLAY_DAC_REGS                          0x0061a000
 +#    define NV50_PDISPLAY_DAC_REGS__LEN                            0x3
@@ -16722,10 +16744,10 @@ index 0000000..1380845
 +}
 diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
 new file mode 100644
-index 0000000..ba66375
+index 0000000..5d91c3f
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_state.c
-@@ -0,0 +1,966 @@
+@@ -0,0 +1,1031 @@
 +/*
 + * Copyright 2005 Stephane Marchesin
 + * Copyright 2008 Stuart Bennett
@@ -16764,6 +16786,49 @@ index 0000000..ba66375
 +static int nouveau_stub_init(struct drm_device *dev) { return 0; }
 +static void nouveau_stub_takedown(struct drm_device *dev) {}
 +
++static int
++sfbhack_init(struct drm_device *dev)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nouveau_bo *nvbo = NULL;
++	int ret, size;
++
++	if (dev_priv->sfb_gem)
++		return 0;
++
++	size = nouveau_mem_fb_amount(dev);
++	if (size > drm_get_resource_len(dev, 1))
++		size = drm_get_resource_len(dev, 1);
++	size >>= 1;
++
++	ret = nouveau_gem_new(dev, dev_priv->channel, size, 0, TTM_PL_FLAG_VRAM,
++			      0, 0x0000, false, true, &nvbo);
++	if (ret)
++		return ret;
++
++	ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM);
++	if (ret) {
++		nouveau_bo_ref(NULL, &nvbo);
++		return ret;
++	}
++
++	dev_priv->sfb_gem = nvbo->gem;
++	return 0;
++}
++
++static void
++sfbhack_takedown(struct drm_device *dev)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++
++	if (dev_priv->sfb_gem) {
++		mutex_lock(&dev->struct_mutex);
++		drm_gem_object_unreference(dev_priv->sfb_gem);
++		mutex_unlock(&dev->struct_mutex);
++		dev_priv->sfb_gem = NULL;
++	}
++}
++
 +static int nouveau_init_engine_ptrs(struct drm_device *dev)
 +{
 +	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -17354,6 +17419,8 @@ index 0000000..ba66375
 +/* KMS: we need mmio at load time, not when the first drm client opens. */
 +void nouveau_lastclose(struct drm_device *dev)
 +{
++	sfbhack_takedown(dev);
++
 +	if (drm_core_check_feature(dev, DRIVER_MODESET))
 +		return;
 +
@@ -17392,6 +17459,8 @@ index 0000000..ba66375
 +{
 +	struct drm_nouveau_private *dev_priv = dev->dev_private;
 +	struct drm_nouveau_getparam *getparam = data;
++	uint32_t sfb_handle;
++	int ret;
 +
 +	NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
 +
@@ -17441,6 +17510,24 @@ index 0000000..ba66375
 +	case NOUVEAU_GETPARAM_VM_VRAM_BASE:
 +		getparam->value = dev_priv->vm_vram_base;
 +		break;
++	case 0xdeadcafe00000001: /* NOUVEAU_GETPARAM_SHAREDFB_HANDLE */
++		ret = sfbhack_init(dev);
++		if (ret)
++			return ret;
++
++		ret = drm_gem_handle_create(file_priv, dev_priv->sfb_gem,
++					    &sfb_handle);
++		if (ret)
++			return ret;
++		getparam->value = sfb_handle;
++		break;
++	case 0xdeadcafe00000002: /* NOUVEAU_GETPARAM_SHAREDFB_SIZE */
++		ret = sfbhack_init(dev);
++		if (ret)
++			return ret;
++
++		getparam->value = dev_priv->sfb_gem->size;
++		break;
 +	default:
 +		NV_ERROR(dev, "unknown parameter %lld\n", getparam->param);
 +		return -EINVAL;
@@ -26930,10 +27017,10 @@ index 0000000..e1595f9
 +}
 diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
 new file mode 100644
-index 0000000..ecec1a9
+index 0000000..d8e8f1b
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
-@@ -0,0 +1,822 @@
+@@ -0,0 +1,807 @@
 +/*
 + * Copyright (C) 2008 Maarten Maathuis.
 + * All Rights Reserved.
@@ -27235,11 +27322,10 @@ index 0000000..ecec1a9
 +	return 0;
 +}
 +
-+static int
-+nv50_crtc_set_clock(struct nouveau_crtc *crtc, struct drm_display_mode *mode)
++int
++nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
 +{
-+	uint32_t pll_reg = NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index);
-+	struct drm_device *dev = crtc->base.dev;
++	uint32_t pll_reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
 +	struct nouveau_pll_vals pll;
 +	struct pll_lims limits;
 +	uint32_t reg1, reg2;
@@ -27266,7 +27352,7 @@ index 0000000..ecec1a9
 +		limits.max_usable_log2p = 6;
 +	}
 +
-+	ret = nouveau_calc_pll_mnp(dev, &limits, mode->clock, &pll);
++	ret = nouveau_calc_pll_mnp(dev, &limits, pclk, &pll);
 +	if (ret <= 0)
 +		return ret;
 +
@@ -27287,18 +27373,6 @@ index 0000000..ecec1a9
 +	return 0;
 +}
 +
-+static int nv50_crtc_set_clock_mode(struct nouveau_crtc *crtc)
-+{
-+	struct drm_device *dev = crtc->base.dev;
-+
-+	NV_DEBUG(dev, "\n");
-+
-+	/* This acknowledges a clock request. */
-+	nv_wr32(NV50_PDISPLAY_CRTC_CLK_CLK_CTRL2(crtc->index), 0);
-+
-+	return 0;
-+}
-+
 +static void nv50_crtc_destroy(struct drm_crtc *drm_crtc)
 +{
 +	struct drm_device *dev = drm_crtc->dev;
@@ -27742,8 +27816,6 @@ index 0000000..ecec1a9
 +	/* set function pointers */
 +	crtc->set_dither = nv50_crtc_set_dither;
 +	crtc->set_scale = nv50_crtc_set_scale;
-+	crtc->set_clock = nv50_crtc_set_clock;
-+	crtc->set_clock_mode = nv50_crtc_set_clock_mode;
 +
 +	crtc->mode_set.crtc = &crtc->base;
 +	crtc->mode_set.connectors = (struct drm_connector **)(crtc + 1);
@@ -27942,10 +28014,10 @@ index 0000000..23234e5
 +
 diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c
 new file mode 100644
-index 0000000..59296fd
+index 0000000..2da910e
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nv50_dac.c
-@@ -0,0 +1,298 @@
+@@ -0,0 +1,303 @@
 +/*
 + * Copyright (C) 2008 Maarten Maathuis.
 + * All Rights Reserved.
@@ -28010,7 +28082,7 @@ index 0000000..59296fd
 +
 +	NV_DEBUG(dev, "or %d\n", encoder->or);
 +
-+	nv_wr32(NV50_PDISPLAY_DAC_CLK_CLK_CTRL2(encoder->or),  0);
++	nv_wr32(NV50_PDISPLAY_DAC_CLK_CTRL2(encoder->or),  0);
 +	return 0;
 +}
 +
@@ -28159,6 +28231,11 @@ index 0000000..59296fd
 +
 +	NV_DEBUG(dev, "or %d\n", encoder->or);
 +
++	ret = dev_priv->in_modeset;
++	dev_priv->in_modeset = false;
++	nv50_dac_dpms(drm_encoder, DRM_MODE_DPMS_ON);
++	dev_priv->in_modeset = ret;
++
 +	if (crtc->index == 1)
 +		mode_ctl |= NV50_DAC_MODE_CTRL_CRTC1;
 +	else
@@ -28246,10 +28323,10 @@ index 0000000..59296fd
 +
 diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
 new file mode 100644
-index 0000000..71bbd89
+index 0000000..5c38c78
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nv50_display.c
-@@ -0,0 +1,637 @@
+@@ -0,0 +1,728 @@
 +/*
 + * Copyright (C) 2008 Maarten Maathuis.
 + * All Rights Reserved.
@@ -28401,8 +28478,8 @@ index 0000000..71bbd89
 +	/* The precise purpose is unknown, i suspect it has something to do
 +	 * with text mode.
 +	 */
-+	if (nv_rd32(NV50_PDISPLAY_SUPERVISOR) & 0x100) {
-+		nv_wr32(NV50_PDISPLAY_SUPERVISOR, 0x100);
++	if (nv_rd32(NV50_PDISPLAY_INTR) & 0x100) {
++		nv_wr32(NV50_PDISPLAY_INTR, 0x100);
 +		nv_wr32(0x006194e8, nv_rd32(0x006194e8) & ~1);
 +		if (!nv_wait(0x006194e8, 2, 0)) {
 +			NV_ERROR(dev, "timeout: (0x6194e8 & 2) != 0\n");
@@ -28496,7 +28573,9 @@ index 0000000..71bbd89
 +	FIRE_RING (&evo->chan);
 +
 +	/* enable clock change interrupts. */
-+	nv_wr32(NV50_PDISPLAY_SUPERVISOR_INTR, 0x70);
++	nv_wr32(NV50_PDISPLAY_INTR_EN, (NV50_PDISPLAY_INTR_EN_CLK_UNK10 |
++					NV50_PDISPLAY_INTR_EN_CLK_UNK20 |
++					NV50_PDISPLAY_INTR_EN_CLK_UNK40));
 +
 +	/* enable hotplug interrupts */
 +	nv_wr32(NV50_PCONNECTOR_HOTPLUG_CTRL, 0x7FFF7FFF);
@@ -28525,25 +28604,22 @@ index 0000000..71bbd89
 +	OUT_RING  (&dev_priv->evo.chan, 0);
 +	FIRE_RING (&dev_priv->evo.chan);
 +
-+	/* Almost like ack'ing a vblank interrupt, maybe in the spirit of cleaning up? */
++	/* Almost like ack'ing a vblank interrupt, maybe in the spirit of
++	 * cleaning up?
++	 */
 +	list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) {
 +		struct nouveau_crtc *crtc = to_nouveau_crtc(drm_crtc);
++		uint32_t mask = NV50_PDISPLAY_INTR_VBLANK_CRTC(crtc->index);
 +
-+		if (crtc->base.enabled) {
-+			uint32_t mask;
-+
-+			if (crtc->index == 1)
-+				mask = NV50_PDISPLAY_SUPERVISOR_CRTC1;
-+			else
-+				mask = NV50_PDISPLAY_SUPERVISOR_CRTC0;
++		if (!crtc->base.enabled)
++			continue;
 +
-+			nv_wr32(NV50_PDISPLAY_SUPERVISOR, mask);
-+			if (!nv_wait(NV50_PDISPLAY_SUPERVISOR, mask, mask)) {
-+				NV_ERROR(dev, "timeout: (0x610024 & 0x%08x) == "
-+					  "0x%08x\n", mask, mask);
-+				NV_ERROR(dev, "0x610024 = 0x%08x\n",
-+					  nv_rd32(0x610024));
-+			}
++		nv_wr32(NV50_PDISPLAY_INTR, mask);
++		if (!nv_wait(NV50_PDISPLAY_INTR, mask, mask)) {
++			NV_ERROR(dev, "timeout: (0x610024 & 0x%08x) == "
++				      "0x%08x\n", mask, mask);
++			NV_ERROR(dev, "0x610024 = 0x%08x\n",
++				 nv_rd32(NV50_PDISPLAY_INTR));
 +		}
 +	}
 +
@@ -28564,9 +28640,8 @@ index 0000000..71bbd89
 +		}
 +	}
 +
-+	/* disable clock change interrupts. */
-+	nv_wr32(NV50_PDISPLAY_SUPERVISOR_INTR,
-+		nv_rd32(NV50_PDISPLAY_SUPERVISOR_INTR) & ~0x70);
++	/* disable interrupts. */
++	nv_wr32(NV50_PDISPLAY_INTR_EN, 0x00000000);
 +
 +	/* disable hotplug interrupts */
 +	nv_wr32(NV50_PCONNECTOR_HOTPLUG_INTR, 0);
@@ -28726,14 +28801,14 @@ index 0000000..71bbd89
 +		}
 +
 +		if (clock_change)
-+			crtc->set_clock(crtc, crtc->mode);
++			nv50_crtc_set_clock(dev, crtc->index, crtc->mode->clock);
 +
 +		NV_DEBUG(dev, "index %d clock_change %d clock_ack %d\n", crtc_index, clock_change, clock_ack);
 +
 +		if (!clock_ack)
 +			continue;
 +
-+		crtc->set_clock_mode(crtc);
++		nv_wr32(NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc->index), 0);
 +
 +		list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) {
 +			encoder = to_nouveau_encoder(drm_encoder);
@@ -28750,149 +28825,242 @@ index 0000000..71bbd89
 +void
 +nv50_display_irq_handler_old(struct drm_device *dev)
 +{
-+	uint32_t super = nv_rd32(NV50_PDISPLAY_SUPERVISOR);
++	uint32_t super = nv_rd32(NV50_PDISPLAY_INTR);
 +	uint32_t state;
 +
 +	NV_DEBUG(dev, "0x610024 = 0x%08x\n", super);
 +
 +	if (super & 0x0000000c)
-+		nv_wr32(NV50_PDISPLAY_SUPERVISOR, super & 0x0000000c);
++		nv_wr32(NV50_PDISPLAY_INTR, super & 0x0000000c);
 +
-+	state   = (super & NV50_PDISPLAY_SUPERVISOR_CLK_MASK);
-+	state >>= NV50_PDISPLAY_SUPERVISOR_CLK_MASK__SHIFT;
++	state = (super >> 4) & 7;
 +	if (state) {
 +		if (state == 2)
 +			nv50_display_vclk_update(dev);
 +
-+		nv_wr32(NV50_PDISPLAY_SUPERVISOR,
-+			(super & NV50_PDISPLAY_SUPERVISOR_CLK_MASK));
++		nv_wr32(NV50_PDISPLAY_INTR, super & 0x00000070);
 +		nv_wr32(NV50_PDISPLAY_UNK30_CTRL,
 +			NV50_PDISPLAY_UNK30_CTRL_PENDING);
 +	}
 +}
 +
 +static int
-+nv50_crtc_encoder_from_610030(struct drm_device *dev,
-+                              struct nouveau_crtc **pcrtc,
-+                              struct nouveau_encoder **pencoder)
++nv50_display_irq_head(struct drm_device *dev, int *phead,
++		      struct dcb_entry **pdcbent)
 +{
-+	struct drm_encoder *drm_encoder;
-+	struct nouveau_encoder *encoder;
-+	struct drm_crtc *drm_crtc;
-+	struct nouveau_crtc *crtc;
-+	uint32_t unk30 = nv_rd32(0x610030);
-+	int mask = (unk30 >> 9) & 3;
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	uint32_t unk30 = nv_rd32(NV50_PDISPLAY_UNK30_CTRL);
++	uint32_t dac = 0, sor = 0;
++	int head, i, or;
 +
-+	*pcrtc = NULL;
-+	*pencoder = NULL;
++	/* We're assuming that head 0 *or* head 1 will be active here,
++	 * and not both.  I'm not sure if the hw will even signal both
++	 * ever, but it definitely shouldn't for us as we commit each
++	 * CRTC separately, and submission will be blocked by the GPU
++	 * until we handle each in turn.
++	 */
++	NV_DEBUG(dev, "0x610030: 0x%08x\n", unk30);
++	head = ffs((unk30 >> 9) & 3) - 1;
++	if (head < 0) {
++		NV_ERROR(dev, "no active heads: 0x%08x\n", nv_rd32(0x610030));
++		return -EINVAL;
++	}
 +
-+	list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) {
-+		crtc = to_nouveau_crtc(drm_crtc);
-+		if (mask & (1 << crtc->index))
-+			break;
++	/* This assumes CRTCs are never bound to multiple encoders, which
++	 * should be the case.
++	 */
++	for (i = 0; i < 3; i++) {
++		if (nv_rd32(NV50_PDISPLAY_DAC_MODE_CTRL_P(i)) & (1 << head))
++			dac |= (1 << i);
 +	}
 +
-+	if (!(mask & (1 << crtc->index)))
-+		return -EINVAL;
++	if (dev_priv->chipset < 0x90 || dev_priv->chipset == 0x92 ||
++	    dev_priv->chipset == 0xa0) {
++		for (i = 0; i < 4; i++) {
++			if (nv_rd32(NV50_PDISPLAY_SOR_MODE_CTRL_P(i)) & (1 << head))
++				sor |= (1 << i);
++		}
++	} else {
++		for (i = 0; i < 4; i++) {
++			if (nv_rd32(NV90_PDISPLAY_SOR_MODE_CTRL_P(i)) & (1 << head))
++				sor |= (1 << i);
++		}
++	}
 +
-+	list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) {
-+		encoder = to_nouveau_encoder(drm_encoder);
-+		if (drm_encoder->crtc == drm_crtc)
-+			break;
++	NV_DEBUG(dev, "dac: 0x%08x, sor: 0x%08x\n", dac, sor);
++
++	if (dac && sor) {
++		NV_ERROR(dev, "multiple encoders: 0x%08x 0x%08x\n", dac, sor);
++		return -1;
++	} else
++	if (dac) {
++		or = ffs(dac) - 1;
++		if (dac & ~(1 << or)) {
++			NV_ERROR(dev, "multiple DAC: 0x%08x\n", dac);
++			return -1;
++		}
++	} else
++	if (sor) {
++		or = ffs(sor) - 1;
++		if (sor & ~(1 << or)) {
++			NV_ERROR(dev, "multiple SOR: 0x%08x\n", sor);
++			return -1;
++		}
++	} else {
++		NV_ERROR(dev, "no encoders!\n");
++		return -1;
 +	}
 +
-+	if (drm_encoder->crtc != drm_crtc)
-+		return -EINVAL;
++	for (i = 0; i < dev_priv->vbios->dcb->entries; i++) {
++		struct dcb_entry *dcbent = &dev_priv->vbios->dcb->entry[i];
++
++		if (dac && (dcbent->type != OUTPUT_ANALOG &&
++			    dcbent->type != OUTPUT_TV))
++			continue;
++		else
++		if (sor && (dcbent->type != OUTPUT_TMDS &&
++			    dcbent->type != OUTPUT_LVDS))
++			continue;
++
++		if (dcbent->or & (1 << or)) {
++			*phead = head;
++			*pdcbent = dcbent;
++			return 0;
++		}
++	}
 +
-+	*pcrtc = crtc;
-+	*pencoder = encoder;
++	NV_ERROR(dev, "no DCB entry for %d %d\n", dac != 0, or);
 +	return 0;
 +}
 +
-+void
-+nv50_display_irq_handler(struct drm_device *dev)
++static void
++nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
++{
++	nv_wr32(NV50_PDISPLAY_INTR, intr & NV50_PDISPLAY_INTR_VBLANK_CRTCn);
++}
++
++static void
++nv50_display_unk10_handler(struct drm_device *dev)
++{
++	struct dcb_entry *dcbent;
++	int head, ret;
++
++	ret = nv50_display_irq_head(dev, &head, &dcbent);
++	if (ret)
++		goto ack;
++
++	nv_wr32(0x619494, nv_rd32(0x619494) & ~8);
++
++	nouveau_bios_run_display_table(dev, dcbent, -1);
++
++ack:
++	nv_wr32(NV50_PDISPLAY_INTR, NV50_PDISPLAY_INTR_CLK_UNK10);
++	nv_wr32(0x610030, 0x80000000);
++}
++
++static void
++nv50_display_unk20_handler(struct drm_device *dev)
 +{
 +	struct drm_nouveau_private *dev_priv = dev->dev_private;
-+	static struct nouveau_encoder *encoder = NULL;
-+	static struct nouveau_crtc *crtc = NULL;
 +	struct nvbios *bios = &dev_priv->VBIOS;
-+	uint32_t intr, tmp;
-+	int ret;
++	struct dcb_entry *dcbent;
++	uint32_t tmp, pclk;
++	int head, or, ret;
 +
-+	for (;;) {
-+		uint32_t unk20 = nv_rd32(0x610020); (void)unk20;
++	ret = nv50_display_irq_head(dev, &head, &dcbent);
++	if (ret)
++		goto ack;
++	or = ffs(dcbent->or) - 1;
++	pclk = nv_rd32(NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff;
 +
-+		intr = nv_rd32(0x610024);
-+		if (!intr)
-+			break;
++	NV_DEBUG(dev, "head %d pxclk: %dKHz\n", head, pclk);
 +
-+		ret = nv50_crtc_encoder_from_610030(dev, &crtc, &encoder);
-+		if (ret) {
-+			NV_ERROR(dev, "can't determine outputs: 0x%08x\n",
-+				 nv_rd32(0x610030));
-+			break;
-+		}
++	nouveau_bios_run_display_table(dev, dcbent, -2);
 +
-+		if (intr & ~0x0000007c) {
-+			NV_ERROR(dev, "unknown PDISPLAY_INTR: 0x%08x\n", intr);
-+			break;
-+		}
++	nv50_crtc_set_clock(dev, head, pclk);
 +
-+		if (intr & 0x00000010) {
-+			nv_wr32(0x619494, nv_rd32(0x619494) & ~8);
-+			nouveau_bios_run_display_table(dev, encoder->dcb, -1);
-+			nv_wr32(0x610024, 0x00000010);
-+			nv_wr32(0x610030, 0x80000000);
-+		} else
-+		if (intr & 0x00000020) {
-+			nouveau_bios_run_display_table(dev, encoder->dcb, -2);
-+			crtc->set_clock(crtc, crtc->mode);
-+			nouveau_bios_run_display_table(dev, encoder->dcb,
-+						       crtc->mode->clock);
-+
-+			tmp = nv_rd32(0x614200 + (crtc->index * 0x800));
-+			tmp &= ~0x000000f;
-+			nv_wr32(0x614200 + (crtc->index * 0x800), tmp);
++	nouveau_bios_run_display_table(dev, dcbent, pclk);
 +
-+			if (encoder->dcb->type != OUTPUT_ANALOG) {
-+				int tclk;
++	tmp = nv_rd32(NV50_PDISPLAY_CRTC_CLK_CTRL2(head));
++	tmp &= ~0x000000f;
++	nv_wr32(NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp);
 +
-+				if (encoder->dcb->type == OUTPUT_LVDS)
-+					tclk = bios->fp.duallink_transition_clk;
-+				else
-+					tclk = 165000;
++	if (dcbent->type != OUTPUT_ANALOG) {
++		int tclk;
 +
-+				tmp = nv_rd32(0x614300 + (encoder->or * 0x800));
-+				tmp &= ~0x00000f0f;
-+				if (crtc->mode->clock > tclk)
-+					tmp |= 0x00000101;
-+				nv_wr32(0x614300 + (encoder->or * 0x800), tmp);
-+			} else {
-+				nv_wr32(0x614280 + (encoder->or * 0x800), 0);
-+			}
++		if (dcbent->type == OUTPUT_LVDS)
++			tclk = bios->fp.duallink_transition_clk;
++		else
++			tclk = 165000;
 +
-+			nv_wr32(0x610024, 0x00000020);
-+			nv_wr32(0x610030, 0x80000000);
-+		} else
-+		if (intr & 0x00000040) {
-+			nouveau_bios_run_display_table(dev, encoder->dcb,
-+						       -crtc->mode->clock);
-+			nv_wr32(0x610024, 0x00000040);
-+			nv_wr32(0x610030, 0x80000000);
-+			nv_wr32(0x619494, nv_rd32(0x619494) | 8);
-+			continue;
-+		} else
-+		if (intr & 0x0000000c) {
-+			nv_wr32(0x610024, intr & 0x0000000c);
++		tmp = nv_rd32(NV50_PDISPLAY_SOR_CLK_CTRL2(or));
++		tmp &= ~0x00000f0f;
++		if (pclk > tclk)
++			tmp |= 0x00000101;
++		nv_wr32(NV50_PDISPLAY_SOR_CLK_CTRL2(or), tmp);
++	} else {
++		nv_wr32(NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0);
++	}
++
++ack:
++	nv_wr32(NV50_PDISPLAY_INTR, NV50_PDISPLAY_INTR_CLK_UNK20);
++	nv_wr32(0x610030, 0x80000000);
++}
++
++static void
++nv50_display_unk40_handler(struct drm_device *dev)
++{
++	struct dcb_entry *dcbent;
++	int head, pclk, ret;
++
++	ret = nv50_display_irq_head(dev, &head, &dcbent);
++	if (ret)
++		goto ack;
++	pclk = nv_rd32(NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff;
++
++	nouveau_bios_run_display_table(dev, dcbent, -pclk);
++
++ack:
++	nv_wr32(NV50_PDISPLAY_INTR, NV50_PDISPLAY_INTR_CLK_UNK40);
++	nv_wr32(0x610030, 0x80000000);
++	nv_wr32(0x619494, nv_rd32(0x619494) | 8);
++}
++
++void
++nv50_display_irq_handler(struct drm_device *dev)
++{
++	while (nv_rd32(NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
++		uint32_t unk20 = nv_rd32(0x610020);
++		uint32_t intr = nv_rd32(NV50_PDISPLAY_INTR);
++		(void)unk20;
++
++		if (!intr)
++			break;
++		NV_DEBUG(dev, "PDISPLAY_INTR 0x%08x\n", intr);
++
++		if (intr & NV50_PDISPLAY_INTR_CLK_UNK10)
++			nv50_display_unk10_handler(dev);
++		else
++		if (intr & NV50_PDISPLAY_INTR_CLK_UNK20)
++			nv50_display_unk20_handler(dev);
++		else
++		if (intr & NV50_PDISPLAY_INTR_CLK_UNK40)
++			nv50_display_unk40_handler(dev);
++		else
++		if (intr & NV50_PDISPLAY_INTR_VBLANK_CRTCn)
++			nv50_display_vblank_handler(dev, intr);
++		else {
++			NV_ERROR(dev, "unknown PDISPLAY_INTR: 0x%08x\n", intr);
++			nv_wr32(NV50_PDISPLAY_INTR, intr);
 +		}
 +	}
 +}
 diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h
 new file mode 100644
-index 0000000..af1d10e
+index 0000000..c069075
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nv50_display.h
-@@ -0,0 +1,44 @@
+@@ -0,0 +1,45 @@
 +/*
 + * Copyright (C) 2008 Maarten Maathuis.
 + * All Rights Reserved.
@@ -28935,6 +29103,7 @@ index 0000000..af1d10e
 +int nv50_display_create(struct drm_device *dev);
 +int nv50_display_destroy(struct drm_device *dev);
 +int nv50_crtc_blank(struct nouveau_crtc *, bool blank);
++int nv50_crtc_set_clock(struct drm_device *, int head, int pclk);
 +
 +#endif /* __NV50_DISPLAY_H__ */
 diff --git a/drivers/gpu/drm/nouveau/nv50_display_commands.h b/drivers/gpu/drm/nouveau/nv50_display_commands.h
@@ -51537,7 +51706,7 @@ index 0000000..6572f12
 +}
 diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
 new file mode 100644
-index 0000000..0ccd4ee
+index 0000000..8977aa3
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nv50_sor.c
 @@ -0,0 +1,310 @@
@@ -51617,7 +51786,7 @@ index 0000000..0ccd4ee
 +	 * initialisation on certain gpu's. I presume it's some kind of
 +	 * clock setting, but what precisely i do not know.
 +	 */
-+	nv_wr32(NV50_PDISPLAY_SOR_CLK_CLK_CTRL2(encoder->or),
++	nv_wr32(NV50_PDISPLAY_SOR_CLK_CTRL2(encoder->or),
 +		0x70000 | ((mode->clock > limit) ? 0x101 : 0));
 +
 +	return 0;


Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/kernel.spec,v
retrieving revision 1.1598
retrieving revision 1.1599
diff -u -p -r1.1598 -r1.1599
--- kernel.spec	30 Jun 2009 00:56:16 -0000	1.1598
+++ kernel.spec	30 Jun 2009 03:47:25 -0000	1.1599
@@ -1850,6 +1850,9 @@ fi
 # and build.
 
 %changelog
+* Tue Jun 30 2009 Ben Skeggs <bskeggs at redhat.com>
+- drm-nouveau.patch: match upstream
+
 * Mon Jun 29 2009 Chuck Ebbert <cebbert at redhat.com> 2.6.31-0.35.rc1.git5
 - 2.6.31-rc1-git5
 - CONFIG_LEDS_LP3944=m




More information about the fedora-extras-commits mailing list