NV50: basic fbcon + misc fixes
authorMaarten Maathuis <madman2003@gmail.com>
Wed, 2 Jul 2008 14:13:54 +0000 (16:13 +0200)
committerMaarten Maathuis <madman2003@gmail.com>
Wed, 2 Jul 2008 14:14:48 +0000 (16:14 +0200)
- There is one fb, used for as many outputs as possible.
- Eventually smaller screens will be scaled to see the full console, but for the moment this'll do.

linux-core/Makefile.kernel
linux-core/nv50_display.c
linux-core/nv50_fbcon.c [new file with mode: 0644]
linux-core/nv50_fbcon.h [new file with mode: 0644]
linux-core/nv50_kms_wrapper.c
shared-core/nouveau_state.c

index 2343014..246c0b3 100644 (file)
@@ -38,7 +38,8 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
                nv04_instmem.o nv50_instmem.o \
                nouveau_bios.o \
                nv50_crtc.o nv50_cursor.o nv50_lut.o nv50_fb.o nv50_output.o nv50_sor.o nv50_dac.o nv50_connector.o nv50_i2c.o nv50_display.o \
-               nv50_kms_wrapper.o
+               nv50_kms_wrapper.o \
+               nv50_fbcon.o
 radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
 radeon_ms-objs := radeon_ms_drv.o radeon_ms_drm.o radeon_ms_family.o \
                radeon_ms_state.o radeon_ms_bo.o radeon_ms_irq.o \
