summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaarten Maathuis <madman2003@gmail.com>2008-06-23 20:33:32 +0200
committerMaarten Maathuis <madman2003@gmail.com>2008-06-23 20:33:32 +0200
commit0a45f150669eaa2737d7485c9b68ea4c483f3048 (patch)
treec2186fd0fe85b6ea6963bb84ce71e515adc1799d
parent30f153a7c2a9bc69e615b7fff3fb060af0e3ed83 (diff)
NV50: Improve set_config and fix some minor bugs.
-rw-r--r--linux-core/nv50_crtc.c47
-rw-r--r--linux-core/nv50_crtc.h1
-rw-r--r--linux-core/nv50_display.c12
-rw-r--r--linux-core/nv50_fb.c7
-rw-r--r--linux-core/nv50_fb.h2
-rw-r--r--linux-core/nv50_kms_wrapper.c427
-rw-r--r--linux-core/nv50_sor.c4
7 files changed, 317 insertions, 183 deletions
diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c
index 887d6ec2..0bcf3058 100644
--- a/linux-core/nv50_crtc.c
+++ b/linux-core/nv50_crtc.c
@@ -72,7 +72,6 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc)
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;
- uint32_t pitch;
NV50_DEBUG("index %d\n", crtc->index);
NV50_DEBUG("%s native mode\n", crtc->use_native_mode ? "using" : "not using");
@@ -119,12 +118,31 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc)
if (hw_mode->flags & V_INTERLACE) {
OUT_MODE(NV50_CRTC0_MODE_UNK2 + offset, (vunk2b - 1) << 16 | (vunk2a - 1));
}
+
+ crtc->set_fb(crtc);
+ crtc->set_dither(crtc);
+
+ /* This is the actual resolution of the mode. */
+ OUT_MODE(NV50_CRTC0_REAL_RES + offset, (crtc->mode->vdisplay << 16) | crtc->mode->hdisplay);
+ OUT_MODE(NV50_CRTC0_SCALE_CENTER_OFFSET + offset, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0));
+
+ /* Maybe move this as well? */
+ crtc->blank(crtc, FALSE);
+
+ return 0;
+}
+
+static int nv50_crtc_set_fb(struct nv50_crtc *crtc)
+{
+ struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
+ uint32_t offset = crtc->index * 0x400;
+
+ NV50_DEBUG("\n");
+
OUT_MODE(NV50_CRTC0_FB_SIZE + offset, crtc->fb->height << 16 | crtc->fb->width);
/* I suspect this flag indicates a linear fb. */
- pitch = ((crtc->fb->width + 63) & ~63) * (crtc->fb->bpp)/8;
- NV50_DEBUG("fb_pitch %d\n", pitch);
- OUT_MODE(NV50_CRTC0_FB_PITCH + offset, pitch | 0x100000);
+ OUT_MODE(NV50_CRTC0_FB_PITCH + offset, crtc->fb->pitch | 0x100000);
switch (crtc->fb->depth) {
case 8:
@@ -140,15 +158,9 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc)
OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_24BPP);
break;
}
- crtc->set_dither(crtc);
+
OUT_MODE(NV50_CRTC0_COLOR_CTRL + offset, NV50_CRTC_COLOR_CTRL_MODE_COLOR);
OUT_MODE(NV50_CRTC0_FB_POS + offset, (crtc->fb->y << 16) | (crtc->fb->x));
- /* This is the actual resolution of the mode. */
- OUT_MODE(NV50_CRTC0_REAL_RES + offset, (crtc->mode->vdisplay << 16) | crtc->mode->hdisplay);
- OUT_MODE(NV50_CRTC0_SCALE_CENTER_OFFSET + offset, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0));
-
- /* Maybe move this as well? */
- crtc->blank(crtc, FALSE);
return 0;
}
@@ -178,20 +190,8 @@ static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked)
if (dev_priv->chipset != 0x50)
OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset, NV84_CRTC0_BLANK_UNK2_BLANK);
} else {
- uint32_t ram_amount;
-
OUT_MODE(NV50_CRTC0_FB_OFFSET + offset, crtc->fb->block->start >> 8);
OUT_MODE(0x864 + offset, 0);
- /* maybe this needs to be moved. */
- NV_WRITE(NV50_PDISPLAY_UNK_380, 0);
- /* RAM is clamped to 256 MiB. */
- ram_amount = nouveau_mem_fb_amount(crtc->dev);
- NV50_DEBUG("ram_amount %d\n", ram_amount);
- if (ram_amount > 256*1024*1024)
- ram_amount = 256*1024*1024;
- NV_WRITE(NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1);
- NV_WRITE(NV50_PDISPLAY_UNK_388, 0x150000);
- NV_WRITE(NV50_PDISPLAY_UNK_38C, 0);
if (crtc->cursor->block)
OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, crtc->cursor->block->start >> 8);
else
@@ -502,6 +502,7 @@ int nv50_crtc_create(struct drm_device *dev, int index)
crtc->validate_mode = nv50_crtc_validate_mode;
crtc->set_mode = nv50_crtc_set_mode;
crtc->execute_mode = nv50_crtc_execute_mode;
+ crtc->set_fb = nv50_crtc_set_fb;
crtc->blank = nv50_crtc_blank;
crtc->set_dither = nv50_crtc_set_dither;
crtc->set_scale = nv50_crtc_set_scale;
diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h
index 5eb815a5..0eadc3d4 100644
--- a/linux-core/nv50_crtc.h
+++ b/linux-core/nv50_crtc.h
@@ -54,6 +54,7 @@ struct nv50_crtc {
int (*validate_mode) (struct nv50_crtc *crtc, struct nouveau_hw_mode *mode);
int (*set_mode) (struct nv50_crtc *crtc, struct nouveau_hw_mode *mode);
int (*execute_mode) (struct nv50_crtc *crtc);
+ int (*set_fb) (struct nv50_crtc *crtc);
int (*blank) (struct nv50_crtc *crtc, bool blanked);
int (*set_dither) (struct nv50_crtc *crtc);
int (*set_scale) (struct nv50_crtc *crtc);
diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c
index 05ff72f8..0c82ff8f 100644
--- a/linux-core/nv50_display.c
+++ b/linux-core/nv50_display.c
@@ -34,6 +34,7 @@ static int nv50_display_pre_init(struct nv50_display *display)
struct drm_device *dev = display->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
int i;
+ uint32_t ram_amount;
NV50_DEBUG("\n");
@@ -67,6 +68,17 @@ static int nv50_display_pre_init(struct nv50_display *display)
NV_WRITE(NV50_PDISPLAY_DAC_REGS_CLK_CTRL1(i), 0x00000001);
}
+ /* This used to be in crtc unblank, but seems out of place there. */
+ NV_WRITE(NV50_PDISPLAY_UNK_380, 0);
+ /* RAM is clamped to 256 MiB. */
+ ram_amount = nouveau_mem_fb_amount(display->dev);
+ NV50_DEBUG("ram_amount %d\n", ram_amount);
+ if (ram_amount > 256*1024*1024)
+ ram_amount = 256*1024*1024;
+ NV_WRITE(NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1);
+ NV_WRITE(NV50_PDISPLAY_UNK_388, 0x150000);
+ NV_WRITE(NV50_PDISPLAY_UNK_38C, 0);
+
display->preinit_done = TRUE;
return 0;
diff --git a/linux-core/nv50_fb.c b/linux-core/nv50_fb.c
index f57a9fad..153899da 100644
--- a/linux-core/nv50_fb.c
+++ b/linux-core/nv50_fb.c
@@ -40,8 +40,9 @@ static int nv50_fb_bind(struct nv50_crtc *crtc, struct nv50_fb_info *info)
return -EINVAL;
}
- if (!info->block || !info->width || !info->height || !info->depth || !info->bpp) {
- DRM_ERROR("block %p width %d height %d depth %d bpp %d\n", info->block, info->width, info->height, info->depth, info->bpp);
+ if (!info->block || !info->width || !info->height || !info->depth || !info->bpp || !info->pitch) {
+ DRM_ERROR("block %p width %d height %d depth %d bpp %d pitch %d\n", info->block, info->width,
+ info->height, info->depth, info->bpp, info->pitch);
return -EINVAL;
}
@@ -55,6 +56,8 @@ static int nv50_fb_bind(struct nv50_crtc *crtc, struct nv50_fb_info *info)
crtc->fb->depth = info->depth;
crtc->fb->bpp = info->bpp;
+ crtc->fb->pitch = info->pitch;
+
/* update lut if needed */
if (crtc->fb->depth != crtc->lut->depth) {
int r_size = 0, g_size = 0, b_size = 0;
diff --git a/linux-core/nv50_fb.h b/linux-core/nv50_fb.h
index 6b286315..3051dc5c 100644
--- a/linux-core/nv50_fb.h
+++ b/linux-core/nv50_fb.h
@@ -35,6 +35,7 @@ struct nv50_fb_info {
struct mem_block *block;
int width, height;
int bpp, depth;
+ int pitch;
int x,y;
};
@@ -42,6 +43,7 @@ struct nv50_fb {
struct mem_block *block;
int width, height;
int bpp, depth;
+ int pitch;
int x,y;
diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c
index a63cb7df..e93a2668 100644
--- a/linux-core/nv50_kms_wrapper.c
+++ b/linux-core/nv50_kms_wrapper.c
@@ -284,12 +284,17 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
struct nouveau_hw_mode *hw_mode = NULL;
struct nv50_fb_info fb_info;
+ bool blank = false;
+ bool switch_fb = false;
+ bool modeset = false;
+
NV50_DEBUG("\n");
/*
- * Initial approach is very simple, always set a mode.
- * Always bail out completely if something is wrong.
- * Later this could be extended to be more smart.
+ * Supported operations:
+ * - Switch mode.
+ * - Switch framebuffer.
+ * - Blank screen.
*/
/* Sanity checking */
@@ -298,138 +303,200 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
goto out;
}
- if (!set->crtc || !set->fb || !set->mode || !set->connectors) {
+ if (!set->crtc || !set->connectors) {
NV50_DEBUG("Sanity check failed\n");
goto out;
}
+ if (set->mode) {
+ if (set->fb) {
+ if (!drm_mode_equal(set->mode, &set->crtc->mode))
+ modeset = true;
+
+ if (set->fb != set->crtc->fb)
+ switch_fb = true;
+
+ if (set->x != set->crtc->x || set->y != set->crtc->y)
+ switch_fb = true;
+ }
+ } else {
+ blank = true;
+ }
+
+ if (!modeset && !switch_fb && !blank) {
+ DRM_ERROR("There is nothing to do, bad input.\n");
+ goto out;
+ }
+
/* Basic variable setting */
dev = set->crtc->dev;
dev_priv = dev->dev_private;
display = nv50_get_display(dev);
crtc = to_nv50_crtc(set->crtc);
- /* Mode validation */
- hw_mode = nv50_kms_to_hw_mode(set->mode);
-
- rval = crtc->validate_mode(crtc, hw_mode);
-
- if (rval != MODE_OK) {
- NV50_DEBUG("Mode not ok\n");
- goto out;
- }
+ /**
+ * Wiring up the encoders and connectors.
+ */
- for (i = 0; i < set->num_connectors; i++) {
- drm_connector = set->connectors[i];
- if (!drm_connector) {
- NV50_DEBUG("No connector\n");
- goto out;
- }
- connector = to_nv50_connector(drm_connector);
+ if (modeset) {
+ /* Mode validation */
+ hw_mode = nv50_kms_to_hw_mode(set->mode);
- output = connector->to_output(connector, connector->digital);
- if (!output) {
- NV50_DEBUG("No output\n");
- goto out;
- }
+ rval = crtc->validate_mode(crtc, hw_mode);
- rval = output->validate_mode(output, hw_mode);
if (rval != MODE_OK) {
NV50_DEBUG("Mode not ok\n");
goto out;
}
- }
- /* Validation done, move on to cleaning of existing structures. */
+ for (i = 0; i < set->num_connectors; i++) {
+ drm_connector = set->connectors[i];
+ if (!drm_connector) {
+ NV50_DEBUG("No connector\n");
+ goto out;
+ }
+ connector = to_nv50_connector(drm_connector);
- /* find encoders that use this crtc. */
- list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) {
- if (drm_encoder->crtc == set->crtc) {
- /* find the connector that goes with it */
- list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) {
- if (drm_connector->encoder == drm_encoder) {
- drm_connector->encoder = NULL;
- break;
- }
+ output = connector->to_output(connector, connector->digital);
+ if (!output) {
+ NV50_DEBUG("No output\n");
+ goto out;
}
- drm_encoder->crtc = NULL;
- }
- }
- /* now find if our desired encoders or connectors are in use already. */
- for (i = 0; i < set->num_connectors; i++) {
- drm_connector = set->connectors[i];
- if (!drm_connector) {
- NV50_DEBUG("No connector\n");
- goto out;
+ rval = output->validate_mode(output, hw_mode);
+ if (rval != MODE_OK) {
+ NV50_DEBUG("Mode not ok\n");
+ goto out;
+ }
}
- if (!drm_connector->encoder)
- continue;
+ /* Validation done, move on to cleaning of existing structures. */
+
+ /* find encoders that use this crtc. */
+ list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) {
+ if (drm_encoder->crtc == set->crtc) {
+ /* find the connector that goes with it */
+ list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) {
+ if (drm_connector->encoder == drm_encoder) {
+ drm_connector->encoder = NULL;
+ break;
+ }
+ }
+ drm_encoder->crtc = NULL;
+ }
+ }
- drm_encoder = drm_connector->encoder;
- drm_connector->encoder = NULL;
+ /* now find if our desired encoders or connectors are in use already. */
+ for (i = 0; i < set->num_connectors; i++) {
+ drm_connector = set->connectors[i];
+ if (!drm_connector) {
+ NV50_DEBUG("No connector\n");
+ goto out;
+ }
- if (!drm_encoder->crtc)
- continue;
+ if (!drm_connector->encoder)
+ continue;
- drm_crtc = drm_encoder->crtc;
- drm_encoder->crtc = NULL;
+ drm_encoder = drm_connector->encoder;
+ drm_connector->encoder = NULL;
- crtc = to_nv50_crtc(drm_crtc);
- crtc->active = false;
- drm_crtc->enabled = false;
- }
+ if (!drm_encoder->crtc)
+ continue;
- /* set framebuffer */
- set->crtc->fb = set->fb;
+ drm_crtc = drm_encoder->crtc;
+ drm_encoder->crtc = NULL;
- /* Time to wire up the public encoder, the private one will be handled later. */
- for (i = 0; i < set->num_connectors; i++) {
- drm_connector = set->connectors[i];
- if (!drm_connector) {
- NV50_DEBUG("No connector\n");
- goto out;
+ crtc = to_nv50_crtc(drm_crtc);
+ crtc->active = false;
+ drm_crtc->enabled = false;
}
- output = connector->to_output(connector, connector->digital);
- if (!output) {
- NV50_DEBUG("No output\n");
- goto out;
- }
+ /* Time to wire up the public encoder, the private one will be handled later. */
+ for (i = 0; i < set->num_connectors; i++) {
+ drm_connector = set->connectors[i];
+ if (!drm_connector) {
+ NV50_DEBUG("No connector\n");
+ goto out;
+ }
- /* find the encoder public structure that matches out output structure. */
- drm_encoder = to_nv50_kms_encoder(output);
+ output = connector->to_output(connector, connector->digital);
+ if (!output) {
+ NV50_DEBUG("No output\n");
+ goto out;
+ }
- if (!drm_encoder) {
- NV50_DEBUG("No encoder\n");
- goto out;
+ /* find the encoder public structure that matches out output structure. */
+ drm_encoder = to_nv50_kms_encoder(output);
+
+ if (!drm_encoder) {
+ NV50_DEBUG("No encoder\n");
+ goto out;
+ }
+
+ drm_encoder->crtc = set->crtc;
+ drm_connector->encoder = drm_encoder;
}
+ }
+
+ /**
+ * Unwire encoders and connectors, etc.
+ */
+ if (blank) {
+ crtc = to_nv50_crtc(drm_crtc);
- drm_encoder->crtc = set->crtc;
- drm_connector->encoder = drm_encoder;
+ crtc->active = false;
+ set->crtc->enabled = false;
+
+ /* find encoders that use this crtc. */
+ list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) {
+ if (drm_encoder->crtc == set->crtc) {
+ /* find the connector that goes with it */
+ list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) {
+ if (drm_connector->encoder == drm_encoder) {
+ drm_connector->encoder = NULL;
+ break;
+ }
+ }
+ drm_encoder->crtc = NULL;
+ }
+ }
}
+ /**
+ * All state should now be updated, now onto the real work.
+ */
+
/* mirror everything to the private structs */
nv50_kms_mirror_routing(dev);
- /* set private framebuffer */
- crtc = to_nv50_crtc(set->crtc);
- fb_info.block = find_block_by_handle(dev_priv->fb_heap, set->fb->mm_handle);
- fb_info.width = set->fb->width;
- fb_info.height = set->fb->height;
- fb_info.depth = set->fb->depth;
- fb_info.bpp = set->fb->bits_per_pixel;
- fb_info.x = set->x;
- fb_info.y = set->y;
-
- rval = crtc->fb->bind(crtc, &fb_info);
- if (rval != 0) {
- NV50_DEBUG("fb_bind failed\n");
- goto out;
+ /**
+ * Bind framebuffer.
+ */
+
+ if (switch_fb) {
+ /* set framebuffer */
+ set->crtc->fb = set->fb;
+
+ /* set private framebuffer */
+ crtc = to_nv50_crtc(set->crtc);
+ fb_info.block = find_block_by_handle(dev_priv->fb_heap, set->fb->mm_handle);
+ fb_info.width = set->fb->width;
+ fb_info.height = set->fb->height;
+ fb_info.depth = set->fb->depth;
+ fb_info.bpp = set->fb->bits_per_pixel;
+ fb_info.pitch = set->fb->pitch;
+ fb_info.x = set->x;
+ fb_info.y = set->y;
+
+ rval = crtc->fb->bind(crtc, &fb_info);
+ if (rval != 0) {
+ NV50_DEBUG("fb_bind failed\n");
+ goto out;
+ }
}
+ /* this is !cursor_show */
if (!crtc->cursor->enabled) {
rval = crtc->cursor->enable(crtc);
if (rval != 0) {
@@ -438,74 +505,119 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
}
}
- /* modeset time, finally */
+ /**
+ * Blanking.
+ */
- /* disconnect unused outputs */
- list_for_each_entry(output, &display->outputs, head) {
- if (output->crtc)
- crtc_mask |= 1 << output->crtc->index;
- else
- output->execute_mode(output, TRUE);
- }
+ if (blank) {
+ crtc = to_nv50_crtc(set->crtc);
- rval = crtc->set_mode(crtc, hw_mode);
- if (rval != 0) {
- NV50_DEBUG("crtc mode set failed\n");
- goto out;
+ rval = crtc->blank(crtc, TRUE);
+ if (rval != 0) {
+ DRM_ERROR("blanking failed\n");
+ goto out;
+ }
}
- /* find native mode. */
- list_for_each_entry(output, &display->outputs, head) {
- if (output->crtc != crtc)
- continue;
+ /**
+ * Change framebuffer, without changing mode.
+ */
- *crtc->native_mode = *output->native_mode;
- list_for_each_entry(connector, &display->connectors, head) {
- if (connector->output != output)
- continue;
+ if (switch_fb && !modeset) {
+ crtc = to_nv50_crtc(set->crtc);
- crtc->scaling_mode = connector->scaling_mode;
- break;
+ rval = crtc->blank(crtc, TRUE);
+ if (rval != 0) {
+ DRM_ERROR("blanking failed\n");
+ goto out;
}
- if (crtc->scaling_mode == SCALE_PANEL)
- crtc->use_native_mode = false;
- else
- crtc->use_native_mode = true;
+ rval = crtc->set_fb(crtc);
+ if (rval != 0) {
+ DRM_ERROR("set_fb failed\n");
+ goto out;
+ }
- break; /* no use in finding more than one mode */
+ /* this also sets the fb offset */
+ rval = crtc->blank(crtc, FALSE);
+ if (rval != 0) {
+ DRM_ERROR("unblanking failed\n");
+ goto out;
+ }
}
- rval = crtc->execute_mode(crtc);
- if (rval != 0) {
- NV50_DEBUG("crtc execute mode failed\n");
- goto out;
- }
+ /**
+ * Normal modesetting.
+ */
- list_for_each_entry(output, &display->outputs, head) {
- if (output->crtc != crtc)
- continue;
+ if (modeset) {
+ /* disconnect unused outputs */
+ list_for_each_entry(output, &display->outputs, head) {
+ if (output->crtc)
+ crtc_mask |= 1 << output->crtc->index;
+ else
+ output->execute_mode(output, TRUE);
+ }
- rval = output->execute_mode(output, FALSE);
+ rval = crtc->set_mode(crtc, hw_mode);
if (rval != 0) {
- NV50_DEBUG("output execute mode failed\n");
+ NV50_DEBUG("crtc mode set failed\n");
goto out;
}
- }
- rval = crtc->set_scale(crtc);
- if (rval != 0) {
- NV50_DEBUG("crtc set scale failed\n");
- goto out;
- }
+ /* find native mode. */
+ list_for_each_entry(output, &display->outputs, head) {
+ if (output->crtc != crtc)
+ continue;
- /* next line changes crtc, so putting it here is important */
- display->last_crtc = crtc->index;
+ *crtc->native_mode = *output->native_mode;
+ list_for_each_entry(connector, &display->connectors, head) {
+ if (connector->output != output)
+ continue;
- /* blank any unused crtcs */
- list_for_each_entry(crtc, &display->crtcs, head) {
- if (!(crtc_mask & (1 << crtc->index)))
- crtc->blank(crtc, TRUE);
+ crtc->scaling_mode = connector->scaling_mode;
+ break;
+ }
+
+ if (crtc->scaling_mode == SCALE_PANEL)
+ crtc->use_native_mode = false;
+ else
+ crtc->use_native_mode = true;
+
+ break; /* no use in finding more than one mode */
+ }
+
+ rval = crtc->execute_mode(crtc);
+ if (rval != 0) {
+ NV50_DEBUG("crtc execute mode failed\n");
+ goto out;
+ }
+
+ list_for_each_entry(output, &display->outputs, head) {
+ if (output->crtc != crtc)
+ continue;
+
+ rval = output->execute_mode(output, FALSE);
+ if (rval != 0) {
+ NV50_DEBUG("output execute mode failed\n");
+ goto out;
+ }
+ }
+
+ rval = crtc->set_scale(crtc);
+ if (rval != 0) {
+ NV50_DEBUG("crtc set scale failed\n");
+ goto out;
+ }
+
+ /* next line changes crtc, so putting it here is important */
+ display->last_crtc = crtc->index;
+
+ /* blank any unused crtcs */
+ list_for_each_entry(crtc, &display->crtcs, head) {
+ if (!(crtc_mask & (1 << crtc->index)))
+ crtc->blank(crtc, TRUE);
+ }
}
display->update(display);
@@ -631,36 +743,35 @@ static int nv50_kms_encoders_init(struct drm_device *dev)
void nv50_kms_connector_detect_all(struct drm_device *dev)
{
struct drm_connector *drm_connector = NULL;
- enum drm_connector_status old, new;
- bool notify = false;
list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) {
- old = drm_connector->status;
- new = drm_connector->funcs->detect(drm_connector);
-
- if (new != old) {
- notify = true;
- drm_connector->funcs->fill_modes(drm_connector, 0, 0);
- }
+ drm_connector->funcs->detect(drm_connector);
}
-
- /* I think this is the hook that notifies of changes. */
- if (notify)
- dev->mode_config.funcs->fb_changed(dev);
}
static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector *drm_connector)
{
struct nv50_connector *connector = to_nv50_connector(drm_connector);
+ struct drm_device *dev = drm_connector->dev;
bool connected;
+ int old_status;
connected = connector->detect(connector);
+ old_status = drm_connector->status;
+
if (connected)
drm_connector->status = connector_status_connected;
else
drm_connector->status = connector_status_disconnected;
+ /* update our modes whenever there is reason to */
+ if (old_status != drm_connector->status) {
+ drm_connector->funcs->fill_modes(drm_connector, 0, 0);
+ /* notify fb of changes */
+ dev->mode_config.funcs->fb_changed(dev);
+ }
+
return drm_connector->status;
}
@@ -695,7 +806,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
struct drm_display_mode *mode, *t;
struct edid *edid = NULL;
- DRM_DEBUG("%s\n", drm_get_connector_name(drm_connector));
+ NV50_DEBUG("%s\n", drm_get_connector_name(drm_connector));
/* set all modes to the unverified state */
list_for_each_entry_safe(mode, t, &drm_connector->modes, head)
mode->status = MODE_UNVERIFIED;
@@ -708,7 +819,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
drm_connector->status = connector_status_disconnected;
if (!connected) {
- DRM_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector));
+ NV50_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector));
/* TODO set EDID to NULL */
return;
}
@@ -762,7 +873,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
struct nouveau_hw_mode *hw_mode;
struct nv50_output *output;
- DRM_DEBUG("No valid modes on %s\n", drm_get_connector_name(drm_connector));
+ NV50_DEBUG("No valid modes on %s\n", drm_get_connector_name(drm_connector));
/* Should we do this here ???
* When no valid EDID modes are available we end up
@@ -787,7 +898,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
drm_mode_sort(&drm_connector->modes);
- DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(drm_connector));
+ NV50_DEBUG("Probed modes for %s\n", drm_get_connector_name(drm_connector));
list_for_each_entry_safe(mode, t, &drm_connector->modes, head) {
mode->vrefresh = drm_mode_vrefresh(mode);
diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c
index 49f29fd3..75909c82 100644
--- a/linux-core/nv50_sor.c
+++ b/linux-core/nv50_sor.c
@@ -100,6 +100,10 @@ static int nv50_sor_set_clock_mode(struct nv50_output *output)
NV50_DEBUG("or %d\n", nv50_output_or_offset(output));
+ /* We don't yet know what to do, if anything at all. */
+ if (output->type == OUTPUT_LVDS)
+ return 0;
+
if (crtc->use_native_mode)
hw_mode = crtc->native_mode;
else