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