index 1d82855..cd527c4 100644 (file)
@@ -337,10 +337,11 @@ void nv50_display_command(struct drm_nouveau_private *dev_priv, uint32_t mthd, u
 
        while (NV_READ(NV50_PDISPLAY_CTRL_STATE) & NV50_PDISPLAY_CTRL_STATE_PENDING) {
                counter++;
-               if (counter > 25000) {
+               if (counter > 1000000) {
                        DRM_ERROR("You probably need a reboot now\n");
                        break;
                }
+               udelay(1);
        }
 }
 
diff --git a/linux-core/nv50_fbcon.c b/linux-core/nv50_fbcon.c
new file mode 100644 (file)
index 0000000..c428ff9
--- /dev/null
@@ -0,0 +1,599 @@
+/*
+ * Copyright (C) 2008 Maarten Maathuis.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+#include "nv50_fbcon.h"
+
+static int nv50_fbcon_setcolreg(unsigned regno, unsigned red, unsigned green,
+                       unsigned blue, unsigned transp,
+                       struct fb_info *info)
+{
+       struct nv50_fbcon_par *par = info->par;
+       struct drm_device *dev = par->dev;
+       struct drm_framebuffer *drm_fb; 
+
+       list_for_each_entry(drm_fb, &dev->mode_config.fb_kernel_list, filp_head) {
+               if (regno > 255)
+                       return 1;
+
+               /* TODO: 8 bit support */
+               if (regno < 16) {
+                       switch (drm_fb->depth) {
+                       case 15:
+                               drm_fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
+                                       ((green & 0xf800) >>  6) |
+                                       ((blue & 0xf800) >> 11);
+                               break;
+                       case 16:
+                               drm_fb->pseudo_palette[regno] = (red & 0xf800) |
+                                       ((green & 0xfc00) >>  5) |
+                                       ((blue  & 0xf800) >> 11);
+                               break;
+                       case 24:
+                       case 32:
+                               drm_fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
+                                       (green & 0xff00) |
+                                       ((blue  & 0xff00) >> 8);
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int nv50_fbcon_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct nv50_fbcon_par *par = info->par;
+       struct drm_framebuffer *drm_fb = par->fb;
+       int depth;
+
+       NV50_DEBUG("\n");
+
+       if (!var || !drm_fb || !info) {
+               DRM_ERROR("No var, drm_fb or info\n");
+       }
+
+       par->use_preferred_mode = false;
+
+       if (var->pixclock == -1 || !var->pixclock) {
+               DRM_INFO("Using preferred mode.\n");
+               par->use_preferred_mode = true;
+       }
+
+       /* Need to resize the fb object !!! */
+       if (var->xres > drm_fb->width || var->yres > drm_fb->height) {
+               DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n", var->xres,var->yres, drm_fb->width, drm_fb->height);
+               DRM_ERROR("Need resizing code.\n");
+               return -EINVAL;
+       }
+
+       switch (var->bits_per_pixel) {
+       case 16:
+               depth = (var->green.length == 6) ? 16 : 15;
+               break;
+       case 32:
+               depth = (var->transp.length > 0) ? 32 : 24;
+               break;
+       default:
+               depth = var->bits_per_pixel;
+               break;
+       }
+
+       switch (depth) {
+       case 15:
+               var->red.offset = 10;
+               var->green.offset = 5;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 5;
+               var->blue.length = 5;
+               var->transp.length = 1;
+               var->transp.offset = 15;
+               break;
+       case 16:
+               var->red.offset = 11;
+               var->green.offset = 5;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 6;
+               var->blue.length = 5;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 24:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 32:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 8;
+               var->transp.offset = 24;
+               break;
+       default:
+               DRM_ERROR("Invalid depth %d\n", depth);
+               return -EINVAL; 
+       }
+
+       return 0;
+}
+
+static int nv50_fbcon_set_par(struct fb_info *info)
+{
+       struct nv50_fbcon_par *par;
+       struct drm_framebuffer *drm_fb;
+       struct drm_connector *drm_connector;
+       struct drm_crtc *drm_crtc;
+       struct fb_var_screeninfo *var;
+       struct drm_display_mode *drm_mode = NULL, *t;
+       struct drm_device *dev;
+       int rval;
+       bool crtc_used[2] = {false, false};
+
+       NV50_DEBUG("\n");
+
+       if (!info) {
+               DRM_ERROR("No fb_info\n");
+               return -EINVAL;
+       }
+
+       par = info->par;
+
+       if (!par) {
+               DRM_ERROR("No nv50_fbcon_par\n");
+               return -EINVAL;
+       }
+
+       drm_fb = par->fb;
+       var = &info->var;
+       dev = par->dev;
+
+       if (!drm_fb || !var || !dev) {
+               DRM_ERROR("No drm_fb, var or dev\n");
+               return -EINVAL;
+       }
+
+       par->use_preferred_mode = false;
+
+       if (var->pixclock == -1 || !var->pixclock) {
+               DRM_INFO("Using preferred mode.\n");
+               par->use_preferred_mode = true;
+       }
+
+       /* FB setup */
+       switch (var->bits_per_pixel) {
+       case 16:
+               drm_fb->depth = (var->green.length == 6) ? 16 : 15;
+               break;
+       case 32:
+               drm_fb->depth = (var->transp.length > 0) ? 32 : 24;
+               break;
+       default:
+               drm_fb->depth = var->bits_per_pixel;
+               break;
+       }
+
+       drm_fb->bits_per_pixel = var->bits_per_pixel;
+
+       info->fix.line_length = drm_fb->pitch;
+       info->fix.smem_len = info->fix.line_length * drm_fb->height;
+       /* ignoring 8bpp for the moment */
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+       info->screen_size = info->fix.smem_len; /* ??? */
+
+       /* create a drm mode */
+       if (!par->use_preferred_mode) {
+               drm_mode = drm_mode_create(dev);
+               drm_mode->hdisplay = var->xres;
+               drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
+               drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
+               drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
+               drm_mode->vdisplay = var->yres;
+               drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
+               drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
+               drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
+               drm_mode->clock = PICOS2KHZ(var->pixclock);
+               drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
+               drm_mode->flags = 0;
+               drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC;
+               drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC;
+
+               drm_mode_set_name(drm_mode);
+               drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V);
+       }
+
+       /* hook up crtc's */
+       list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) {
+               enum drm_connector_status status;
+               struct drm_mode_set mode_set;
+               int crtc_count = 0;
+
+               status = drm_connector->funcs->detect(drm_connector);
+
+               if (status != connector_status_connected)
+                       continue;
+
+               memset(&mode_set, 0, sizeof(struct drm_mode_set));
+
+               /* set connector */
+               mode_set.num_connectors = 1;
+               mode_set.connectors = kzalloc(sizeof(struct drm_connector *), GFP_KERNEL);
+               if (!mode_set.connectors) {
+                       rval = -ENOMEM;
+                       goto out;
+               }
+               mode_set.connectors[0] = drm_connector;
+
+               /* set fb */
+               list_for_each_entry(drm_fb, &dev->mode_config.fb_kernel_list, filp_head) {
+                       break; /* first entry is the only entry */
+               }
+               mode_set.fb = drm_fb;
+
+               /* set mode */
+               if (par->use_preferred_mode) {
+                       /* find preferred mode */
+                       list_for_each_entry_safe(drm_mode, t, &drm_connector->modes, head) {
+                               if (drm_mode->type & DRM_MODE_TYPE_PREFERRED)
+                                       break;
+                       }
+               }
+               mode_set.mode = drm_mode;
+
+               list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) {
+                       if (crtc_used[crtc_count]) {
+                               crtc_count++;
+                               continue;
+                       }
+
+                       /* found a crtc */
+                       mode_set.crtc = drm_crtc;
+
+                       break;
+               }
+
+               /* proceed as planned */
+               if (mode_set.crtc) {
+                       mode_set.crtc->funcs->set_config(&mode_set);
+                       crtc_used[crtc_count] = true;
+               }
+
+               kfree(mode_set.connectors);
+       }
+
+       return 0;
+
+out:
+       return rval;
+}
+
+static struct fb_ops nv50_fb_ops = {
+       .owner = THIS_MODULE,
+       //.fb_open = nv50_fb_open,
+       //.fb_read = nv50_fb_read,
+       //.fb_write = nv50_fb_write,
+       //.fb_release = nv50_fb_release,
+       //.fb_ioctl = nv50_fb_ioctl,
+       .fb_check_var = nv50_fbcon_check_var,
+       .fb_set_par = nv50_fbcon_set_par,
+       .fb_setcolreg = nv50_fbcon_setcolreg,
+       .fb_fillrect = cfb_fillrect,
+       .fb_copyarea = cfb_copyarea,
+       .fb_imageblit = cfb_imageblit,
+       //.fb_pan_display = nv50_fb_pan_display,
+};
+
+static int nv50_fbcon_initial_config(struct drm_device *dev)
+{
+       struct drm_connector *drm_connector;
+
+       struct drm_framebuffer *drm_fb = NULL;
+       struct drm_mode_fb_cmd drm_fb_cmd;
+       enum drm_connector_status status;
+       uint32_t max_width = 0, max_height = 0, pitch = 0;
+       struct mem_block *block;
+       struct drm_file *file_priv;
+       uint32_t flags;
+       int rval = 0;
+
+       list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) {
+               status = drm_connector->funcs->detect(drm_connector);
+
+               /* find the framebuffer size */
+               if (status == connector_status_connected) {
+                       struct drm_display_mode *mode, *t;
+                       list_for_each_entry_safe(mode, t, &drm_connector->modes, head) {
+                               if (mode->type & DRM_MODE_TYPE_PREFERRED) {
+                                       if (mode->hdisplay > max_width)
+                                               max_width = mode->hdisplay;
+                                       if (mode->vdisplay > max_height)
+                                               max_height = mode->vdisplay;
+                               }
+                       }
+               }
+       }
+
+       /* allocate framebuffer */
+       file_priv = kzalloc(sizeof(struct drm_file), GFP_KERNEL);
+       if (!file_priv) {
+               rval = -ENOMEM;
+               goto out;
+       }
+
+       pitch = (max_width + 63) & ~63;
+       pitch *= 4; /* TODO */
+
+       flags = NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED;
+
+       /* Any file_priv should do as it's pointer is used as identification. */
+       block = nouveau_mem_alloc(dev, 0, pitch * max_height, flags, file_priv);
+       if (!block) {
+               rval = -ENOMEM;
+               goto out;
+       }
+
+       memset(&drm_fb_cmd, 0, sizeof(struct drm_mode_fb_cmd));
+
+       drm_fb_cmd.width = max_width;
+       drm_fb_cmd.height = max_height;
+       drm_fb_cmd.pitch = pitch;
+       drm_fb_cmd.bpp = 32; /* TODO */
+       drm_fb_cmd.handle = block->map_handle;
+       drm_fb_cmd.depth = 24; /* TODO */
+
+       drm_fb = dev->mode_config.funcs->fb_create(dev, file_priv, &drm_fb_cmd);
+       if (!drm_fb) {
+               rval = -EINVAL;
+               goto out;
+       }
+
+       list_add(&drm_fb->filp_head, &dev->mode_config.fb_kernel_list);
+
+       return 0;
+
+out:
+       if (file_priv)
+               kfree(file_priv);
+       if (drm_fb)
+               drm_fb->funcs->destroy(drm_fb);
+
+       return rval;
+}
+
+/*
+ * Single framebuffer, ideally operating in clone mode across various connectors.
+ */
+int nv50_fbcon_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct fb_info *info;
+       struct nv50_fbcon_par *par;
+       struct device *device = &dev->pdev->dev;
+       struct drm_framebuffer *drm_fb;
+       struct mem_block *block;
+       void __iomem *fb = NULL;
+       int rval;
+
+       rval = nv50_fbcon_initial_config(dev);
+       if (rval != 0) {
+               DRM_ERROR("nv50_fbcon_initial_config failed\n");
+               return rval;
+       }
+
+       list_for_each_entry(drm_fb, &dev->mode_config.fb_kernel_list, filp_head) {
+               break; /* first entry is the only entry */
+       }
+
+       if (!drm_fb) {
+               DRM_ERROR("no drm_fb found\n");
+               return -EINVAL;
+       }
+
+       block = find_block_by_handle(dev_priv->fb_heap, drm_fb->mm_handle);
+       if (!block) {
+               DRM_ERROR("can't find mem_block\n");
+               return -EINVAL;
+       }
+
+       info = framebuffer_alloc(sizeof(struct nv50_fbcon_par), device);
+       if (!info) {
+               DRM_ERROR("framebuffer_alloc failed\n");
+               return -EINVAL;
+       }
+
+       par = info->par;
+
+       strcpy(info->fix.id, "nv50drmfb");
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->fix.type_aux = 0;
+       info->fix.xpanstep = 0; /* 1 is doing it in hw */
+       info->fix.ypanstep = 0;
+       info->fix.ywrapstep = 0;
+       info->fix.accel = FB_ACCEL_NONE;
+       info->fix.type_aux = 0;
+
+       info->flags = FBINFO_DEFAULT;
+
+       info->fbops = &nv50_fb_ops;
+
+       info->fix.line_length = drm_fb->pitch;
+       info->fix.smem_start = dev_priv->fb_phys + block->start;
+       info->fix.smem_len = info->fix.line_length * drm_fb->height;
+
+       info->flags = FBINFO_DEFAULT;
+
+       fb = ioremap(dev_priv->fb_phys + block->start, block->size);
+       if (!fb) {
+               DRM_ERROR("Unable to ioremap framebuffer\n");
+               return -EINVAL;
+       }
+
+       info->screen_base = fb;
+       info->screen_size = info->fix.smem_len; /* FIXME */
+
+       info->pseudo_palette = drm_fb->pseudo_palette;
+       info->var.xres_virtual = drm_fb->width;
+       info->var.yres_virtual = drm_fb->height;
+       info->var.bits_per_pixel = drm_fb->bits_per_pixel;
+       info->var.xoffset = 0;
+       info->var.yoffset = 0;
+       info->var.activate = FB_ACTIVATE_NOW;
+       info->var.height = -1;
+       info->var.width = -1;
+
+       /* TODO: improve this */
+       info->var.xres = drm_fb->width;
+       info->var.yres = drm_fb->height;
+
+       info->fix.mmio_start = drm_get_resource_start(dev, 0);
+       info->fix.mmio_len = drm_get_resource_len(dev, 0);
+
+       DRM_DEBUG("fb depth is %d\n", drm_fb->depth);
+       DRM_DEBUG("   pitch is %d\n", drm_fb->pitch);
+
+       switch(drm_fb->depth) {
+       case 15:
+               info->var.red.offset = 10;
+               info->var.green.offset = 5;
+               info->var.blue.offset = 0;
+               info->var.red.length = 5;
+               info->var.green.length = 5;
+               info->var.blue.length = 5;
+               info->var.transp.offset = 15;
+               info->var.transp.length = 1;
+               break;
+       case 16:
+               info->var.red.offset = 11;
+               info->var.green.offset = 5;
+               info->var.blue.offset = 0;
+               info->var.red.length = 5;
+               info->var.green.length = 6;
+               info->var.blue.length = 5;
+               info->var.transp.offset = 0;
+               break;
+       case 24:
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+               info->var.red.length = 8;
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.transp.offset = 0;
+               info->var.transp.length = 0;
+               break;
+       case 32:
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+               info->var.red.length = 8;
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.transp.offset = 24;
+               info->var.transp.length = 8;
+               break;
+       default:
+               break;
+       }
+
+       drm_fb->fbdev = info;
+       par->dev = dev;
+       par->fb = drm_fb;
+
+       register_framebuffer(info);
+
+       DRM_INFO("nv50drmfb initialised\n");
+
+       return 0;
+}
+
+int nv50_fbcon_destroy(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct drm_framebuffer *drm_fb;
+       struct fb_info *info;
+       struct mem_block *block;
+       struct drm_file *file_priv;
+
+       list_for_each_entry(drm_fb, &dev->mode_config.fb_kernel_list, filp_head) {
+               break; /* first entry is the only entry */
+       }
+
+       if (!drm_fb) {
+               DRM_ERROR("No framebuffer to destroy\n");
+               return -EINVAL;
+       }
+
+       info = drm_fb->fbdev;
+       if (!info) {
+               DRM_ERROR("No fb_info\n");
+               return -EINVAL;
+       }
+
+       unregister_framebuffer(info);
+
+       block = find_block_by_handle(dev_priv->fb_heap, drm_fb->mm_handle);
+       if (!block) {
+               DRM_ERROR("can't find mem_block\n");
+               return -EINVAL;
+       }
+
+       /* we need to free this after memory is freed */
+       file_priv = block->file_priv;
+
+       /* free memory */
+       nouveau_mem_free(dev, block);
+
+       if (file_priv) {
+               kfree(file_priv);
+               file_priv = NULL;
+       }
+
+       framebuffer_release(info);
+
+       return 0;
+}
diff --git a/linux-core/nv50_fbcon.h b/linux-core/nv50_fbcon.h
new file mode 100644 (file)
index 0000000..98e7101
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 Maarten Maathuis.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __NV50_FBCON_H__
+#define __NV50_FBCON_H__
+
+#include "nv50_kms_wrapper.h"
+
+struct nv50_fbcon_par {
+       struct drm_framebuffer *fb;
+       struct drm_device *dev;
+       bool use_preferred_mode;
+};
+
+int nv50_fbcon_init(struct drm_device *dev);
+int nv50_fbcon_destroy(struct drm_device *dev);
+
+#endif /* __NV50_FBCON_H__ */
\ No newline at end of file
index 7f1a095..2a214f6 100644 (file)
@@ -153,6 +153,7 @@ static void nv50_kms_mirror_routing(struct drm_device *dev)
        struct nv50_output *output = NULL;
        struct nv50_connector *connector = NULL;
        struct drm_connector *drm_connector = NULL;
