From 09b67dda0bc040860aedce4a2d28bce1c80e56d6 Mon Sep 17 00:00:00 2001
From: Maarten Maathuis <madman2003@gmail.com>
Date: Wed, 25 Jun 2008 15:16:38 +0200
Subject: NV50: Some cleanup and fixes.

---
 linux-core/nv50_crtc.c    | 10 ++++++----
 linux-core/nv50_crtc.h    |  1 +
 linux-core/nv50_cursor.c  | 18 +++++++++++++++++-
 linux-core/nv50_cursor.h  |  1 +
 shared-core/nouveau_mem.c | 29 +++++++++++++++++++++++++++++
 5 files changed, 54 insertions(+), 5 deletions(-)

diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c
index 0bcf3058..af2f03d8 100644
--- a/linux-core/nv50_crtc.c
+++ b/linux-core/nv50_crtc.c
@@ -192,10 +192,9 @@ static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked)
 	} else {
 		OUT_MODE(NV50_CRTC0_FB_OFFSET + offset, crtc->fb->block->start >> 8);
 		OUT_MODE(0x864 + offset, 0);
-		if (crtc->cursor->block)
-			OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, crtc->cursor->block->start >> 8);
-		else
-			OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, 0);
+
+		crtc->cursor->set_offset(crtc);
+
 		if (dev_priv->chipset != 0x50)
 			OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset, NV84_CRTC0_BLANK_UNK2_UNBLANK);
 
@@ -212,6 +211,9 @@ static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked)
 		OUT_MODE(NV50_CRTC0_BLANK_CTRL + offset, NV50_CRTC0_BLANK_CTRL_UNBLANK);
 	}
 
+	/* sometimes you need to know if a screen is already blanked. */
+	crtc->blanked = blanked;
+
 	return 0;
 }
 
diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h
index 0eadc3d4..b63c5a22 100644
--- a/linux-core/nv50_crtc.h
+++ b/linux-core/nv50_crtc.h
@@ -39,6 +39,7 @@ struct nv50_crtc {
 	struct drm_device *dev;
 	int index;
 	bool active;
+	bool blanked;
 
 	struct nouveau_hw_mode *mode;
 	struct nouveau_hw_mode *native_mode;
diff --git a/linux-core/nv50_cursor.c b/linux-core/nv50_cursor.c
index 47ae11bb..091c94fe 100644
--- a/linux-core/nv50_cursor.c
+++ b/linux-core/nv50_cursor.c
@@ -103,6 +103,21 @@ static int nv50_cursor_set_pos(struct nv50_crtc *crtc, int x, int y)
 	return 0;
 }
 
+static int nv50_cursor_set_offset(struct nv50_crtc *crtc)
+{
+	struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
+
+	NV50_DEBUG("\n");
+
+	if (crtc->cursor->block) {
+		OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + crtc->index * 0x400, crtc->cursor->block->start >> 8);
+	} else {
+		OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + crtc->index * 0x400, 0);
+	}
+
+	return 0;
+}
+
 static int nv50_cursor_set_bo(struct nv50_crtc *crtc, drm_handle_t handle)
 {
 	struct mem_block *block = NULL;
@@ -121,7 +136,7 @@ static int nv50_cursor_set_bo(struct nv50_crtc *crtc, drm_handle_t handle)
 
 		/* set the cursor offset cursor */
 		if (first_time) {
-			OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + crtc->index * 0x400, crtc->cursor->block->start >> 8);
+			crtc->cursor->set_offset(crtc);
 			if (crtc->cursor->visible)
 				crtc->cursor->show(crtc);
 		}
@@ -148,6 +163,7 @@ int nv50_cursor_create(struct nv50_crtc *crtc)
 	crtc->cursor->show = nv50_cursor_show;
 	crtc->cursor->hide = nv50_cursor_hide;
 	crtc->cursor->set_pos = nv50_cursor_set_pos;
+	crtc->cursor->set_offset = nv50_cursor_set_offset;
 	crtc->cursor->set_bo = nv50_cursor_set_bo;
 	crtc->cursor->enable = nv50_cursor_enable;
 	crtc->cursor->disable = nv50_cursor_disable;
diff --git a/linux-core/nv50_cursor.h b/linux-core/nv50_cursor.h
index a2e4632c..4fd0d39a 100644
--- a/linux-core/nv50_cursor.h
+++ b/linux-core/nv50_cursor.h
@@ -40,6 +40,7 @@ struct nv50_cursor {
 	int (*show) (struct nv50_crtc *crtc);
 	int (*hide) (struct nv50_crtc *crtc);
 	int (*set_pos) (struct nv50_crtc *crtc, int x, int y);
+	int (*set_offset) (struct nv50_crtc *crtc);
 	int (*set_bo) (struct nv50_crtc *crtc, drm_handle_t handle);
 	int (*enable) (struct nv50_crtc *crtc);
 	int (*disable) (struct nv50_crtc *crtc);
diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c
index 51ac48dd..4acd6bd6 100644
--- a/shared-core/nouveau_mem.c
+++ b/shared-core/nouveau_mem.c
@@ -34,6 +34,8 @@
 #include "drm.h"
 #include "drm_sarea.h"
 #include "nouveau_drv.h"
+#include "nv50_kms_wrapper.h"
+
 
 static struct mem_block *
 split_block(struct mem_block *p, uint64_t start, uint64_t size,
@@ -730,6 +732,33 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block)
 
 	DRM_DEBUG("freeing 0x%llx type=0x%08x\n", block->start, block->flags);
 
+	/* Check if the deallocations cause problems for our modesetting system. */
+	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+		if (dev_priv->card_type >= NV_50) {
+			struct nv50_crtc *crtc = NULL;
+			struct nv50_display *display = nv50_get_display(dev);
+
+			list_for_each_entry(crtc, &display->crtcs, head) {
+				if (crtc->fb->block == block) {
+					crtc->fb->block = NULL;
+
+					/* this will force a lut change next time a fb is loaded */
+					crtc->lut->depth = 0;
+
+					if (!crtc->blanked)
+						crtc->blank(crtc, TRUE);
+				}
+
+				if (crtc->cursor->block == block) {
+					crtc->cursor->block = NULL;
+
+					if (crtc->cursor->visible)
+						crtc->cursor->hide(crtc);
+				}
+			}
+		}
+	}
+
 	if (block->flags&NOUVEAU_MEM_MAPPED)
 		drm_rmmap(dev, block->map);
 
-- 
cgit v1.2.3