summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2009-03-10 18:21:31 +1000
committerBen Skeggs <bskeggs@redhat.com>2009-03-10 18:22:42 +1000
commitcce3eb4e26bb765303d177526d70517e56301d98 (patch)
tree53e7ee103d75c366b4ef18cdc3f3dfc5c4694bea
parent16122cb1d9e4ec8eb21de69b3b66a83b8777a6f0 (diff)
drm/nv50: assorted kms fixes/cleanups
-rw-r--r--linux-core/nouveau_crtc.h5
-rw-r--r--linux-core/nv50_connector.c1
-rw-r--r--linux-core/nv50_crtc.c155
-rw-r--r--linux-core/nv50_cursor.c24
-rw-r--r--linux-core/nv50_cursor.h4
-rw-r--r--linux-core/nv50_display_commands.h13
-rw-r--r--linux-core/nv50_sor.c1
7 files changed, 108 insertions, 95 deletions
diff --git a/linux-core/nouveau_crtc.h b/linux-core/nouveau_crtc.h
index 0ba94756..c65994f0 100644
--- a/linux-core/nouveau_crtc.h
+++ b/linux-core/nouveau_crtc.h
@@ -37,7 +37,12 @@ struct nouveau_crtc {
struct drm_display_mode *mode;
bool use_dithering;
+ struct {
+ uint32_t offset;
+ } fb;
+
struct nv50_cursor *cursor;
+
struct {
struct mem_block *mem;
uint16_t r[256];
diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c
index dd404734..2c6952b8 100644
--- a/linux-core/nv50_connector.c
+++ b/linux-core/nv50_connector.c
@@ -385,7 +385,6 @@ nv50_connector_native_mode(struct nouveau_connector *connector)
return NULL;
list_for_each_entry(mode, &connector->base.probed_modes, head) {
- DRM_INFO("%d %d 0x%08x\n", mode->hdisplay, mode->vdisplay, mode->type);
if (mode->type & DRM_MODE_TYPE_PREFERRED)
return drm_mode_duplicate(dev, mode);
}
diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c
index efd3b9cf..8d410b00 100644
--- a/linux-core/nv50_crtc.c
+++ b/linux-core/nv50_crtc.c
@@ -95,33 +95,34 @@ nv50_crtc_blank(struct nouveau_crtc *crtc, bool blanked)
DRM_DEBUG("%s\n", blanked ? "blanked" : "unblanked");
if (blanked) {
- crtc->cursor->hide(crtc);
+ crtc->cursor->hide(crtc, false);
OUT_MODE(NV50_CRTC0_CLUT_MODE + offset,
NV50_CRTC0_CLUT_MODE_BLANK);
+ OUT_MODE(NV50_CRTC0_CLUT_OFFSET + offset, 0);
if (dev_priv->chipset != 0x50)
- OUT_MODE(NV84_CRTC0_BLANK_UNK1 + offset,
- NV84_CRTC0_BLANK_UNK1_BLANK);
+ OUT_MODE(NV84_CRTC0_CLUT_DMA + offset,
+ NV84_CRTC0_CLUT_DMA_DISABLE);
+
OUT_MODE(NV50_CRTC0_BLANK_CTRL + offset,
NV50_CRTC0_BLANK_CTRL_BLANK);
- if (dev_priv->chipset != 0x50)
- OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset,
- NV84_CRTC0_BLANK_UNK2_BLANK);
} else {
crtc->cursor->set_offset(crtc);
-
- if (dev_priv->chipset != 0x50)
- OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset,
- NV84_CRTC0_BLANK_UNK2_UNBLANK);
-
if (crtc->cursor->visible)
- crtc->cursor->show(crtc);
+ crtc->cursor->show(crtc, false);
else
- crtc->cursor->hide(crtc);
+ crtc->cursor->hide(crtc, false);
+ OUT_MODE(NV50_CRTC0_CLUT_MODE + offset, crtc->lut.depth == 8 ?
+ NV50_CRTC0_CLUT_MODE_OFF : NV50_CRTC0_CLUT_MODE_ON);
+ OUT_MODE(NV50_CRTC0_CLUT_OFFSET + offset,
+ crtc->lut.mem->start >> 8);
if (dev_priv->chipset != 0x50)
- OUT_MODE(NV84_CRTC0_BLANK_UNK1 + offset,
- NV84_CRTC0_BLANK_UNK1_UNBLANK);
+ OUT_MODE(NV84_CRTC0_CLUT_DMA + offset,
+ NV84_CRTC0_CLUT_DMA_LOCAL);
+
+ OUT_MODE(NV50_CRTC0_FB_OFFSET + offset, crtc->fb.offset >> 8);
+ OUT_MODE(0x864 + offset, 0);
OUT_MODE(NV50_CRTC0_BLANK_CTRL + offset,
NV50_CRTC0_BLANK_CTRL_UNBLANK);
}
@@ -444,13 +445,12 @@ static int nv50_crtc_cursor_set(struct drm_crtc *drm_crtc,
crtc->cursor->set_bo(crtc, gem);
crtc->cursor->set_offset(crtc);
- ret = crtc->cursor->show(crtc);
+ ret = crtc->cursor->show(crtc, true);
} else {
crtc->cursor->set_bo(crtc, NULL);
- crtc->cursor->hide(crtc);
+ crtc->cursor->hide(crtc, true);
}
- OUT_MODE(NV50_UPDATE_DISPLAY, 0);
return ret;
}
@@ -525,6 +525,9 @@ static void nv50_crtc_prepare(struct drm_crtc *drm_crtc)
static void nv50_crtc_commit(struct drm_crtc *drm_crtc)
{
+ struct nouveau_crtc *crtc = to_nouveau_crtc(drm_crtc);
+
+ nv50_crtc_blank(crtc, false);
}
static bool nv50_crtc_mode_fixup(struct drm_crtc *drm_crtc,
@@ -534,35 +537,67 @@ static bool nv50_crtc_mode_fixup(struct drm_crtc *drm_crtc,
return true;
}
-static int
-nv50_crtc_execute_mode(struct nouveau_crtc *crtc, struct drm_display_mode *mode)
+static void
+nv50_crtc_mode_set(struct drm_crtc *drm_crtc, struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode, int x, int y)
{
- struct drm_device *dev = crtc->base.dev;
+ struct drm_device *dev = drm_crtc->dev;
+ struct nouveau_crtc *crtc = to_nouveau_crtc(drm_crtc);
+ struct drm_encoder *drm_encoder;
+ struct nouveau_encoder *encoder;
+ struct drm_crtc_helper_funcs *crtc_helper = drm_crtc->helper_private;
+ struct nouveau_connector *connector = NULL;
uint32_t hsync_dur, vsync_dur, hsync_start_to_end, vsync_start_to_end;
uint32_t hunk1, vunk1, vunk2a, vunk2b;
uint32_t offset = crtc->index * 0x400;
+ /* Find the connector attached to this CRTC */
+ list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) {
+ struct drm_connector *drm_connector;
+
+ encoder = to_nouveau_encoder(drm_encoder);
+ if (drm_encoder->crtc != &crtc->base)
+ continue;
+
+ list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) {
+ connector = to_nouveau_connector(drm_connector);
+ if (drm_connector->encoder != drm_encoder)
+ continue;
+
+ break;
+ }
+
+ break; /* no use in finding more than one mode */
+ }
+
+ *crtc->mode = *adjusted_mode;
+ crtc->use_dithering = connector->use_dithering;
+
DRM_DEBUG("index %d\n", crtc->index);
- hsync_dur = mode->hsync_end - mode->hsync_start;
- vsync_dur = mode->vsync_end - mode->vsync_start;
- hsync_start_to_end = mode->htotal - mode->hsync_start;
- vsync_start_to_end = mode->vtotal - mode->vsync_start;
+ hsync_dur = adjusted_mode->hsync_end - adjusted_mode->hsync_start;
+ vsync_dur = adjusted_mode->vsync_end - adjusted_mode->vsync_start;
+ hsync_start_to_end = adjusted_mode->htotal - adjusted_mode->hsync_start;
+ vsync_start_to_end = adjusted_mode->vtotal - adjusted_mode->vsync_start;
/* I can't give this a proper name, anyone else can? */
- hunk1 = mode->htotal - mode->hsync_start + mode->hdisplay;
- vunk1 = mode->vtotal - mode->vsync_start + mode->vdisplay;
- /* Another strange value, this time only for interlaced modes. */
- vunk2a = 2*mode->vtotal - mode->vsync_start + mode->vdisplay;
- vunk2b = mode->vtotal - mode->vsync_start + mode->vtotal;
-
- if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ hunk1 = adjusted_mode->htotal -
+ adjusted_mode->hsync_start + adjusted_mode->hdisplay;
+ vunk1 = adjusted_mode->vtotal -
+ adjusted_mode->vsync_start + adjusted_mode->vdisplay;
+ /* Another strange value, this time only for interlaced adjusted_modes. */
+ vunk2a = 2 * adjusted_mode->vtotal -
+ adjusted_mode->vsync_start + adjusted_mode->vdisplay;
+ vunk2b = adjusted_mode->vtotal -
+ adjusted_mode->vsync_start + adjusted_mode->vtotal;
+
+ if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
vsync_dur /= 2;
vsync_start_to_end /= 2;
vunk1 /= 2;
vunk2a /= 2;
vunk2b /= 2;
/* magic */
- if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
+ if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) {
vsync_start_to_end -= 1;
vunk1 -= 1;
vunk2a -= 1;
@@ -570,20 +605,20 @@ nv50_crtc_execute_mode(struct nouveau_crtc *crtc, struct drm_display_mode *mode)
}
}
- OUT_MODE(NV50_CRTC0_CLOCK + offset, mode->clock | 0x800000);
+ OUT_MODE(NV50_CRTC0_CLOCK + offset, adjusted_mode->clock | 0x800000);
OUT_MODE(NV50_CRTC0_INTERLACE + offset,
- (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 0);
+ (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 0);
OUT_MODE(NV50_CRTC0_DISPLAY_START + offset, 0);
OUT_MODE(NV50_CRTC0_UNK82C + offset, 0);
OUT_MODE(NV50_CRTC0_DISPLAY_TOTAL + offset,
- mode->vtotal << 16 | mode->htotal);
+ adjusted_mode->vtotal << 16 | adjusted_mode->htotal);
OUT_MODE(NV50_CRTC0_SYNC_DURATION + offset,
(vsync_dur - 1) << 16 | (hsync_dur - 1));
OUT_MODE(NV50_CRTC0_SYNC_START_TO_BLANK_END + offset,
(vsync_start_to_end - 1) << 16 | (hsync_start_to_end - 1));
OUT_MODE(NV50_CRTC0_MODE_UNK1 + offset,
(vunk1 - 1) << 16 | (hunk1 - 1));
- if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
OUT_MODE(NV50_CRTC0_MODE_UNK2 + offset,
(vunk2b - 1) << 16 | (vunk2a - 1));
}
@@ -597,44 +632,7 @@ nv50_crtc_execute_mode(struct nouveau_crtc *crtc, struct drm_display_mode *mode)
NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0));
nv50_crtc_blank(crtc, false);
- return 0;
-}
-
-
-static void
-nv50_crtc_mode_set(struct drm_crtc *drm_crtc, struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode, int x, int y)
-{
- struct drm_device *dev = drm_crtc->dev;
- struct nouveau_crtc *crtc = to_nouveau_crtc(drm_crtc);
- struct drm_encoder *drm_encoder;
- struct nouveau_encoder *encoder;
- struct drm_crtc_helper_funcs *crtc_helper = drm_crtc->helper_private;
- struct nouveau_connector *connector = NULL;
-
- /* Find the connector attached to this CRTC */
- list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) {
- struct drm_connector *drm_connector;
- encoder = to_nouveau_encoder(drm_encoder);
- if (drm_encoder->crtc != &crtc->base)
- continue;
-
- list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) {
- connector = to_nouveau_connector(drm_connector);
- if (drm_connector->encoder != drm_encoder)
- continue;
-
- break;
- }
-
- break; /* no use in finding more than one mode */
- }
-
- *crtc->mode = *adjusted_mode;
- crtc->use_dithering = connector->use_dithering;
-
- nv50_crtc_execute_mode(crtc, adjusted_mode);
crtc->set_scale(crtc, connector->scaling_mode, false);
crtc_helper->mode_set_base(drm_crtc, x, y);
}
@@ -648,10 +646,11 @@ nv50_crtc_mode_set_base(struct drm_crtc *drm_crtc, int x, int y)
struct drm_framebuffer *drm_fb = crtc->base.fb;
struct nouveau_framebuffer *fb = to_nouveau_framebuffer(drm_fb);
struct nouveau_gem_object *ngem = nouveau_gem_object(fb->gem);
- uint32_t v_vram = ngem->bo->offset - dev_priv->vm_vram_base;
uint32_t offset = crtc->index * 0x400;
- OUT_MODE(NV50_CRTC0_FB_OFFSET + offset, v_vram >> 8);
+ crtc->fb.offset = ngem->bo->offset - dev_priv->vm_vram_base;
+
+ OUT_MODE(NV50_CRTC0_FB_OFFSET + offset, crtc->fb.offset >> 8);
OUT_MODE(0x864 + offset, 0);
OUT_MODE(NV50_CRTC0_FB_SIZE + offset,
@@ -684,10 +683,6 @@ nv50_crtc_mode_set_base(struct drm_crtc *drm_crtc, int x, int y)
nv50_crtc_lut_load(crtc);
}
- OUT_MODE(NV50_CRTC0_CLUT_MODE + offset, fb->base.depth == 8 ?
- NV50_CRTC0_CLUT_MODE_OFF : NV50_CRTC0_CLUT_MODE_ON);
- OUT_MODE(NV50_CRTC0_CLUT_OFFSET + offset, crtc->lut.mem->start >> 8);
-
OUT_MODE(NV50_UPDATE_DISPLAY, 0);
}
diff --git a/linux-core/nv50_cursor.c b/linux-core/nv50_cursor.c
index fca5b4a4..10736de6 100644
--- a/linux-core/nv50_cursor.c
+++ b/linux-core/nv50_cursor.c
@@ -84,8 +84,9 @@ static int nv50_cursor_disable(struct nouveau_crtc *crtc)
}
/* Calling update or changing the stored cursor state is left to the higher level ioctl's. */
-static int nv50_cursor_show(struct nouveau_crtc *crtc)
+static int nv50_cursor_show(struct nouveau_crtc *crtc, bool update)
{
+ struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private;
struct drm_device *dev = crtc->base.dev;
uint32_t offset = crtc->index * 0x400;
@@ -98,22 +99,37 @@ static int nv50_cursor_show(struct nouveau_crtc *crtc)
return -EINVAL;
}
+ if (dev_priv->chipset != 0x50)
+ OUT_MODE(NV84_CRTC0_CURSOR_DMA + offset,
+ NV84_CRTC0_CURSOR_DMA_LOCAL);
OUT_MODE(NV50_CRTC0_CURSOR_CTRL + offset, NV50_CRTC0_CURSOR_CTRL_SHOW);
+
+ if (update) {
+ OUT_MODE(NV50_UPDATE_DISPLAY, 0);
+ crtc->cursor->visible = true;
+ }
- crtc->cursor->visible = true;
return 0;
}
-static int nv50_cursor_hide(struct nouveau_crtc *crtc)
+static int nv50_cursor_hide(struct nouveau_crtc *crtc, bool update)
{
+ struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private;
struct drm_device *dev = crtc->base.dev;
uint32_t offset = crtc->index * 0x400;
DRM_DEBUG("\n");
OUT_MODE(NV50_CRTC0_CURSOR_CTRL + offset, NV50_CRTC0_CURSOR_CTRL_HIDE);
+ if (dev_priv->chipset != 0x50)
+ OUT_MODE(NV84_CRTC0_CURSOR_DMA + offset,
+ NV84_CRTC0_CURSOR_DMA_DISABLE);
+
+ if (update) {
+ OUT_MODE(NV50_UPDATE_DISPLAY, 0);
+ crtc->cursor->visible = false;
+ }
- crtc->cursor->visible = false;
return 0;
}
diff --git a/linux-core/nv50_cursor.h b/linux-core/nv50_cursor.h
index 9be1591a..089a69c9 100644
--- a/linux-core/nv50_cursor.h
+++ b/linux-core/nv50_cursor.h
@@ -32,8 +32,8 @@ struct nv50_cursor {
int x, y;
bool visible;
- int (*show) (struct nouveau_crtc *crtc);
- int (*hide) (struct nouveau_crtc *crtc);
+ int (*show) (struct nouveau_crtc *crtc, bool update);
+ int (*hide) (struct nouveau_crtc *crtc, bool update);
int (*set_pos) (struct nouveau_crtc *crtc, int x, int y);
int (*set_offset) (struct nouveau_crtc *crtc);
int (*set_bo) (struct nouveau_crtc *crtc, struct drm_gem_object *gem);
diff --git a/linux-core/nv50_display_commands.h b/linux-core/nv50_display_commands.h
index 97b3d3c1..4fd10c96 100644
--- a/linux-core/nv50_display_commands.h
+++ b/linux-core/nv50_display_commands.h
@@ -75,10 +75,9 @@
#define NV50_CRTC0_CLUT_MODE_ON 0xC0000000
#define NV50_CRTC0_CLUT_OFFSET 0x844
-/* Anyone know what part of the chip is triggered here precisely? */
-#define NV84_CRTC0_BLANK_UNK1 0x85C
- #define NV84_CRTC0_BLANK_UNK1_BLANK 0x0
- #define NV84_CRTC0_BLANK_UNK1_UNBLANK 0x1
+#define NV84_CRTC0_CLUT_DMA 0x85C
+ #define NV84_CRTC0_CLUT_DMA_DISABLE 0x0
+ #define NV84_CRTC0_CLUT_DMA_LOCAL 0x1
#define NV50_CRTC0_FB_OFFSET 0x860
@@ -105,9 +104,9 @@
#define NV50_CRTC0_CURSOR_OFFSET 0x884
/* Anyone know what part of the chip is triggered here precisely? */
-#define NV84_CRTC0_BLANK_UNK2 0x89C
- #define NV84_CRTC0_BLANK_UNK2_BLANK 0x0
- #define NV84_CRTC0_BLANK_UNK2_UNBLANK 0x1
+#define NV84_CRTC0_CURSOR_DMA 0x89C
+ #define NV84_CRTC0_CURSOR_DMA_DISABLE 0x0
+ #define NV84_CRTC0_CURSOR_DMA_LOCAL 0x1
#define NV50_CRTC0_DITHERING_CTRL 0x8A0
#define NV50_CRTC0_DITHERING_CTRL_ON 0x11
diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c
index fd29ffc9..a147fb66 100644
--- a/linux-core/nv50_sor.c
+++ b/linux-core/nv50_sor.c
@@ -44,7 +44,6 @@ nv50_sor_disconnect(struct nouveau_encoder *encoder)
DRM_DEBUG("Disconnecting SOR %d\n", encoder->or);
OUT_MODE(NV50_SOR0_MODE_CTRL + offset, NV50_SOR_MODE_CTRL_OFF);
- OUT_MODE(NV50_UPDATE_DISPLAY, 0);
}
static int