+       struct drm_crtc *drm_crtc = NULL;
 
        /* Wipe all previous connections. */
        list_for_each_entry(connector, &display->connectors, item) {
@@ -179,6 +180,13 @@ static void nv50_kms_mirror_routing(struct drm_device *dev)
                        }
                }
        }
+
+       /* mirror crtc active state */
+       list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) {
+               crtc = to_nv50_crtc(drm_crtc);
+
+               crtc->active = drm_crtc->enabled;
+       }
 }
 
 /*
@@ -428,8 +436,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
                        drm_crtc = drm_encoder->crtc;
                        drm_encoder->crtc = NULL;
 
-                       crtc = to_nv50_crtc(drm_crtc);
-                       crtc->active = false;
                        drm_crtc->enabled = false;
                }
 
@@ -456,6 +462,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
                        }
 
                        drm_encoder->crtc = set->crtc;
+                       set->crtc->enabled = true;
                        drm_connector->encoder = drm_encoder;
                }
        }
@@ -468,7 +475,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
                crtc = to_nv50_crtc(set->crtc);
 
                /* keeping the encoders and connectors attached, so they can be tracked */
-               crtc->active = false;
                set->crtc->enabled = false;
        }
 
index 9f8fc43..3baae6a 100644 (file)
@@ -28,6 +28,7 @@
 #include "nouveau_drv.h"
 #include "nouveau_drm.h"
 #include "nv50_kms_wrapper.h"
+#include "nv50_fbcon.h"
 
 static int nouveau_init_card_mappings(struct drm_device *dev)
 {
@@ -367,7 +368,8 @@ nouveau_card_init(struct drm_device *dev)
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                if (dev_priv->card_type >= NV_50) {
                        nv50_kms_init(dev);
-                       nv50_kms_connector_detect_all(dev);
+                       //nv50_kms_connector_detect_all(dev);
+                       nv50_fbcon_init(dev);
                }
 
        return 0;
@@ -615,6 +617,7 @@ int nouveau_unload(struct drm_device *dev)
 {
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                nv50_kms_destroy(dev);
+               nv50_fbcon_destroy(dev);
                nouveau_close(dev);
        }