From a18b4befb9b76c4b2662ff6caa0e4f0975eb8e9c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 17 May 2007 09:00:06 -0700 Subject: Fix FB pitch value (we had it wrong and were working around it in a few places). Add new FB hooks to the drm driver structure and make i915 use them for an Intel specific FB driver. This will allow acceleration and better handling of the command stream. --- linux-core/intel_fb.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 linux-core/intel_fb.c (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c new file mode 100644 index 00000000..267b4fd6 --- /dev/null +++ b/linux-core/intel_fb.c @@ -0,0 +1,358 @@ +/* + * Copyright © 2007 David Airlie + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Authors: + * David Airlie + */ + /* + * Modularization + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +struct intelfb_par { + struct drm_device *dev; + struct drm_framebuffer *fb; +}; + +static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct intelfb_par *par = info->par; + struct drm_framebuffer *fb = par->fb; + if (regno > 17) + return 1; + + if (regno < 16) { + switch (fb->depth) { + case 15: + fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 16: + fb->pseudo_palette[regno] = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 24: + case 32: + fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + } + + return 0; +} + +/* this will let fbcon do the mode init */ +static int intelfb_set_par(struct fb_info *info) +{ + struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; + + drm_set_desired_modes(dev); + return 0; +} + +static void intelfb_copyarea(struct fb_info *info, + const struct fb_copyarea *region) +{ + struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 src_x1, src_y1, dst_x1, dst_y1, dst_x2, dst_y2, offset; + u32 cmd, rop_depth_pitch, src_pitch; + RING_LOCALS; + + cmd = XY_SRC_COPY_BLT_CMD; + src_x1 = region->sx; + src_y1 = region->sy; + dst_x1 = region->dx; + dst_y1 = region->dy; + dst_x2 = region->dx + region->width; + dst_y2 = region->dy + region->height; + offset = par->fb->offset; + rop_depth_pitch = BLT_ROP_GXCOPY | par->fb->pitch; + src_pitch = par->fb->pitch; + + switch (par->fb->bits_per_pixel) { + case 16: + rop_depth_pitch |= BLT_DEPTH_16_565; + break; + case 32: + rop_depth_pitch |= BLT_DEPTH_32; + cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB; + break; + } + + BEGIN_LP_RING(8); + OUT_RING(cmd); + OUT_RING(rop_depth_pitch); + OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff)); + OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff)); + OUT_RING(offset); + OUT_RING((src_y1 << 16) | (src_x1 & 0xffff)); + OUT_RING(src_pitch); + OUT_RING(offset); + ADVANCE_LP_RING(); +} + +#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) +#define ROUND_DOWN_TO(x, y) ((x) / (y) * (y)) + +void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 cmd, rop_pitch_depth, tmp; + int nbytes, ndwords, pad; + u32 dst_x1, dst_y1, dst_x2, dst_y2, offset, bg, fg; + int dat, ix, iy, iw; + int i, j; + RING_LOCALS; + + /* size in bytes of a padded scanline */ + nbytes = ROUND_UP_TO(image->width, 16) / 8; + + /* Total bytes of padded scanline data to write out. */ + nbytes *= image->height; + + /* + * Check if the glyph data exceeds the immediate mode limit. + * It would take a large font (1K pixels) to hit this limit. + */ + if (nbytes > 128 || image->depth != 1) + return cfb_imageblit(info, image); + + /* Src data is packaged a dword (32-bit) at a time. */ + ndwords = ROUND_UP_TO(nbytes, 4) / 4; + + /* + * Ring has to be padded to a quad word. But because the command starts + with 7 bytes, pad only if there is an even number of ndwords + */ + pad = !(ndwords % 2); + + DRM_DEBUG("imageblit %dx%dx%d to (%d,%d)\n", image->width, + image->height, image->depth, image->dx, image->dy); + DRM_DEBUG("nbytes: %d, ndwords: %d, pad: %d\n", nbytes, ndwords, pad); + + tmp = (XY_MONO_SRC_COPY_IMM_BLT & 0xff) + ndwords; + cmd = (XY_MONO_SRC_COPY_IMM_BLT & ~0xff) | tmp; + offset = par->fb->offset; + dst_x1 = image->dx; + dst_y1 = image->dy; + dst_x2 = image->dx + image->width; + dst_y2 = image->dy + image->height; + rop_pitch_depth = BLT_ROP_GXCOPY | par->fb->pitch; + + switch (par->fb->bits_per_pixel) { + case 8: + rop_pitch_depth |= BLT_DEPTH_8; + fg = image->fg_color; + bg = image->bg_color; + break; + case 16: + rop_pitch_depth |= BLT_DEPTH_16_565; + fg = par->fb->pseudo_palette[image->fg_color]; + bg = par->fb->pseudo_palette[image->bg_color]; + break; + case 32: + rop_pitch_depth |= BLT_DEPTH_32; + cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB; + fg = par->fb->pseudo_palette[image->fg_color]; + bg = par->fb->pseudo_palette[image->bg_color]; + break; + default: + DRM_ERROR("unknown depth %d\n", par->fb->bits_per_pixel); + break; + } + + BEGIN_LP_RING(8 + ndwords); + OUT_RING(cmd); + OUT_RING(rop_pitch_depth); + OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff)); + OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff)); + OUT_RING(offset); + OUT_RING(bg); + OUT_RING(fg); + ix = iy = 0; + iw = ROUND_UP_TO(image->width, 8) / 8; + while (ndwords--) { + dat = 0; + for (j = 0; j < 2; ++j) { + for (i = 0; i < 2; ++i) { + if (ix != iw || i == 0) + dat |= image->data[iy*iw + ix++] << (i+j*2)*8; + } + if (ix == iw && iy != (image->height - 1)) { + ix = 0; + ++iy; + } + } + OUT_RING(dat); + } + if (pad) + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); +} + +static struct fb_ops intelfb_ops = { + .owner = THIS_MODULE, + // .fb_open = intelfb_open, + // .fb_read = intelfb_read, + // .fb_write = intelfb_write, + // .fb_release = intelfb_release, + // .fb_ioctl = intelfb_ioctl, + .fb_set_par = intelfb_set_par, + .fb_setcolreg = intelfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, //intelfb_copyarea, + .fb_imageblit = intelfb_imageblit, +}; + +int intelfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) +{ + struct fb_info *info; + struct intelfb_par *par; + struct device *device = &dev->pdev->dev; + int ret; + + info = framebuffer_alloc(sizeof(struct intelfb_par), device); + if (!info){ + return -EINVAL; + } + + fb->fbdev = info; + + par = info->par; + + par->dev = dev; + par->fb = fb; + + info->fbops = &intelfb_ops; + + strcpy(info->fix.id, "intelfb"); + info->fix.smem_start = fb->offset + dev->mode_config.fb_base; + info->fix.smem_len = fb->bo->mem.size; + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + info->fix.xpanstep = 8; + info->fix.ypanstep = 1; + info->fix.ywrapstep = 0; + info->fix.visual = FB_VISUAL_DIRECTCOLOR; + info->fix.accel = FB_ACCEL_I830; + info->fix.type_aux = 0; + info->fix.mmio_start = 0; + info->fix.mmio_len = 0; + info->fix.line_length = fb->pitch; + + info->flags = FBINFO_DEFAULT; + + ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base); + if (ret) + DRM_ERROR("error mapping fb: %d\n", ret); + + info->screen_base = fb->virtual_base; + info->screen_size = fb->bo->mem.size; + info->pseudo_palette = fb->pseudo_palette; + info->var.xres = fb->width; + info->var.xres_virtual = fb->width; + info->var.yres = fb->height; + info->var.yres_virtual = fb->height; + info->var.bits_per_pixel = 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; + info->var.vmode = FB_VMODE_NONINTERLACED; + + info->pixmap.size = 64*1024; + info->pixmap.buf_align = 8; + info->pixmap.access_align = 32; + info->pixmap.flags = FB_PIXMAP_SYSTEM; + info->pixmap.scan_align = 1; + + DRM_DEBUG("fb depth is %d\n", fb->depth); + DRM_DEBUG(" pitch is %d\n", fb->pitch); + switch(fb->depth) { + case 8: + case 15: + case 16: + break; + default: + case 24: + case 32: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = info->var.green.length = + info->var.blue.length = 8; + if (fb->depth == 32) { + info->var.transp.offset = 24; + info->var.transp.length = 8; + } + break; + } + + if (register_framebuffer(info) < 0) + return -EINVAL; + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + return 0; +} +EXPORT_SYMBOL(intelfb_probe); + +int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) +{ + struct fb_info *info = fb->fbdev; + + if (info) { + unregister_framebuffer(info); + framebuffer_release(info); + drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); + } + return 0; +} +EXPORT_SYMBOL(intelfb_remove); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From c0479dad8e34a51efebfaa05b0d329aa7d2b95d1 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 17 May 2007 19:32:46 +0100 Subject: bring in change from drm_fb.c --- linux-core/intel_fb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 7126c16c..9d7b7327 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -504,7 +504,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->var.vsync_len = mode->vsync_end - mode->vsync_start; info->var.upper_margin = mode->vtotal - mode->vsync_end; info->var.pixclock = 10000000 / mode->htotal * 1000 / - mode->vtotal * 100000 / mode->vrefresh; + mode->vtotal * 100; + /* avoid overflow */ + info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; info->pixmap.size = 64*1024; info->pixmap.buf_align = 8; -- cgit v1.2.3 From 95945bbf226610ba4f41381fd0436722082397ec Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 17 May 2007 23:33:48 +0100 Subject: Set crtcinfo on temporary mode --- linux-core/intel_fb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 9d7b7327..3c865a2f 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -262,6 +262,7 @@ static int intelfb_set_par(struct fb_info *info) drm_mode->clock = PICOS2KHZ(var->pixclock); drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); drm_mode_set_name(drm_mode); + drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); #endif if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) -- cgit v1.2.3 From 0c33a2cd2ec81478403d39b1b92aaa4431e7cf0a Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Fri, 18 May 2007 14:16:10 +0100 Subject: Move fbo creation to the specified fb driver which gives it a chance to allocate the memory from whichever buffer it wants to. --- linux-core/intel_fb.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 3c865a2f..ceeefc8c 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -210,7 +210,6 @@ static int intelfb_set_par(struct fb_info *info) struct drm_device *dev = par->dev; struct drm_display_mode *drm_mode; struct fb_var_screeninfo *var = &info->var; - struct drm_output *output; switch (var->bits_per_pixel) { case 16: @@ -444,8 +443,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) struct fb_info *info; struct intelfb_par *par; struct device *device = &dev->pdev->dev; - struct drm_framebuffer *fb = crtc->fb; + struct drm_framebuffer *fb; struct drm_display_mode *mode = crtc->desired_mode; + drm_buffer_object_t *fbo = NULL; int ret; info = framebuffer_alloc(sizeof(struct intelfb_par), device); @@ -453,6 +453,41 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) return -EINVAL; } + fb = drm_framebuffer_create(dev); + if (!fb) { + framebuffer_release(info); + DRM_ERROR("failed to allocate fb.\n"); + return -EINVAL; + } + crtc->fb = fb; + + fb->width = crtc->desired_mode->hdisplay; + fb->height = crtc->desired_mode->vdisplay; + + fb->bits_per_pixel = 32; + fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); + fb->depth = 24; + ret = drm_buffer_object_create(dev, + fb->width * fb->height * 4, + drm_bo_type_kernel, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_PRIV0 | /* FIXME! */ + DRM_BO_FLAG_NO_MOVE, + 0, 0, 0, + &fbo); + if (ret || !fbo) { + printk(KERN_ERR "failed to allocate framebuffer\n"); + drm_framebuffer_destroy(fb); + framebuffer_release(info); + return -EINVAL; + } + fb->offset = fbo->offset; + fb->bo = fbo; + printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, + fb->height, fbo->offset, fbo); + + fb->fbdev = info; par = info->par; -- cgit v1.2.3 From f89458722173b364b8c3c27788b6c61889da554c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 18 May 2007 09:40:01 -0700 Subject: Add locking. The main lock is dev->mode_config.config_lock. It should be held across any operations that modify mode lists, crtc config, output config, etc. It should be taken at high level entry points (currently just initial config and user IOCTL). Seems to work ok on my system, but needs more testing (with lockdep) and review from some fresh eyes. --- linux-core/intel_fb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 7126c16c..2ce66460 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -203,6 +203,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, } /* this will let fbcon do the mode init */ +/* FIXME: take mode config lock? */ static int intelfb_set_par(struct fb_info *info) { struct intelfb_par *par = info->par; -- cgit v1.2.3 From e918d2b7814e2cf5345dba63031c402010b1d3e4 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 22 May 2007 13:38:58 -0700 Subject: Call preallocated space VRAM instead of PRIV0 to be more consistent with other drivers. --- linux-core/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 449ef543..3bfbcda3 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -473,7 +473,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_PRIV0 | /* FIXME! */ + DRM_BO_FLAG_MEM_VRAM | /* FIXME! */ DRM_BO_FLAG_NO_MOVE, 0, 0, 0, &fbo); -- cgit v1.2.3 From 2ed12b6b7eee8a1b5b0adf0cd8f3cb8c1bc3ccaf Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 27 Sep 2007 14:21:03 +0100 Subject: Add some more checks to modelist walking for matching incoming modes to current modelist. --- linux-core/intel_fb.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 048295ab..04fd0fdd 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -49,6 +49,17 @@ struct intelfb_par { struct drm_crtc *crtc; }; +static int +var_to_refresh(const struct fb_var_screeninfo *var) +{ + int xtot = var->xres + var->left_margin + var->right_margin + + var->hsync_len; + int ytot = var->yres + var->upper_margin + var->lower_margin + + var->vsync_len; + + return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot; +} + static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) @@ -98,7 +109,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, struct drm_framebuffer *fb = par->crtc->fb; struct drm_display_mode *drm_mode; struct drm_output *output; - int depth; + int depth, found = 0; if (!var->pixclock) return -EINVAL; @@ -191,11 +202,14 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, list_for_each_entry(drm_mode, &output->modes, head) { if (drm_mode->hdisplay == var->xres && drm_mode->vdisplay == var->yres && - drm_mode->clock != 0) + (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && + (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { + found = 1; break; + } } - if (!drm_mode) + if (!found) return -EINVAL; #endif @@ -210,7 +224,9 @@ static int intelfb_set_par(struct fb_info *info) struct drm_framebuffer *fb = par->crtc->fb; struct drm_device *dev = par->dev; struct drm_display_mode *drm_mode; + struct drm_output *output; struct fb_var_screeninfo *var = &info->var; + int found = 0; switch (var->bits_per_pixel) { case 16: @@ -246,9 +262,18 @@ static int intelfb_set_par(struct fb_info *info) list_for_each_entry(drm_mode, &output->modes, head) { if (drm_mode->hdisplay == var->xres && drm_mode->vdisplay == var->yres && - drm_mode->clock != 0) + (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && + (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { + found = 1; break; + } } + + if (!found) { + DRM_ERROR("Couldn't find a mode for requested %dx%d-%d\n", + var->xres,var->yres,var_to_refresh(var)); + return -EINVAL; + } #else drm_mode = drm_mode_create(dev); drm_mode->hdisplay = var->xres; @@ -265,13 +290,15 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); #endif + drm_mode_debug_printmodeline(dev, drm_mode); + if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) return -EINVAL; /* Have to destroy our created mode if we're not searching the mode * list for it. */ -#if 1 +#if 1 drm_mode_destroy(dev, drm_mode); #endif @@ -472,6 +499,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM, 0, 0, 0, &fbo); @@ -629,6 +657,7 @@ int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) unregister_framebuffer(info); framebuffer_release(info); drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); + drm_framebuffer_destroy(fb); } return 0; } -- cgit v1.2.3 From cc9be8ac323e47616e48adebc5cc85c654524b45 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 15 Oct 2007 11:51:19 +0100 Subject: Fix some buffer teardown problems. --- linux-core/intel_fb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 04fd0fdd..ecfab3ed 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -657,6 +657,7 @@ int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) unregister_framebuffer(info); framebuffer_release(info); drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); + drm_bo_usage_deref_locked(&fb->bo); drm_framebuffer_destroy(fb); } return 0; -- cgit v1.2.3 From 2b07b0a45d32a9ffb7f6b9bb1b8f6f8e615524cb Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 15 Oct 2007 11:54:18 +0100 Subject: should be unlocked --- linux-core/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index ecfab3ed..c9cb293a 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -657,7 +657,7 @@ int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) unregister_framebuffer(info); framebuffer_release(info); drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); - drm_bo_usage_deref_locked(&fb->bo); + drm_bo_usage_deref_unlocked(&fb->bo); drm_framebuffer_destroy(fb); } return 0; -- cgit v1.2.3 From 53b4e0cb789151164a0a43b55058319667847aaf Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 26 Nov 2007 14:05:49 +1100 Subject: drm: make fb modes use usermode add/remove interface this stops usermode from getting a mode in the crtc it can't make sense off. --- linux-core/intel_fb.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 564a913e..3a4ffc7f 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -47,6 +47,7 @@ struct intelfb_par { struct drm_device *dev; struct drm_crtc *crtc; + struct drm_display_mode *fb_mode; }; static int @@ -107,7 +108,6 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, struct intelfb_par *par = info->par; struct drm_device *dev = par->dev; struct drm_framebuffer *fb = par->crtc->fb; - struct drm_display_mode *drm_mode; struct drm_output *output; int depth, found = 0; @@ -275,6 +275,7 @@ static int intelfb_set_par(struct fb_info *info) return -EINVAL; } #else + drm_mode = drm_mode_create(dev); drm_mode->hdisplay = var->xres; drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; @@ -290,18 +291,16 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); #endif + drm_mode_addmode(dev, drm_mode); + if (par->fb_mode) + drm_mode_rmmode(dev, par->fb_mode); + + par->fb_mode = drm_mode; drm_mode_debug_printmodeline(dev, drm_mode); if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) return -EINVAL; - /* Have to destroy our created mode if we're not searching the mode - * list for it. - */ -#if 1 - drm_mode_destroy(dev, drm_mode); -#endif - return 0; } -- cgit v1.2.3 From f9ac54b0319b273de83a004d6cfdf46a3b9d6ced Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 26 Nov 2007 15:06:42 +1100 Subject: fb: make fb interface use user mode attach/detach for adding modes --- linux-core/intel_fb.c | 65 ++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 35 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 3a4ffc7f..5f43f291 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -223,7 +223,7 @@ static int intelfb_set_par(struct fb_info *info) struct intelfb_par *par = info->par; struct drm_framebuffer *fb = par->crtc->fb; struct drm_device *dev = par->dev; - struct drm_display_mode *drm_mode; + struct drm_display_mode *drm_mode, *search_mode; struct drm_output *output; struct fb_var_screeninfo *var = &info->var; int found = 0; @@ -248,34 +248,7 @@ static int intelfb_set_par(struct fb_info *info) info->screen_size = info->fix.smem_len; /* ??? */ - /* Should we walk the output's modelist or just create our own ??? - * For now, we create and destroy a mode based on the incoming - * parameters. But there's commented out code below which scans - * the output list too. - */ -#if 0 - list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->crtc) - break; - } - - list_for_each_entry(drm_mode, &output->modes, head) { - if (drm_mode->hdisplay == var->xres && - drm_mode->vdisplay == var->yres && - (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && - (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { - found = 1; - break; - } - } - - if (!found) { - DRM_ERROR("Couldn't find a mode for requested %dx%d-%d\n", - var->xres,var->yres,var_to_refresh(var)); - return -EINVAL; - } -#else - + /* create a drm mode */ drm_mode = drm_mode_create(dev); drm_mode->hdisplay = var->xres; drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; @@ -289,14 +262,36 @@ static int intelfb_set_par(struct fb_info *info) drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); drm_mode_set_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); -#endif - drm_mode_addmode(dev, drm_mode); - if (par->fb_mode) - drm_mode_rmmode(dev, par->fb_mode); + list_for_each_entry(output, &dev->mode_config.output_list, head) { + if (output->crtc == par->crtc) + break; + } + + drm_mode_debug_printmodeline(dev, drm_mode); + list_for_each_entry(search_mode, &output->modes, head) { + DRM_ERROR("mode %s : %s\n", drm_mode->name, search_mode->name); + drm_mode_debug_printmodeline(dev, search_mode); + if (drm_mode_equal(drm_mode, search_mode)) { + drm_mode_destroy(dev, drm_mode); + drm_mode = search_mode; + found = 1; + break; + } + } - par->fb_mode = drm_mode; - drm_mode_debug_printmodeline(dev, drm_mode); + if (!found) { + drm_mode_addmode(dev, drm_mode); + if (par->fb_mode) { + drm_mode_detachmode_crtc(dev, par->fb_mode); + drm_mode_rmmode(dev, par->fb_mode); + } + + par->fb_mode = drm_mode; + drm_mode_debug_printmodeline(dev, drm_mode); + /* attach mode */ + drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode); + } if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) return -EINVAL; -- cgit v1.2.3 From 96df9b11ad8974d7a2a0a589114cbbb04a584f18 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Dec 2007 13:42:32 +1000 Subject: finish of mode add/remove, just have attach/detach modes --- linux-core/intel_fb.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 5f43f291..a8c9188d 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -281,10 +281,8 @@ static int intelfb_set_par(struct fb_info *info) } if (!found) { - drm_mode_addmode(dev, drm_mode); if (par->fb_mode) { drm_mode_detachmode_crtc(dev, par->fb_mode); - drm_mode_rmmode(dev, par->fb_mode); } par->fb_mode = drm_mode; -- cgit v1.2.3 From 1a07dd5ffd014aae8f767ab1f5166131aa27ef3f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Dec 2007 15:28:26 +1000 Subject: hooks up sync and flags and also clocks to get mode matching better --- linux-core/intel_fb.c | 52 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index a8c9188d..0a3a00b5 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -216,6 +216,32 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, return 0; } +bool i915_drmfb_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2, unsigned int pixclock) +{ + + if (mode1->hdisplay == mode2->hdisplay && + mode1->hsync_start == mode2->hsync_start && + mode1->hsync_end == mode2->hsync_end && + mode1->htotal == mode2->htotal && + mode1->hskew == mode2->hskew && + mode1->vdisplay == mode2->vdisplay && + mode1->vsync_start == mode2->vsync_start && + mode1->vsync_end == mode2->vsync_end && + mode1->vtotal == mode2->vtotal && + mode1->vscan == mode2->vscan && + mode1->flags == mode2->flags) + { + if (mode1->clock == mode2->clock) + return true; + + if (KHZ2PICOS(mode2->clock) == pixclock) + return true; + return false; + } + + return false; +} + /* this will let fbcon do the mode init */ /* FIXME: take mode config lock? */ static int intelfb_set_par(struct fb_info *info) @@ -260,6 +286,10 @@ static int intelfb_set_par(struct fb_info *info) 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); @@ -270,9 +300,8 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_debug_printmodeline(dev, drm_mode); list_for_each_entry(search_mode, &output->modes, head) { - DRM_ERROR("mode %s : %s\n", drm_mode->name, search_mode->name); drm_mode_debug_printmodeline(dev, search_mode); - if (drm_mode_equal(drm_mode, search_mode)) { + if (i915_drmfb_mode_equal(drm_mode, search_mode, var->pixclock)) { drm_mode_destroy(dev, drm_mode); drm_mode = search_mode; found = 1; @@ -550,7 +579,6 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->var.activate = FB_ACTIVATE_NOW; info->var.height = -1; info->var.width = -1; - info->var.vmode = FB_VMODE_NONINTERLACED; info->var.xres = mode->hdisplay; info->var.right_margin = mode->hsync_start - mode->hdisplay; @@ -560,10 +588,20 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->var.lower_margin = mode->vsync_start - mode->vdisplay; info->var.vsync_len = mode->vsync_end - mode->vsync_start; info->var.upper_margin = mode->vtotal - mode->vsync_end; - info->var.pixclock = 10000000 / mode->htotal * 1000 / - mode->vtotal * 100; - /* avoid overflow */ - info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; + info->var.pixclock = KHZ2PICOS(mode->clock); + + if (mode->flags & V_PHSYNC) + info->var.sync |= FB_SYNC_HOR_HIGH_ACT; + + if (mode->flags & V_PVSYNC) + info->var.sync |= FB_SYNC_VERT_HIGH_ACT; + + if (mode->flags & V_INTERLACE) + info->var.vmode = FB_VMODE_INTERLACED; + else if (mode->flags & V_DBLSCAN) + info->var.vmode = FB_VMODE_DOUBLE; + else + info->var.vmode = FB_VMODE_NONINTERLACED; info->pixmap.size = 64*1024; info->pixmap.buf_align = 8; -- cgit v1.2.3 From 8020724615eb6f334d5f90b1e83e6a46d4a126ac Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Dec 2007 11:46:54 +1000 Subject: check previous mode first --- linux-core/intel_fb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 0a3a00b5..c81e4408 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -320,9 +320,11 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode); } - if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) + if (par->crtc->enabled) { + if (!drm_mode_equal(&par->crtc->mode, drm_mode)) + if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) return -EINVAL; - + } return 0; } -- cgit v1.2.3 From 9814e87016ff90556ae34e3395c10d29add2ba08 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Dec 2007 11:47:29 +1000 Subject: retab intelfb code --- linux-core/intel_fb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index c81e4408..32c7dc31 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -321,9 +321,9 @@ static int intelfb_set_par(struct fb_info *info) } if (par->crtc->enabled) { - if (!drm_mode_equal(&par->crtc->mode, drm_mode)) - if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) - return -EINVAL; + if (!drm_mode_equal(&par->crtc->mode, drm_mode)) + if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) + return -EINVAL; } return 0; } -- cgit v1.2.3 From e239882b1e90cba0297118ec7dc432bea06b0bd0 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 4 Dec 2007 15:36:36 +0100 Subject: Modesetting Hotplug --- linux-core/intel_fb.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 32c7dc31..b67c0fcc 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -489,6 +489,46 @@ static struct fb_ops intelfb_ops = { .fb_imageblit = cfb_imageblit, //intelfb_imageblit, }; +/** + * Curretly it is assumed that the old framebuffer is reused. + * + * LOCKING + * caller should hold the mode config lock. + * + */ +int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) +{ + struct fb_info *info; + struct drm_framebuffer *fb; + struct drm_display_mode *mode = crtc->desired_mode; + + fb = crtc->fb; + if (!fb) + return 1; + + info = fb->fbdev; + if (!info) + return 1; + + if (!mode) + return 1; + + info->var.xres = mode->hdisplay; + info->var.right_margin = mode->hsync_start - mode->hdisplay; + info->var.hsync_len = mode->hsync_end - mode->hsync_start; + info->var.left_margin = mode->htotal - mode->hsync_end; + info->var.yres = mode->vdisplay; + info->var.lower_margin = mode->vsync_start - mode->vdisplay; + info->var.vsync_len = mode->vsync_end - mode->vsync_start; + info->var.upper_margin = mode->vtotal - mode->vsync_end; + info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; + /* avoid overflow */ + info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; + + return 0; +} +EXPORT_SYMBOL(intelfb_resize); + int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) { struct fb_info *info; @@ -512,8 +552,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) } crtc->fb = fb; - fb->width = crtc->desired_mode->hdisplay; - fb->height = crtc->desired_mode->vdisplay; + /* To allow resizeing without swapping buffers */ + fb->width = 2048;/* crtc->desired_mode->hdisplay; */ + fb->height = 2048;/* crtc->desired_mode->vdisplay; */ fb->bits_per_pixel = 32; fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); -- cgit v1.2.3 From a2254c5a9670a3e865f0eb5acd46e905c9b146ce Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 28 Jan 2008 03:12:29 +0100 Subject: Added cursor support --- linux-core/intel_fb.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index b67c0fcc..bb42bc69 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -49,7 +49,7 @@ struct intelfb_par { struct drm_crtc *crtc; struct drm_display_mode *fb_mode; }; - +/* static int var_to_refresh(const struct fb_var_screeninfo *var) { @@ -59,7 +59,7 @@ var_to_refresh(const struct fb_var_screeninfo *var) var->vsync_len; return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot; -} +}*/ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, @@ -106,10 +106,10 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_device *dev = par->dev; + /*struct drm_device *dev = par->dev;*/ struct drm_framebuffer *fb = par->crtc->fb; - struct drm_output *output; - int depth, found = 0; + /*struct drm_output *output;*/ + int depth/*, found = 0*/; if (!var->pixclock) return -EINVAL; @@ -254,6 +254,8 @@ static int intelfb_set_par(struct fb_info *info) struct fb_var_screeninfo *var = &info->var; int found = 0; + DRM_DEBUG("\n"); + switch (var->bits_per_pixel) { case 16: fb->depth = (var->green.length == 6) ? 16 : 15; @@ -321,9 +323,19 @@ static int intelfb_set_par(struct fb_info *info) } if (par->crtc->enabled) { - if (!drm_mode_equal(&par->crtc->mode, drm_mode)) - if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) + if (!drm_mode_equal(&par->crtc->mode, drm_mode)) { + if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) return -EINVAL; + } else if (par->crtc->x != var->xoffset || par->crtc->x != var->xoffset) { + if (!par->crtc->funcs->mode_set_base) { + if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) + return -EINVAL; + } else { + par->crtc->funcs->mode_set_base(par->crtc, var->xoffset, var->yoffset); + par->crtc->x = var->xoffset; + par->crtc->y = var->yoffset; + } + } } return 0; } -- cgit v1.2.3 From b9b6f9234dd9e702a7d58978cbd88dc297b2b51a Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 28 Jan 2008 22:06:09 +0100 Subject: Misc panning fixes for intel_fb --- linux-core/intel_fb.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index bb42bc69..59df1976 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -326,7 +326,7 @@ static int intelfb_set_par(struct fb_info *info) if (!drm_mode_equal(&par->crtc->mode, drm_mode)) { if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) return -EINVAL; - } else if (par->crtc->x != var->xoffset || par->crtc->x != var->xoffset) { + } else if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) { if (!par->crtc->funcs->mode_set_base) { if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) return -EINVAL; @@ -485,6 +485,31 @@ void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) ADVANCE_LP_RING(); } #endif +static int intelfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct intelfb_par *par = info->par; + struct drm_crtc *crtc = par->crtc; + struct drm_framebuffer *fb = crtc->fb; + + DRM_DEBUG("\n"); + + if (!crtc->funcs->mode_set_base) { + DRM_ERROR("panning not supported\n"); + return -EFAULT; + } + + /* TODO add check size and pos*/ + + crtc->funcs->mode_set_base(crtc, var->xoffset, var->yoffset); + + par->crtc->x = var->xoffset; + par->crtc->y = var->yoffset; + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + return 0; +} static struct fb_ops intelfb_ops = { .owner = THIS_MODULE, @@ -499,6 +524,7 @@ static struct fb_ops intelfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, //intelfb_copyarea, .fb_imageblit = cfb_imageblit, //intelfb_imageblit, + .fb_pan_display = intelfb_pan_display, }; /** @@ -606,8 +632,8 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_TRUECOLOR; info->fix.type_aux = 0; - info->fix.xpanstep = 8; - info->fix.ypanstep = 1; + info->fix.xpanstep = 1; /* doing it in hw */ + info->fix.ypanstep = 1; /* doing it in hw */ info->fix.ywrapstep = 0; info->fix.accel = FB_ACCEL_I830; info->fix.type_aux = 0; -- cgit v1.2.3 From de0084590bc34c2c23cb3d7a754f3e98059f4cf2 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 5 Feb 2008 10:11:46 +0000 Subject: fix some warnings --- linux-core/intel_fb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 59df1976..6df243b0 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -490,7 +490,6 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, { struct intelfb_par *par = info->par; struct drm_crtc *crtc = par->crtc; - struct drm_framebuffer *fb = crtc->fb; DRM_DEBUG("\n"); -- cgit v1.2.3 From 8844245cfcc5b19caafc772fd457401ab3253a28 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 20 Feb 2008 10:51:19 +1000 Subject: drm/fb: get rid of offset from structure use bo offset --- linux-core/intel_fb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 6df243b0..56403998 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -612,7 +612,6 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) return -EINVAL; } - fb->offset = fbo->offset; fb->bo = fbo; printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, fb->height, fbo->offset, fbo); @@ -639,7 +638,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->fix.mmio_start = 0; info->fix.mmio_len = 0; info->fix.line_length = fb->pitch; - info->fix.smem_start = fb->offset + dev->mode_config.fb_base; + info->fix.smem_start = fb->bo->offset + dev->mode_config.fb_base; info->fix.smem_len = info->fix.line_length * fb->height; info->flags = FBINFO_DEFAULT; -- cgit v1.2.3 From 2476cb209ebbb11edace4bbce0cfaff4e1599dca Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Fri, 22 Feb 2008 11:46:22 +0000 Subject: Implement short circuit for base change only Allow mode to be set with fb_id set to -1, meaning set the mode with the current fb (if we have one bound). Allow intelfb to hook back up it's fb if modesetting clears it (maybe temporary). Move any crtc->fb related register changes to set_base in intel_fb. General intelfb cleanups. --- linux-core/intel_fb.c | 118 ++++++++++++++++++++++---------------------------- 1 file changed, 51 insertions(+), 67 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 56403998..e33494c6 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -48,6 +48,7 @@ struct intelfb_par { struct drm_device *dev; struct drm_crtc *crtc; struct drm_display_mode *fb_mode; + struct drm_framebuffer *fb; }; /* static int @@ -66,7 +67,7 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->crtc->fb; + struct drm_framebuffer *fb = par->fb; struct drm_crtc *crtc = par->crtc; if (regno > 255) @@ -107,7 +108,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, { struct intelfb_par *par = info->par; /*struct drm_device *dev = par->dev;*/ - struct drm_framebuffer *fb = par->crtc->fb; + struct drm_framebuffer *fb = par->fb; /*struct drm_output *output;*/ int depth/*, found = 0*/; @@ -216,41 +217,15 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, return 0; } -bool i915_drmfb_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2, unsigned int pixclock) -{ - - if (mode1->hdisplay == mode2->hdisplay && - mode1->hsync_start == mode2->hsync_start && - mode1->hsync_end == mode2->hsync_end && - mode1->htotal == mode2->htotal && - mode1->hskew == mode2->hskew && - mode1->vdisplay == mode2->vdisplay && - mode1->vsync_start == mode2->vsync_start && - mode1->vsync_end == mode2->vsync_end && - mode1->vtotal == mode2->vtotal && - mode1->vscan == mode2->vscan && - mode1->flags == mode2->flags) - { - if (mode1->clock == mode2->clock) - return true; - - if (KHZ2PICOS(mode2->clock) == pixclock) - return true; - return false; - } - - return false; -} - /* this will let fbcon do the mode init */ /* FIXME: take mode config lock? */ static int intelfb_set_par(struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->crtc->fb; + struct drm_framebuffer *fb = par->fb; struct drm_device *dev = par->dev; struct drm_display_mode *drm_mode, *search_mode; - struct drm_output *output; + struct drm_output *output = NULL; struct fb_var_screeninfo *var = &info->var; int found = 0; @@ -295,15 +270,23 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_set_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); + found = 0; list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->crtc) + if (output->crtc == par->crtc){ + found = 1; break; + } } + /* no output bound, bail */ + if (!found) + return -EINVAL; + + found = 0; drm_mode_debug_printmodeline(dev, drm_mode); list_for_each_entry(search_mode, &output->modes, head) { drm_mode_debug_printmodeline(dev, search_mode); - if (i915_drmfb_mode_equal(drm_mode, search_mode, var->pixclock)) { + if (drm_mode_equal(drm_mode, search_mode)) { drm_mode_destroy(dev, drm_mode); drm_mode = search_mode; found = 1; @@ -311,8 +294,12 @@ static int intelfb_set_par(struct fb_info *info) } } + /* If we didn't find a matching mode that exists on our output, + * create a new attachment for the incoming user specified mode + */ if (!found) { if (par->fb_mode) { + /* this also destroys the mode */ drm_mode_detachmode_crtc(dev, par->fb_mode); } @@ -322,21 +309,13 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode); } - if (par->crtc->enabled) { - if (!drm_mode_equal(&par->crtc->mode, drm_mode)) { - if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) - return -EINVAL; - } else if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) { - if (!par->crtc->funcs->mode_set_base) { - if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) - return -EINVAL; - } else { - par->crtc->funcs->mode_set_base(par->crtc, var->xoffset, var->yoffset); - par->crtc->x = var->xoffset; - par->crtc->y = var->yoffset; - } - } - } + /* re-attach fb */ + if (!par->crtc->fb) + par->crtc->fb = par->fb; + + if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) + return -EINVAL; + return 0; } @@ -493,17 +472,14 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, DRM_DEBUG("\n"); - if (!crtc->funcs->mode_set_base) { - DRM_ERROR("panning not supported\n"); - return -EFAULT; - } - /* TODO add check size and pos*/ - crtc->funcs->mode_set_base(crtc, var->xoffset, var->yoffset); + /* re-attach fb */ + if (!crtc->fb) + crtc->fb = par->fb; + + drm_crtc_set_mode(crtc, &crtc->mode, var->xoffset, var->yoffset); - par->crtc->x = var->xoffset; - par->crtc->y = var->yoffset; info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; @@ -535,7 +511,7 @@ static struct fb_ops intelfb_ops = { */ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) { - struct fb_info *info; + struct fb_info *info; struct drm_framebuffer *fb; struct drm_display_mode *mode = crtc->desired_mode; @@ -559,7 +535,7 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) info->var.vsync_len = mode->vsync_end - mode->vsync_start; info->var.upper_margin = mode->vtotal - mode->vsync_end; info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; - /* avoid overflow */ + /* avoid overflow */ info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; return 0; @@ -596,7 +572,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) fb->bits_per_pixel = 32; fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); fb->depth = 24; - ret = drm_buffer_object_create(dev, fb->width * fb->height * 4, + ret = drm_buffer_object_create(dev, fb->pitch * fb->height * 4, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | @@ -623,6 +599,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) par->dev = dev; par->crtc = crtc; + par->fb = fb; info->fbops = &intelfb_ops; @@ -635,19 +612,26 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->fix.ywrapstep = 0; info->fix.accel = FB_ACCEL_I830; info->fix.type_aux = 0; - info->fix.mmio_start = 0; - info->fix.mmio_len = 0; + + if (IS_I9XX(dev)) { + info->fix.mmio_start = pci_resource_start(dev->pdev, 0); + info->fix.mmio_len = pci_resource_len(dev->pdev, 0); + } else { + info->fix.mmio_start = pci_resource_start(dev->pdev, 1); + info->fix.mmio_len = pci_resource_len(dev->pdev, 1); + } + info->fix.line_length = fb->pitch; info->fix.smem_start = fb->bo->offset + dev->mode_config.fb_base; info->fix.smem_len = info->fix.line_length * fb->height; info->flags = FBINFO_DEFAULT; - ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base); - if (ret) - DRM_ERROR("error mapping fb: %d\n", ret); - - info->screen_base = fb->virtual_base; + ret = drm_bo_kmap(fb->bo, 0, fb->bo->num_pages, &fb->kmap); + if (ret) + DRM_ERROR("error mapping fb: %d\n", ret); + + info->screen_base = fb->kmap.virtual; info->screen_size = info->fix.smem_len; /* FIXME */ info->pseudo_palette = fb->pseudo_palette; info->var.xres_virtual = fb->width; @@ -757,10 +741,10 @@ int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) if (info) { unregister_framebuffer(info); - framebuffer_release(info); - drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); + drm_bo_kunmap(&fb->kmap); drm_bo_usage_deref_unlocked(&fb->bo); drm_framebuffer_destroy(fb); + framebuffer_release(info); } return 0; } -- cgit v1.2.3 From 33cb42a9f7c7c4f4dd91756af55de7352944efa4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 13:03:42 +1100 Subject: make startup of Xorg smoother if the mode doesn't change. just flip the framebuffer in when required. --- linux-core/intel_fb.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index e33494c6..931bc1b6 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -228,6 +228,7 @@ static int intelfb_set_par(struct fb_info *info) struct drm_output *output = NULL; struct fb_var_screeninfo *var = &info->var; int found = 0; + int changed = 0; DRM_DEBUG("\n"); @@ -310,11 +311,22 @@ static int intelfb_set_par(struct fb_info *info) } /* re-attach fb */ - if (!par->crtc->fb) + if (!par->crtc->fb) { par->crtc->fb = par->fb; + changed = 1; + } - if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) - return -EINVAL; + if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) + changed = 1; + + drm_mode_debug_printmodeline(dev, drm_mode); + drm_mode_debug_printmodeline(dev, &par->crtc->mode); + if (!drm_mode_equal(drm_mode, &par->crtc->mode)) + changed = 1; + + if (changed) + if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) + return -EINVAL; return 0; } @@ -469,16 +481,21 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, { struct intelfb_par *par = info->par; struct drm_crtc *crtc = par->crtc; - + int changed = 0; DRM_DEBUG("\n"); /* TODO add check size and pos*/ + if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) + changed = 1; /* re-attach fb */ - if (!crtc->fb) + if (!crtc->fb) { crtc->fb = par->fb; + changed = 1; + } - drm_crtc_set_mode(crtc, &crtc->mode, var->xoffset, var->yoffset); + if (changed) + drm_crtc_set_mode(crtc, &crtc->mode, var->xoffset, var->yoffset); info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; -- cgit v1.2.3 From 9f19e79f955281b9de393219e4ad9835ffe29c49 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 17:09:51 +1100 Subject: drm: we already worked out the pitch. multiplying by 4 is just madness.. --- linux-core/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 931bc1b6..52ff3a67 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -589,7 +589,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) fb->bits_per_pixel = 32; fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); fb->depth = 24; - ret = drm_buffer_object_create(dev, fb->pitch * fb->height * 4, + ret = drm_buffer_object_create(dev, fb->pitch * fb->height, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | -- cgit v1.2.3 From 631c6af4d926fd1fe73f017cfb032538cee7ea7d Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 13 Mar 2008 11:47:37 +0000 Subject: Fix green offset --- linux-core/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 52ff3a67..7c4b0632 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -157,7 +157,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, break; case 16: var->red.offset = 11; - var->green.offset = 6; + var->green.offset = 5; var->blue.offset = 0; var->red.length = 5; var->green.length = 6; -- cgit v1.2.3 From 19abd5c1ac3456e67241fbd2d8cd08148d6de9f9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 8 May 2008 16:10:26 +1000 Subject: drm: set crtc->fb to NULL --- linux-core/intel_fb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 7c4b0632..63491b61 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -763,6 +763,7 @@ int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) drm_framebuffer_destroy(fb); framebuffer_release(info); } + crtc->fb = NULL; return 0; } EXPORT_SYMBOL(intelfb_remove); -- cgit v1.2.3 From 442e12412396280eb5164d7b8f6792969c2cf6a0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 8 May 2008 16:11:25 +1000 Subject: drm: check for NULL fb here, shouldn't happen but avoid oops for now --- linux-core/intel_fb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 63491b61..7df1525a 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -754,7 +754,12 @@ EXPORT_SYMBOL(intelfb_probe); int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) { struct drm_framebuffer *fb = crtc->fb; - struct fb_info *info = fb->fbdev; + struct fb_info *info; + + if (!fb) + return -EINVAL; + + info = fb->fbdev; if (info) { unregister_framebuffer(info); -- cgit v1.2.3 From 9d9104ad5fcd2d284a0a87385e9eb1a77adc869e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 8 May 2008 15:25:37 +0200 Subject: i915: Fixed indent in intel_fb.c --- linux-core/intel_fb.c | 438 +++++++++++++++++++++++++------------------------- 1 file changed, 221 insertions(+), 217 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 7df1525a..73ad35c7 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -47,24 +47,25 @@ struct intelfb_par { struct drm_device *dev; struct drm_crtc *crtc; - struct drm_display_mode *fb_mode; + struct drm_display_mode *fb_mode; struct drm_framebuffer *fb; + struct drm_mode_set set; }; /* static int var_to_refresh(const struct fb_var_screeninfo *var) { int xtot = var->xres + var->left_margin + var->right_margin + - var->hsync_len; + var->hsync_len; int ytot = var->yres + var->upper_margin + var->lower_margin + - var->vsync_len; + var->vsync_len; return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot; }*/ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) + unsigned blue, unsigned transp, + struct fb_info *info) { struct intelfb_par *par = info->par; struct drm_framebuffer *fb = par->fb; @@ -82,9 +83,9 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, if (regno < 16) { switch (fb->depth) { case 15: - fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11); + ((blue & 0xf800) >> 11); break; case 16: fb->pseudo_palette[regno] = (red & 0xf800) | @@ -94,7 +95,7 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, case 24: case 32: fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | - (green & 0xff00) | + (green & 0xff00) | ((blue & 0xff00) >> 8); break; } @@ -104,114 +105,114 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, } static int intelfb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) + struct fb_info *info) { - struct intelfb_par *par = info->par; - /*struct drm_device *dev = par->dev;*/ + struct intelfb_par *par = info->par; + /*struct drm_device *dev = par->dev;*/ struct drm_framebuffer *fb = par->fb; - /*struct drm_output *output;*/ - int depth/*, found = 0*/; - - if (!var->pixclock) - return -EINVAL; - - /* Need to resize the fb object !!! */ - if (var->xres > fb->width || var->yres > fb->height) { - DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,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 8: - var->red.offset = 0; - var->green.offset = 0; - 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 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: - return -EINVAL; - } + /*struct drm_output *output;*/ + int depth/*, found = 0*/; + + if (!var->pixclock) + return -EINVAL; + + /* Need to resize the fb object !!! */ + if (var->xres > fb->width || var->yres > fb->height) { + DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,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 8: + var->red.offset = 0; + var->green.offset = 0; + 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 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: + return -EINVAL; + } #if 0 - /* Here we walk the output mode list and look for modes. If we haven't - * got it, then bail. Not very nice, so this is disabled. - * In the set_par code, we create our mode based on the incoming - * parameters. Nicer, but may not be desired by some. - */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->crtc) - break; - } - - list_for_each_entry(drm_mode, &output->modes, head) { - if (drm_mode->hdisplay == var->xres && - drm_mode->vdisplay == var->yres && - (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && - (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { + /* Here we walk the output mode list and look for modes. If we haven't + * got it, then bail. Not very nice, so this is disabled. + * In the set_par code, we create our mode based on the incoming + * parameters. Nicer, but may not be desired by some. + */ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + if (output->crtc == par->crtc) + break; + } + + list_for_each_entry(drm_mode, &output->modes, head) { + if (drm_mode->hdisplay == var->xres && + drm_mode->vdisplay == var->yres && + (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && + (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { found = 1; break; } } - if (!found) - return -EINVAL; + if (!found) + return -EINVAL; #endif return 0; @@ -224,68 +225,68 @@ static int intelfb_set_par(struct fb_info *info) struct intelfb_par *par = info->par; struct drm_framebuffer *fb = par->fb; struct drm_device *dev = par->dev; - struct drm_display_mode *drm_mode, *search_mode; - struct drm_output *output = NULL; - struct fb_var_screeninfo *var = &info->var; + struct drm_display_mode *drm_mode, *search_mode; + struct drm_output *output = NULL; + struct fb_var_screeninfo *var = &info->var; int found = 0; int changed = 0; DRM_DEBUG("\n"); - switch (var->bits_per_pixel) { - case 16: - fb->depth = (var->green.length == 6) ? 16 : 15; - break; - case 32: - fb->depth = (var->transp.length > 0) ? 32 : 24; - break; - default: - fb->depth = var->bits_per_pixel; - break; - } + switch (var->bits_per_pixel) { + case 16: + fb->depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + fb->depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + fb->depth = var->bits_per_pixel; + break; + } - fb->bits_per_pixel = var->bits_per_pixel; + fb->bits_per_pixel = var->bits_per_pixel; - info->fix.line_length = fb->pitch; - info->fix.smem_len = info->fix.line_length * fb->height; - info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + info->fix.line_length = fb->pitch; + info->fix.smem_len = info->fix.line_length * fb->height; + info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - info->screen_size = info->fix.smem_len; /* ??? */ + info->screen_size = info->fix.smem_len; /* ??? */ /* create a drm 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 = 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_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); found = 0; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->crtc){ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + if (output->crtc == par->crtc){ found = 1; - break; + break; } - } + } /* no output bound, bail */ if (!found) return -EINVAL; found = 0; - drm_mode_debug_printmodeline(dev, drm_mode); - list_for_each_entry(search_mode, &output->modes, head) { + drm_mode_debug_printmodeline(dev, drm_mode); + list_for_each_entry(search_mode, &output->modes, head) { drm_mode_debug_printmodeline(dev, search_mode); if (drm_mode_equal(drm_mode, search_mode)) { drm_mode_destroy(dev, drm_mode); @@ -296,8 +297,8 @@ static int intelfb_set_par(struct fb_info *info) } /* If we didn't find a matching mode that exists on our output, - * create a new attachment for the incoming user specified mode - */ + * create a new attachment for the incoming user specified mode + */ if (!found) { if (par->fb_mode) { /* this also destroys the mode */ @@ -318,7 +319,7 @@ static int intelfb_set_par(struct fb_info *info) if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) changed = 1; - + drm_mode_debug_printmodeline(dev, drm_mode); drm_mode_debug_printmodeline(dev, &par->crtc->mode); if (!drm_mode_equal(drm_mode, &par->crtc->mode)) @@ -333,9 +334,9 @@ static int intelfb_set_par(struct fb_info *info) #if 0 static void intelfb_copyarea(struct fb_info *info, - const struct fb_copyarea *region) + const struct fb_copyarea *region) { - struct intelfb_par *par = info->par; + struct intelfb_par *par = info->par; struct drm_device *dev = par->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 src_x1, src_y1, dst_x1, dst_y1, dst_x2, dst_y2, offset; @@ -380,7 +381,7 @@ static void intelfb_copyarea(struct fb_info *info, void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) { - struct intelfb_par *par = info->par; + struct intelfb_par *par = info->par; struct drm_device *dev = par->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 cmd, rop_pitch_depth, tmp; @@ -397,9 +398,9 @@ void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) nbytes *= image->height; /* - * Check if the glyph data exceeds the immediate mode limit. - * It would take a large font (1K pixels) to hit this limit. - */ + * Check if the glyph data exceeds the immediate mode limit. + * It would take a large font (1K pixels) to hit this limit. + */ if (nbytes > 128 || image->depth != 1) return cfb_imageblit(info, image); @@ -407,13 +408,13 @@ void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) ndwords = ROUND_UP_TO(nbytes, 4) / 4; /* - * Ring has to be padded to a quad word. But because the command starts - with 7 bytes, pad only if there is an even number of ndwords - */ + * Ring has to be padded to a quad word. But because the command starts + with 7 bytes, pad only if there is an even number of ndwords + */ pad = !(ndwords % 2); DRM_DEBUG("imageblit %dx%dx%d to (%d,%d)\n", image->width, - image->height, image->depth, image->dx, image->dy); + image->height, image->depth, image->dx, image->dy); DRM_DEBUG("nbytes: %d, ndwords: %d, pad: %d\n", nbytes, ndwords, pad); tmp = (XY_MONO_SRC_COPY_IMM_BLT & 0xff) + ndwords; @@ -477,7 +478,7 @@ void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) } #endif static int intelfb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) + struct fb_info *info) { struct intelfb_par *par = info->par; struct drm_crtc *crtc = par->crtc; @@ -505,11 +506,11 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, static struct fb_ops intelfb_ops = { .owner = THIS_MODULE, - // .fb_open = intelfb_open, - // .fb_read = intelfb_read, - // .fb_write = intelfb_write, - // .fb_release = intelfb_release, - // .fb_ioctl = intelfb_ioctl, + //.fb_open = intelfb_open, + //.fb_read = intelfb_read, + //.fb_write = intelfb_write, + //.fb_release = intelfb_release, + //.fb_ioctl = intelfb_ioctl, .fb_check_var = intelfb_check_var, .fb_set_par = intelfb_set_par, .fb_setcolreg = intelfb_setcolreg, @@ -590,14 +591,14 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); fb->depth = 24; ret = drm_buffer_object_create(dev, fb->pitch * fb->height, - drm_bo_type_kernel, - DRM_BO_FLAG_READ | - DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_TT | - DRM_BO_FLAG_MEM_VRAM | - DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, 0, 0, - &fbo); + drm_bo_type_kernel, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, 0, 0, + &fbo); if (ret || !fbo) { printk(KERN_ERR "failed to allocate framebuffer\n"); drm_framebuffer_destroy(fb); @@ -607,7 +608,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) fb->bo = fbo; printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, - fb->height, fbo->offset, fbo); + fb->height, fbo->offset, fbo); fb->fbdev = info; @@ -645,9 +646,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->flags = FBINFO_DEFAULT; ret = drm_bo_kmap(fb->bo, 0, fb->bo->num_pages, &fb->kmap); - if (ret) - DRM_ERROR("error mapping fb: %d\n", ret); - + if (ret) + DRM_ERROR("error mapping fb: %d\n", ret); + info->screen_base = fb->kmap.virtual; info->screen_size = info->fix.smem_len; /* FIXME */ info->pseudo_palette = fb->pseudo_palette; @@ -660,13 +661,13 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->var.height = -1; info->var.width = -1; - info->var.xres = mode->hdisplay; - info->var.right_margin = mode->hsync_start - mode->hdisplay; - info->var.hsync_len = mode->hsync_end - mode->hsync_start; - info->var.left_margin = mode->htotal - mode->hsync_end; - info->var.yres = mode->vdisplay; - info->var.lower_margin = mode->vsync_start - mode->vdisplay; - info->var.vsync_len = mode->vsync_end - mode->vsync_start; + info->var.xres = mode->hdisplay; + info->var.right_margin = mode->hsync_start - mode->hdisplay; + info->var.hsync_len = mode->hsync_end - mode->hsync_start; + info->var.left_margin = mode->htotal - mode->hsync_end; + info->var.yres = mode->vdisplay; + info->var.lower_margin = mode->vsync_start - mode->vdisplay; + info->var.vsync_len = mode->vsync_end - mode->vsync_start; info->var.upper_margin = mode->vtotal - mode->vsync_end; info->var.pixclock = KHZ2PICOS(mode->clock); @@ -693,48 +694,51 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) DRM_DEBUG(" pitch is %d\n", fb->pitch); switch(fb->depth) { case 8: - info->var.red.offset = 0; - info->var.green.offset = 0; - info->var.blue.offset = 0; - info->var.red.length = 8; /* 8bit DAC */ - info->var.green.length = 8; - info->var.blue.length = 8; - info->var.transp.offset = 0; - info->var.transp.length = 0; - break; + info->var.red.offset = 0; + info->var.green.offset = 0; + info->var.blue.offset = 0; + info->var.red.length = 8; /* 8bit DAC */ + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; case 15: - info->var.red.offset = 10; - info->var.green.offset = 5; - info->var.blue.offset = 0; - info->var.red.length = info->var.green.length = - info->var.blue.length = 5; - info->var.transp.offset = 15; - info->var.transp.length = 1; - break; + 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; + 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 = info->var.green.length = - info->var.blue.length = 8; - info->var.transp.offset = 0; - info->var.transp.length = 0; - break; + 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 = info->var.green.length = - info->var.blue.length = 8; + 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; @@ -746,7 +750,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) return -EINVAL; printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, - info->fix.id); + info->fix.id); return 0; } EXPORT_SYMBOL(intelfb_probe); -- cgit v1.2.3 From 7bcbc443f4f5161ab1e1a11cb6694e6d6269377c Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 8 May 2008 20:10:18 +0200 Subject: i915: Changed intel_fb to use the new drm_crtc_set_config interface --- linux-core/intel_fb.c | 70 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 29 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 73ad35c7..50c24a75 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -46,10 +46,14 @@ struct intelfb_par { struct drm_device *dev; +/* struct drm_crtc *crtc; struct drm_display_mode *fb_mode; struct drm_framebuffer *fb; +*/ + struct drm_display_mode *our_mode; struct drm_mode_set set; + struct drm_output *hack; }; /* static int @@ -68,8 +72,8 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->fb; - struct drm_crtc *crtc = par->crtc; + struct drm_framebuffer *fb = par->set.fb; + struct drm_crtc *crtc = par->set.crtc; if (regno > 255) return 1; @@ -109,7 +113,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, { struct intelfb_par *par = info->par; /*struct drm_device *dev = par->dev;*/ - struct drm_framebuffer *fb = par->fb; + struct drm_framebuffer *fb = par->set.fb; /*struct drm_output *output;*/ int depth/*, found = 0*/; @@ -223,13 +227,12 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, static int intelfb_set_par(struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->fb; + struct drm_framebuffer *fb = par->set.fb; struct drm_device *dev = par->dev; struct drm_display_mode *drm_mode, *search_mode; struct drm_output *output = NULL; struct fb_var_screeninfo *var = &info->var; int found = 0; - int changed = 0; DRM_DEBUG("\n"); @@ -274,7 +277,7 @@ static int intelfb_set_par(struct fb_info *info) found = 0; list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->crtc){ + if (output->crtc == par->set.crtc){ found = 1; break; } @@ -300,17 +303,24 @@ static int intelfb_set_par(struct fb_info *info) * create a new attachment for the incoming user specified mode */ if (!found) { - if (par->fb_mode) { + if (par->our_mode) { /* this also destroys the mode */ - drm_mode_detachmode_crtc(dev, par->fb_mode); + drm_mode_detachmode_crtc(dev, par->our_mode); } - par->fb_mode = drm_mode; + par->set.mode = drm_mode; + par->our_mode = drm_mode; drm_mode_debug_printmodeline(dev, drm_mode); /* attach mode */ - drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode); + drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode); + } else { + par->set.mode = drm_mode; + if (par->our_mode) + drm_mode_detachmode_crtc(dev, par->our_mode); + par->our_mode = NULL; } +#if 0 /* re-attach fb */ if (!par->crtc->fb) { par->crtc->fb = par->fb; @@ -330,6 +340,9 @@ static int intelfb_set_par(struct fb_info *info) return -EINVAL; return 0; +#else + return drm_crtc_set_config(&par->set); +#endif } #if 0 @@ -481,27 +494,20 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_crtc *crtc = par->crtc; - int changed = 0; + int ret; DRM_DEBUG("\n"); - /* TODO add check size and pos*/ - if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) - changed = 1; - - /* re-attach fb */ - if (!crtc->fb) { - crtc->fb = par->fb; - changed = 1; - } + par->set.x = var->xoffset; + par->set.y = var->yoffset; - if (changed) - drm_crtc_set_mode(crtc, &crtc->mode, var->xoffset, var->yoffset); + ret = drm_crtc_set_config(&par->set); - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; + if (!ret) { + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + } - return 0; + return ret; } static struct fb_ops intelfb_ops = { @@ -560,7 +566,7 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) } EXPORT_SYMBOL(intelfb_resize); -int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) +int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output) { struct fb_info *info; struct intelfb_par *par; @@ -575,6 +581,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) return -EINVAL; } + if (!output) + return -EINVAL; + fb = drm_framebuffer_create(dev); if (!fb) { framebuffer_release(info); @@ -616,8 +625,11 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) par = info->par; par->dev = dev; - par->crtc = crtc; - par->fb = fb; + par->set.crtc = crtc; + par->set.fb = fb; + par->hack = output; + par->set.outputs = &par->hack; + par->set.num_outputs = 1; info->fbops = &intelfb_ops; -- cgit v1.2.3 From a51e38548cfdece2978e9b5f0d6f0467ba7a7272 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Fri, 9 May 2008 10:06:17 +0800 Subject: fix kernel oops when removing fb drm_crtc->fb may point to NULL, f.e X server will allocate a new fb and assign it to the CRTC at startup, when X server exits, it will destroy the allocated fb, making drm_crtc->fb points to NULL. --- linux-core/intel_fb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 50c24a75..9934e3af 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -767,9 +767,8 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_outp } EXPORT_SYMBOL(intelfb_probe); -int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) +int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) { - struct drm_framebuffer *fb = crtc->fb; struct fb_info *info; if (!fb) @@ -784,7 +783,6 @@ int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) drm_framebuffer_destroy(fb); framebuffer_release(info); } - crtc->fb = NULL; return 0; } EXPORT_SYMBOL(intelfb_remove); -- cgit v1.2.3 From b4d8cda8e6d6ea319ab7c471d6d68b8af8693cfe Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 23 May 2008 18:41:58 -0700 Subject: drm_mode_debug_printmodeline doesn't need struct drm_device * Makes printing modelines from some routines easier. --- linux-core/intel_fb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 9934e3af..4f5a0000 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -288,9 +288,9 @@ static int intelfb_set_par(struct fb_info *info) return -EINVAL; found = 0; - drm_mode_debug_printmodeline(dev, drm_mode); + drm_mode_debug_printmodeline(drm_mode); list_for_each_entry(search_mode, &output->modes, head) { - drm_mode_debug_printmodeline(dev, search_mode); + drm_mode_debug_printmodeline(search_mode); if (drm_mode_equal(drm_mode, search_mode)) { drm_mode_destroy(dev, drm_mode); drm_mode = search_mode; @@ -310,7 +310,7 @@ static int intelfb_set_par(struct fb_info *info) par->set.mode = drm_mode; par->our_mode = drm_mode; - drm_mode_debug_printmodeline(dev, drm_mode); + drm_mode_debug_printmodeline(drm_mode); /* attach mode */ drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode); } else { @@ -330,8 +330,8 @@ static int intelfb_set_par(struct fb_info *info) if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) changed = 1; - drm_mode_debug_printmodeline(dev, drm_mode); - drm_mode_debug_printmodeline(dev, &par->crtc->mode); + drm_mode_debug_printmodeline(drm_mode); + drm_mode_debug_printmodeline(&par->crtc->mode); if (!drm_mode_equal(drm_mode, &par->crtc->mode)) changed = 1; -- cgit v1.2.3 From df8cd54286fbae5903d8ede390ec4a11cb6c4b6c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 29 May 2008 14:02:14 +1000 Subject: modesetting: reorganise code into core and helper functions. This splits a lot of the core modesetting code out into a file of helper functions, that are only called from themselves and/or the driver. The driver gets called into more often or can call these functions from itself if it is a helper using driver. I've broken framebuffer resize doing this but I didn't like the API for that in any case. --- linux-core/intel_fb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 4f5a0000..05fc3b29 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -341,7 +341,7 @@ static int intelfb_set_par(struct fb_info *info) return 0; #else - return drm_crtc_set_config(&par->set); + return par->set.crtc->funcs->set_config(&par->set); #endif } @@ -496,11 +496,11 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, struct intelfb_par *par = info->par; int ret; DRM_DEBUG("\n"); - + par->set.x = var->xoffset; par->set.y = var->yoffset; - ret = drm_crtc_set_config(&par->set); + ret = par->set.crtc->funcs->set_config(&par->set); if (!ret) { info->var.xoffset = var->xoffset; -- cgit v1.2.3 From 9d38448ed33aaff324cc4bbe1e0878593e97d07d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 15:03:12 +1000 Subject: modesetting: the great renaming. Okay we have crtc, encoder and connectors. No more outputs exposed beyond driver internals I've broken intel tv connector stuff. Really for TV we should have one TV connector, with a sub property for the type of signal been driven over it --- linux-core/intel_fb.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 05fc3b29..394d2344 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -53,7 +53,7 @@ struct intelfb_par { */ struct drm_display_mode *our_mode; struct drm_mode_set set; - struct drm_output *hack; + struct drm_connector *hack; }; /* static int @@ -114,7 +114,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, struct intelfb_par *par = info->par; /*struct drm_device *dev = par->dev;*/ struct drm_framebuffer *fb = par->set.fb; - /*struct drm_output *output;*/ + /*struct drm_connector *connector;*/ int depth/*, found = 0*/; if (!var->pixclock) @@ -195,17 +195,17 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, } #if 0 - /* Here we walk the output mode list and look for modes. If we haven't + /* Here we walk the connector mode list and look for modes. If we haven't * got it, then bail. Not very nice, so this is disabled. * In the set_par code, we create our mode based on the incoming * parameters. Nicer, but may not be desired by some. */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->crtc) + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->crtc == par->crtc) break; } - list_for_each_entry(drm_mode, &output->modes, head) { + list_for_each_entry(drm_mode, &connector->modes, head) { if (drm_mode->hdisplay == var->xres && drm_mode->vdisplay == var->yres && (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && @@ -230,7 +230,7 @@ static int intelfb_set_par(struct fb_info *info) struct drm_framebuffer *fb = par->set.fb; struct drm_device *dev = par->dev; struct drm_display_mode *drm_mode, *search_mode; - struct drm_output *output = NULL; + struct drm_connector *connector = NULL; struct fb_var_screeninfo *var = &info->var; int found = 0; @@ -276,20 +276,20 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); found = 0; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->set.crtc){ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->crtc == par->set.crtc){ found = 1; break; } } - /* no output bound, bail */ + /* no connector bound, bail */ if (!found) return -EINVAL; found = 0; drm_mode_debug_printmodeline(drm_mode); - list_for_each_entry(search_mode, &output->modes, head) { + list_for_each_entry(search_mode, &connector->modes, head) { drm_mode_debug_printmodeline(search_mode); if (drm_mode_equal(drm_mode, search_mode)) { drm_mode_destroy(dev, drm_mode); @@ -299,7 +299,7 @@ static int intelfb_set_par(struct fb_info *info) } } - /* If we didn't find a matching mode that exists on our output, + /* If we didn't find a matching mode that exists on our connector, * create a new attachment for the incoming user specified mode */ if (!found) { @@ -566,7 +566,7 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) } EXPORT_SYMBOL(intelfb_resize); -int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output) +int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector) { struct fb_info *info; struct intelfb_par *par; @@ -581,7 +581,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_outp return -EINVAL; } - if (!output) + if (!connector) return -EINVAL; fb = drm_framebuffer_create(dev); @@ -627,9 +627,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_outp par->dev = dev; par->set.crtc = crtc; par->set.fb = fb; - par->hack = output; - par->set.outputs = &par->hack; - par->set.num_outputs = 1; + par->hack = connector; + par->set.connectors = &par->hack; + par->set.num_connectors = 1; info->fbops = &intelfb_ops; -- cgit v1.2.3 From e439e74776b215d70d8e34e8aa9cea22179dcbc6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 10:05:54 +1000 Subject: drm/modesetting: another re-org of some internals. Move dpms into the helper functions. Move crtc into the encoder. Move disable unused functions into the helper. --- linux-core/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 394d2344..138d189e 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -277,7 +277,7 @@ static int intelfb_set_par(struct fb_info *info) found = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->crtc == par->set.crtc){ + if (connector->encoder->crtc == par->set.crtc){ found = 1; break; } -- cgit v1.2.3 From 4e7b24639808e5e1e2c05143028db1a3bc2812e9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 14:04:41 +1000 Subject: drm: add functions to get/set gamma ramps --- linux-core/intel_fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 138d189e..268e95c5 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -41,6 +41,7 @@ #include "drmP.h" #include "drm.h" #include "drm_crtc.h" +#include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" @@ -79,8 +80,7 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, return 1; if (fb->depth == 8) { - if (crtc->funcs->gamma_set) - crtc->funcs->gamma_set(crtc, red, green, blue, regno); + intel_crtc_fb_gamma_set(crtc, red, green, blue, regno); return 0; } -- cgit v1.2.3 From 3ed17803d826b10f8f94d09acf12877e9738823c Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 2 Jun 2008 10:44:29 +0100 Subject: more checks for NULL encoder so we don't segfault. --- linux-core/intel_fb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 268e95c5..d490880a 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -277,7 +277,8 @@ static int intelfb_set_par(struct fb_info *info) found = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder->crtc == par->set.crtc){ + if (connector->encoder && + connector->encoder->crtc == par->set.crtc){ found = 1; break; } -- cgit v1.2.3 From 76a44f14d6339e5bc0c936ef4a360f6c152511bd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 11:59:28 +1000 Subject: drm/modesetting: overhaul the fb create/delete. Move TTM code into the driver --- linux-core/intel_fb.c | 58 +++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 25 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index d490880a..1107cbfb 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -573,7 +573,10 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn struct intelfb_par *par; struct device *device = &dev->pdev->dev; struct drm_framebuffer *fb; + struct intel_framebuffer *intel_fb; struct drm_display_mode *mode = crtc->desired_mode; + struct drm_mode_fb_cmd mode_cmd; + struct drm_buffer_object *fbo = NULL; int ret; @@ -585,22 +588,14 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn if (!connector) return -EINVAL; - fb = drm_framebuffer_create(dev); - if (!fb) { - framebuffer_release(info); - DRM_ERROR("failed to allocate fb.\n"); - return -EINVAL; - } - crtc->fb = fb; - - /* To allow resizeing without swapping buffers */ - fb->width = 2048;/* crtc->desired_mode->hdisplay; */ - fb->height = 2048;/* crtc->desired_mode->vdisplay; */ + mode_cmd.width = 2048;/* crtc->desired_mode->hdisplay; */ + mode_cmd.height = 2048;/* crtc->desired_mode->vdisplay; */ + + mode_cmd.bpp = 32; + mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8); + mode_cmd.depth = 24; - fb->bits_per_pixel = 32; - fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); - fb->depth = 24; - ret = drm_buffer_object_create(dev, fb->pitch * fb->height, + ret = drm_buffer_object_create(dev, mode_cmd.pitch * mode_cmd.height, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | @@ -611,14 +606,27 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn &fbo); if (ret || !fbo) { printk(KERN_ERR "failed to allocate framebuffer\n"); - drm_framebuffer_destroy(fb); framebuffer_release(info); return -EINVAL; } + - fb->bo = fbo; - printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, - fb->height, fbo->offset, fbo); + fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd); + if (!fb) { + framebuffer_release(info); + drm_bo_usage_deref_unlocked(&fbo); + DRM_ERROR("failed to allocate fb.\n"); + return -EINVAL; + } + + intel_fb = to_intel_framebuffer(fb); + + intel_fb->bo = fbo; + crtc->fb = fb; + + /* To allow resizeing without swapping buffers */ + printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width, + intel_fb->base.height, intel_fb->bo->offset, fbo); fb->fbdev = info; @@ -653,16 +661,16 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn } info->fix.line_length = fb->pitch; - info->fix.smem_start = fb->bo->offset + dev->mode_config.fb_base; + info->fix.smem_start = intel_fb->bo->offset + dev->mode_config.fb_base; info->fix.smem_len = info->fix.line_length * fb->height; info->flags = FBINFO_DEFAULT; - ret = drm_bo_kmap(fb->bo, 0, fb->bo->num_pages, &fb->kmap); + ret = drm_bo_kmap(intel_fb->bo, 0, intel_fb->bo->num_pages, &intel_fb->kmap); if (ret) DRM_ERROR("error mapping fb: %d\n", ret); - info->screen_base = fb->kmap.virtual; + info->screen_base = intel_fb->kmap.virtual; info->screen_size = info->fix.smem_len; /* FIXME */ info->pseudo_palette = fb->pseudo_palette; info->var.xres_virtual = fb->width; @@ -771,6 +779,7 @@ EXPORT_SYMBOL(intelfb_probe); int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) { struct fb_info *info; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); if (!fb) return -EINVAL; @@ -779,9 +788,8 @@ int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) if (info) { unregister_framebuffer(info); - drm_bo_kunmap(&fb->kmap); - drm_bo_usage_deref_unlocked(&fb->bo); - drm_framebuffer_destroy(fb); + drm_bo_kunmap(&intel_fb->kmap); + drm_bo_usage_deref_unlocked(&intel_fb->bo); framebuffer_release(info); } return 0; -- cgit v1.2.3 From 967bd219116a4f20aec828b890a225d2f92afd0b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 11:11:22 +1000 Subject: modesetting: initial attempt at debonging fb --- linux-core/intel_fb.c | 537 ++++++++++++++++++++++++++++---------------------- 1 file changed, 300 insertions(+), 237 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 1107cbfb..2f28ca1b 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -47,14 +47,10 @@ struct intelfb_par { struct drm_device *dev; -/* - struct drm_crtc *crtc; - struct drm_display_mode *fb_mode; - struct drm_framebuffer *fb; -*/ struct drm_display_mode *our_mode; - struct drm_mode_set set; - struct drm_connector *hack; + struct intel_framebuffer *intel_fb; + int crtc_count; + struct list_head mode_set_list; }; /* static int @@ -73,38 +69,41 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->set.fb; - struct drm_crtc *crtc = par->set.crtc; + struct drm_mode_set *modeset; - if (regno > 255) - return 1; + list_for_each_entry(modeset, &par->mode_set_list, head) { + struct drm_crtc *crtc = modeset->crtc; + struct drm_framebuffer *fb = modeset->fb; - if (fb->depth == 8) { - intel_crtc_fb_gamma_set(crtc, red, green, blue, regno); - return 0; - } + if (regno > 255) + return 1; - if (regno < 16) { - switch (fb->depth) { - case 15: - fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | - ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11); - break; - case 16: - fb->pseudo_palette[regno] = (red & 0xf800) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; - case 24: - case 32: - fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | - (green & 0xff00) | - ((blue & 0xff00) >> 8); - break; + if (fb->depth == 8) { + intel_crtc_fb_gamma_set(crtc, red, green, blue, regno); + return 0; } - } + if (regno < 16) { + switch (fb->depth) { + case 15: + fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 16: + fb->pseudo_palette[regno] = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 24: + case 32: + fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + } + } return 0; } @@ -112,12 +111,11 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct intelfb_par *par = info->par; - /*struct drm_device *dev = par->dev;*/ - struct drm_framebuffer *fb = par->set.fb; - /*struct drm_connector *connector;*/ - int depth/*, found = 0*/; + struct intel_framebuffer *intel_fb = par->intel_fb; + struct drm_framebuffer *fb = &intel_fb->base; + int depth; - if (!var->pixclock) + if (var->pixclock == -1 || !var->pixclock) return -EINVAL; /* Need to resize the fb object !!! */ @@ -194,31 +192,6 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, return -EINVAL; } -#if 0 - /* Here we walk the connector mode list and look for modes. If we haven't - * got it, then bail. Not very nice, so this is disabled. - * In the set_par code, we create our mode based on the incoming - * parameters. Nicer, but may not be desired by some. - */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->crtc == par->crtc) - break; - } - - list_for_each_entry(drm_mode, &connector->modes, head) { - if (drm_mode->hdisplay == var->xres && - drm_mode->vdisplay == var->yres && - (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && - (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { - found = 1; - break; - } - } - - if (!found) - return -EINVAL; -#endif - return 0; } @@ -227,123 +200,122 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, static int intelfb_set_par(struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->set.fb; struct drm_device *dev = par->dev; - struct drm_display_mode *drm_mode, *search_mode; - struct drm_connector *connector = NULL; struct fb_var_screeninfo *var = &info->var; int found = 0; - DRM_DEBUG("\n"); + DRM_DEBUG("%d %d\n", var->xres, var->pixclock); - switch (var->bits_per_pixel) { - case 16: - fb->depth = (var->green.length == 6) ? 16 : 15; - break; - case 32: - fb->depth = (var->transp.length > 0) ? 32 : 24; - break; - default: - fb->depth = var->bits_per_pixel; - break; - } - - fb->bits_per_pixel = var->bits_per_pixel; - info->fix.line_length = fb->pitch; - info->fix.smem_len = info->fix.line_length * fb->height; - info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - - info->screen_size = info->fix.smem_len; /* ??? */ - - /* create a drm 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); - - found = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder && - connector->encoder->crtc == par->set.crtc){ - found = 1; - break; - } - } + if (var->pixclock != -1) { - /* no connector bound, bail */ - if (!found) - return -EINVAL; + DRM_ERROR("PIXEL CLCOK SET\n"); +#if 0 + struct intel_framebuffer *intel_fb = par->intel_fb; + struct drm_framebuffer *fb = &intel_fb->base; + struct drm_display_mode *drm_mode, *search_mode; + struct drm_connector *connector = NULL; - found = 0; - drm_mode_debug_printmodeline(drm_mode); - list_for_each_entry(search_mode, &connector->modes, head) { - drm_mode_debug_printmodeline(search_mode); - if (drm_mode_equal(drm_mode, search_mode)) { - drm_mode_destroy(dev, drm_mode); - drm_mode = search_mode; - found = 1; + switch (var->bits_per_pixel) { + case 16: + fb->depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + fb->depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + fb->depth = var->bits_per_pixel; break; } - } - - /* If we didn't find a matching mode that exists on our connector, - * create a new attachment for the incoming user specified mode - */ - if (!found) { - if (par->our_mode) { - /* this also destroys the mode */ - drm_mode_detachmode_crtc(dev, par->our_mode); + + fb->bits_per_pixel = var->bits_per_pixel; + + info->fix.line_length = fb->pitch; + info->fix.smem_len = info->fix.line_length * fb->height; + info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + + info->screen_size = info->fix.smem_len; /* ??? */ + /* reuse desired mode if possible */ + /* create a drm 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); + + found = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder && + connector->encoder->crtc == par->set.crtc){ + found = 1; + break; + } } - - par->set.mode = drm_mode; - par->our_mode = drm_mode; + + /* no connector bound, bail */ + if (!found) + return -EINVAL; + + found = 0; drm_mode_debug_printmodeline(drm_mode); - /* attach mode */ - drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode); + list_for_each_entry(search_mode, &connector->modes, head) { + drm_mode_debug_printmodeline(search_mode); + if (drm_mode_equal(drm_mode, search_mode)) { + drm_mode_destroy(dev, drm_mode); + drm_mode = search_mode; + found = 1; + break; + } + } + + /* If we didn't find a matching mode that exists on our connector, + * create a new attachment for the incoming user specified mode + */ + if (!found) { + if (par->our_mode) { + /* this also destroys the mode */ + drm_mode_detachmode_crtc(dev, par->our_mode); + } + + par->set.mode = drm_mode; + par->our_mode = drm_mode; + drm_mode_debug_printmodeline(drm_mode); + /* attach mode */ + drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode); + } else { + par->set.mode = drm_mode; + if (par->our_mode) + drm_mode_detachmode_crtc(dev, par->our_mode); + par->our_mode = NULL; + } + return par->set.crtc->funcs->set_config(&par->set); +#endif + return -EINVAL; } else { - par->set.mode = drm_mode; - if (par->our_mode) - drm_mode_detachmode_crtc(dev, par->our_mode); - par->our_mode = NULL; - } - -#if 0 - /* re-attach fb */ - if (!par->crtc->fb) { - par->crtc->fb = par->fb; - changed = 1; + struct drm_mode_set *modeset; + int ret; + + list_for_each_entry(modeset, &par->mode_set_list, head) { + if (modeset->num_connectors) { + ret = modeset->crtc->funcs->set_config(modeset); + if (ret) + return ret; + } + } + return 0; } - - if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) - changed = 1; - - drm_mode_debug_printmodeline(drm_mode); - drm_mode_debug_printmodeline(&par->crtc->mode); - if (!drm_mode_equal(drm_mode, &par->crtc->mode)) - changed = 1; - - if (changed) - if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) - return -EINVAL; - - return 0; -#else - return par->set.crtc->funcs->set_config(&par->set); -#endif } #if 0 @@ -495,17 +467,22 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct intelfb_par *par = info->par; - int ret; + struct drm_mode_set *modeset; + int ret = 0; DRM_DEBUG("\n"); - - par->set.x = var->xoffset; - par->set.y = var->yoffset; - ret = par->set.crtc->funcs->set_config(&par->set); + list_for_each_entry(modeset, &par->mode_set_list, head) { + modeset->x = var->xoffset; + modeset->y = var->yoffset; - if (!ret) { - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; + if (modeset->num_connectors) { + ret = modeset->crtc->funcs->set_config(modeset); + + if (!ret) { + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + } + } } return ret; @@ -567,29 +544,19 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) } EXPORT_SYMBOL(intelfb_resize); -int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector) +int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height, struct intel_framebuffer **intel_fb_p) { struct fb_info *info; struct intelfb_par *par; - struct device *device = &dev->pdev->dev; struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb; - struct drm_display_mode *mode = crtc->desired_mode; struct drm_mode_fb_cmd mode_cmd; - struct drm_buffer_object *fbo = NULL; + struct device *device = &dev->pdev->dev; int ret; - info = framebuffer_alloc(sizeof(struct intelfb_par), device); - if (!info){ - return -EINVAL; - } - - if (!connector) - return -EINVAL; - - mode_cmd.width = 2048;/* crtc->desired_mode->hdisplay; */ - mode_cmd.height = 2048;/* crtc->desired_mode->vdisplay; */ + mode_cmd.width = fb_width;/* crtc->desired_mode->hdisplay; */ + mode_cmd.height = fb_height;/* crtc->desired_mode->vdisplay; */ mode_cmd.bpp = 32; mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8); @@ -606,43 +573,29 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn &fbo); if (ret || !fbo) { printk(KERN_ERR "failed to allocate framebuffer\n"); - framebuffer_release(info); return -EINVAL; } fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd); if (!fb) { - framebuffer_release(info); drm_bo_usage_deref_unlocked(&fbo); DRM_ERROR("failed to allocate fb.\n"); return -EINVAL; } intel_fb = to_intel_framebuffer(fb); + *intel_fb_p = intel_fb; intel_fb->bo = fbo; - crtc->fb = fb; - - /* To allow resizeing without swapping buffers */ - printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width, - intel_fb->base.height, intel_fb->bo->offset, fbo); + info = framebuffer_alloc(sizeof(struct intelfb_par), device); + if (!info) + return -EINVAL; - fb->fbdev = info; - par = info->par; - par->dev = dev; - par->set.crtc = crtc; - par->set.fb = fb; - par->hack = connector; - par->set.connectors = &par->hack; - par->set.num_connectors = 1; - - info->fbops = &intelfb_ops; - - strcpy(info->fix.id, "intelfb"); + strcpy(info->fix.id, "inteldrmfb"); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_TRUECOLOR; info->fix.type_aux = 0; @@ -651,14 +604,10 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn info->fix.ywrapstep = 0; info->fix.accel = FB_ACCEL_I830; info->fix.type_aux = 0; - - if (IS_I9XX(dev)) { - info->fix.mmio_start = pci_resource_start(dev->pdev, 0); - info->fix.mmio_len = pci_resource_len(dev->pdev, 0); - } else { - info->fix.mmio_start = pci_resource_start(dev->pdev, 1); - info->fix.mmio_len = pci_resource_len(dev->pdev, 1); - } + + info->flags = FBINFO_DEFAULT; + + info->fbops = &intelfb_ops; info->fix.line_length = fb->pitch; info->fix.smem_start = intel_fb->bo->offset + dev->mode_config.fb_base; @@ -682,28 +631,16 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn info->var.height = -1; info->var.width = -1; - info->var.xres = mode->hdisplay; - info->var.right_margin = mode->hsync_start - mode->hdisplay; - info->var.hsync_len = mode->hsync_end - mode->hsync_start; - info->var.left_margin = mode->htotal - mode->hsync_end; - info->var.yres = mode->vdisplay; - info->var.lower_margin = mode->vsync_start - mode->vdisplay; - info->var.vsync_len = mode->vsync_end - mode->vsync_start; - info->var.upper_margin = mode->vtotal - mode->vsync_end; - info->var.pixclock = KHZ2PICOS(mode->clock); - - if (mode->flags & V_PHSYNC) - info->var.sync |= FB_SYNC_HOR_HIGH_ACT; - - if (mode->flags & V_PVSYNC) - info->var.sync |= FB_SYNC_VERT_HIGH_ACT; + info->var.xres = fb_width; + info->var.yres = fb_height; - if (mode->flags & V_INTERLACE) - info->var.vmode = FB_VMODE_INTERLACED; - else if (mode->flags & V_DBLSCAN) - info->var.vmode = FB_VMODE_DOUBLE; - else - info->var.vmode = FB_VMODE_NONINTERLACED; + if (IS_I9XX(dev)) { + info->fix.mmio_start = pci_resource_start(dev->pdev, 0); + info->fix.mmio_len = pci_resource_len(dev->pdev, 0); + } else { + info->fix.mmio_start = pci_resource_start(dev->pdev, 1); + info->fix.mmio_len = pci_resource_len(dev->pdev, 1); + } info->pixmap.size = 64*1024; info->pixmap.buf_align = 8; @@ -767,12 +704,138 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn break; } + fb->fbdev = info; + + INIT_LIST_HEAD(&par->mode_set_list); + + par->intel_fb = intel_fb; + + /* To allow resizeing without swapping buffers */ + printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width, + intel_fb->base.height, intel_fb->bo->offset, fbo); + + return 0; +} + +int intelfb_probe(struct drm_device *dev) +{ + struct fb_info *info; + struct intelfb_par *par; + struct device *device = &dev->pdev->dev; + struct intel_framebuffer *intel_fb; + struct drm_mode_set *modeset; + struct drm_crtc *crtc; + struct drm_connector *connector; + int ret; + int crtc_count = 0, i; + unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; + + DRM_DEBUG("\n"); + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->desired_mode) { + if (crtc->desired_mode->hdisplay < fb_width) + fb_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay < fb_height) + fb_height = crtc->desired_mode->vdisplay; + } + crtc_count++; + } + + if (fb_width == -1 || fb_height == -1) { + return -EINVAL; + } + + DRM_DEBUG("here %d %d\n", fb_width, fb_height); + ret = intelfb_create(dev, fb_width, fb_height, &intel_fb); + if (ret) + return -EINVAL; + + DRM_DEBUG("here %p\n", intel_fb); + info = intel_fb->base.fbdev; + par = info->par; + + DRM_DEBUG("crtc count is %d\n", crtc_count); + /* make up a couple of config sets */ + for (i = 0; i < crtc_count; i++) { + int conn_count = 0; + + modeset = kzalloc(sizeof(struct drm_mode_set), GFP_KERNEL); + modeset->fb = &intel_fb->base; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + if (intel_crtc->pipe == i) + modeset->crtc = crtc; + } + + + DRM_DEBUG("1\n"); + /* find out how many connectors are on this */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder) + if (connector->encoder->crtc == modeset->crtc) + conn_count++; + } + + list_add_tail(&modeset->head, &par->mode_set_list); + + if (!conn_count) + continue; + + DRM_DEBUG("cc %d\n", conn_count); + modeset->connectors = kcalloc(conn_count, sizeof(struct drm_connector *), GFP_KERNEL); + if (!modeset->connectors) { + ret = -ENOMEM; + goto fail; + } + + modeset->num_connectors = conn_count; + + conn_count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder) + if (connector->encoder->crtc == modeset->crtc) + modeset->connectors[conn_count++] = connector; + } + modeset->mode = modeset->crtc->desired_mode; + } + + info->var.pixclock = -1; +#if 0 + info->var.right_margin = mode->hsync_start - mode->hdisplay; + info->var.hsync_len = mode->hsync_end - mode->hsync_start; + info->var.left_margin = mode->htotal - mode->hsync_end; + info->var.lower_margin = mode->vsync_start - mode->vdisplay; + info->var.vsync_len = mode->vsync_end - mode->vsync_start; + info->var.upper_margin = mode->vtotal - mode->vsync_end; + info->var.pixclock = KHZ2PICOS(mode->clock); + + if (mode->flags & V_PHSYNC) + info->var.sync |= FB_SYNC_HOR_HIGH_ACT; + + if (mode->flags & V_PVSYNC) + info->var.sync |= FB_SYNC_VERT_HIGH_ACT; + + if (mode->flags & V_INTERLACE) + info->var.vmode = FB_VMODE_INTERLACED; + else if (mode->flags & V_DBLSCAN) + info->var.vmode = FB_VMODE_DOUBLE; + else + info->var.vmode = FB_VMODE_NONINTERLACED; + +#endif + if (register_framebuffer(info) < 0) return -EINVAL; printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); return 0; +fail: + /* TODO */ + return ret; } EXPORT_SYMBOL(intelfb_probe); -- cgit v1.2.3 From 1d980669e6d448e15c61507d81552c532b93bcd8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 11:20:52 +1000 Subject: modesetting: add surface width/heights --- linux-core/intel_fb.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 2f28ca1b..a87672d8 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -544,7 +544,9 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) } EXPORT_SYMBOL(intelfb_resize); -int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height, struct intel_framebuffer **intel_fb_p) +int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height, + uint32_t surface_width, uint32_t surface_height, + struct intel_framebuffer **intel_fb_p) { struct fb_info *info; struct intelfb_par *par; @@ -622,8 +624,8 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height info->screen_base = intel_fb->kmap.virtual; info->screen_size = info->fix.smem_len; /* FIXME */ info->pseudo_palette = fb->pseudo_palette; - info->var.xres_virtual = fb->width; - info->var.yres_virtual = fb->height; + info->var.xres_virtual = surface_width; + info->var.yres_virtual = surface_height; info->var.bits_per_pixel = fb->bits_per_pixel; info->var.xoffset = 0; info->var.yoffset = 0; @@ -729,6 +731,7 @@ int intelfb_probe(struct drm_device *dev) int ret; int crtc_count = 0, i; unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; + unsigned int surface_width = 0, surface_height = 0; DRM_DEBUG("\n"); @@ -739,6 +742,12 @@ int intelfb_probe(struct drm_device *dev) if (crtc->desired_mode->vdisplay < fb_height) fb_height = crtc->desired_mode->vdisplay; + + if (crtc->desired_mode->hdisplay > surface_width) + surface_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay > surface_height) + surface_height = crtc->desired_mode->vdisplay; } crtc_count++; } @@ -747,8 +756,8 @@ int intelfb_probe(struct drm_device *dev) return -EINVAL; } - DRM_DEBUG("here %d %d\n", fb_width, fb_height); - ret = intelfb_create(dev, fb_width, fb_height, &intel_fb); + DRM_DEBUG("here %d %d %d %d\n", fb_width, fb_height, surface_width, surface_height); + ret = intelfb_create(dev, fb_width, fb_height, surface_width, surface_height, &intel_fb); if (ret) return -EINVAL; -- cgit v1.2.3 From 1495dd31d60e588743f20a9e470c8b0045313e7c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 11:24:57 +1000 Subject: modesetting: use surface width height for buffer allocs --- linux-core/intel_fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index a87672d8..ae290f3c 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -557,8 +557,8 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height struct device *device = &dev->pdev->dev; int ret; - mode_cmd.width = fb_width;/* crtc->desired_mode->hdisplay; */ - mode_cmd.height = fb_height;/* crtc->desired_mode->vdisplay; */ + mode_cmd.width = surface_width;/* crtc->desired_mode->hdisplay; */ + mode_cmd.height = surface_height;/* crtc->desired_mode->vdisplay; */ mode_cmd.bpp = 32; mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8); -- cgit v1.2.3 From 56a1293184e4f628498c88e38e1601349b05ad93 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 11:43:48 +1000 Subject: modesetting: fix fb clearing up --- linux-core/intel_fb.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index ae290f3c..0355e784 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -623,9 +623,12 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height info->screen_base = intel_fb->kmap.virtual; info->screen_size = info->fix.smem_len; /* FIXME */ + + memset(intel_fb->kmap.virtual, 0, info->screen_size); + info->pseudo_palette = fb->pseudo_palette; - info->var.xres_virtual = surface_width; - info->var.yres_virtual = surface_height; + info->var.xres_virtual = fb->width; + info->var.yres_virtual = fb->height; info->var.bits_per_pixel = fb->bits_per_pixel; info->var.xoffset = 0; info->var.yoffset = 0; -- cgit v1.2.3 From f73e54bbf0b97a8f5184ede64d4f263020d623ee Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 13:40:08 +1000 Subject: drm: modesetting unify the hotplug init paths a lot. remove fb callbacks, just probe into the driver to sort it out --- linux-core/intel_fb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 0355e784..9b2e9314 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -469,7 +469,6 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, struct intelfb_par *par = info->par; struct drm_mode_set *modeset; int ret = 0; - DRM_DEBUG("\n"); list_for_each_entry(modeset, &par->mode_set_list, head) { modeset->x = var->xoffset; -- cgit v1.2.3 From efcf066eff690887ace33c0f1192168a31115805 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 15:21:07 +1000 Subject: drm/modesetting: attempt to make fb code more sane --- linux-core/intel_fb.c | 234 +++++++++++++++++++++++++++++++------------------- 1 file changed, 144 insertions(+), 90 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 9b2e9314..2355bf3d 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -585,6 +585,8 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height return -EINVAL; } + list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); + intel_fb = to_intel_framebuffer(fb); *intel_fb_p = intel_fb; @@ -721,129 +723,181 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height return 0; } -int intelfb_probe(struct drm_device *dev) +#define INTELFB_CONN_LIMIT 4 + +static int intelfb_create_crtcmodesets(struct intel_framebuffer *intel_fb, int num_sets, int crtc_base) { - struct fb_info *info; + int i,j; + struct drm_device *dev = intel_fb->base.dev; struct intelfb_par *par; - struct device *device = &dev->pdev->dev; - struct intel_framebuffer *intel_fb; struct drm_mode_set *modeset; struct drm_crtc *crtc; - struct drm_connector *connector; - int ret; - int crtc_count = 0, i; - unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; - unsigned int surface_width = 0, surface_height = 0; - - DRM_DEBUG("\n"); - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->desired_mode) { - if (crtc->desired_mode->hdisplay < fb_width) - fb_width = crtc->desired_mode->hdisplay; + struct fb_info *info; - if (crtc->desired_mode->vdisplay < fb_height) - fb_height = crtc->desired_mode->vdisplay; + info = intel_fb->base.fbdev; + par = info->par; - if (crtc->desired_mode->hdisplay > surface_width) - surface_width = crtc->desired_mode->hdisplay; + for (i = 0; i < num_sets; i++) { + modeset = kzalloc(sizeof(struct drm_mode_set) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); + if (!modeset) + goto fail; - if (crtc->desired_mode->vdisplay > surface_height) - surface_height = crtc->desired_mode->vdisplay; + /* attach a CRTC to the modeset */ + j = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (j == i + crtc_base) { + modeset->crtc = crtc; + break; + } + j++; } - crtc_count++; + modeset->fb = &intel_fb->base; + + modeset->connectors = (struct drm_connector **)(modeset + 1); + list_add_tail(&modeset->head, &par->mode_set_list); } - if (fb_width == -1 || fb_height == -1) { - return -EINVAL; +fail: + list_for_each_entry(modeset, &par->mode_set_list, head) { + list_del(&modeset->head); + kfree(modeset); } - DRM_DEBUG("here %d %d %d %d\n", fb_width, fb_height, surface_width, surface_height); - ret = intelfb_create(dev, fb_width, fb_height, surface_width, surface_height, &intel_fb); - if (ret) - return -EINVAL; + return -ENOMEM; +} - DRM_DEBUG("here %p\n", intel_fb); - info = intel_fb->base.fbdev; - par = info->par; +static int intelfb_single_fb_probe(struct drm_device *dev) +{ + struct drm_crtc *crtc; + struct drm_connector *connector; + unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; + unsigned int surface_width = 0, surface_height = 0; + int new_fb = 0; + int crtc_count = 0; + int ret, i, conn_count = 0; + struct intel_framebuffer *intel_fb; + struct fb_info *info; + struct intelfb_par *par; + struct drm_mode_set *modeset; - DRM_DEBUG("crtc count is %d\n", crtc_count); - /* make up a couple of config sets */ - for (i = 0; i < crtc_count; i++) { - int conn_count = 0; + /* first up get a count of crtcs now in use and new min/maxes width/heights */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (drm_helper_crtc_in_use(crtc)) { + if (crtc->desired_mode) { + if (crtc->desired_mode->hdisplay < fb_width) + fb_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay < fb_height) + fb_height = crtc->desired_mode->vdisplay; + + if (crtc->desired_mode->hdisplay > surface_width) + surface_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay > surface_height) + surface_height = crtc->desired_mode->vdisplay; + } + crtc_count++; + } + } - modeset = kzalloc(sizeof(struct drm_mode_set), GFP_KERNEL); - modeset->fb = &intel_fb->base; + if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { + /* hmm everyone went away - assume VGA cable just fell out + and will come back later. */ + return 0; + } - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - if (intel_crtc->pipe == i) - modeset->crtc = crtc; + /* do we have an fb already? */ + if (list_empty(&dev->mode_config.fb_kernel_list)) { + /* create an fb if we don't have one */ + ret = intelfb_create(dev, fb_width, fb_height, surface_width, surface_height, &intel_fb); + if (ret) + return -EINVAL; + + /* create a set per crtc connected to this fb */ + ret = intelfb_create_crtcmodesets(intel_fb, dev->mode_config.num_crtc, 0); + if (ret) + return ret; + new_fb = 1; + } else { + struct drm_framebuffer *fb; + fb = list_first_entry(&dev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head); + intel_fb = to_intel_framebuffer(fb); + + /* check if we are going to have a size issue */ + /* do a surface compare */ + if ((fb->width < surface_width) || (fb->height < surface_height)) { + DRM_ERROR("NEED BIGGER SURFACE DUDE\n"); + return -EINVAL; } + } + info = intel_fb->base.fbdev; + par = info->par; - DRM_DEBUG("1\n"); - /* find out how many connectors are on this */ + /* okay we need to setup new connector sets in the crtcs */ + list_for_each_entry(modeset, &par->mode_set_list, head) { + + conn_count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->encoder) - if (connector->encoder->crtc == modeset->crtc) + if(connector->encoder->crtc == modeset->crtc) { + modeset->connectors[conn_count] = connector; conn_count++; + if (conn_count > INTELFB_CONN_LIMIT) + BUG(); + } } - list_add_tail(&modeset->head, &par->mode_set_list); - - if (!conn_count) - continue; - - DRM_DEBUG("cc %d\n", conn_count); - modeset->connectors = kcalloc(conn_count, sizeof(struct drm_connector *), GFP_KERNEL); - if (!modeset->connectors) { - ret = -ENOMEM; - goto fail; - } + for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) + modeset->connectors[i] = NULL; modeset->num_connectors = conn_count; - - conn_count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder) - if (connector->encoder->crtc == modeset->crtc) - modeset->connectors[conn_count++] = connector; - } - modeset->mode = modeset->crtc->desired_mode; + if (modeset->mode != modeset->crtc->desired_mode) + modeset->mode = modeset->crtc->desired_mode; } - - info->var.pixclock = -1; -#if 0 - info->var.right_margin = mode->hsync_start - mode->hdisplay; - info->var.hsync_len = mode->hsync_end - mode->hsync_start; - info->var.left_margin = mode->htotal - mode->hsync_end; - info->var.lower_margin = mode->vsync_start - mode->vdisplay; - info->var.vsync_len = mode->vsync_end - mode->vsync_start; - info->var.upper_margin = mode->vtotal - mode->vsync_end; - info->var.pixclock = KHZ2PICOS(mode->clock); - if (mode->flags & V_PHSYNC) - info->var.sync |= FB_SYNC_HOR_HIGH_ACT; + if (new_fb) { + info->var.pixclock = -1; + if (register_framebuffer(info) < 0) + return -EINVAL; + } + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + return 0; +} + +int intelfb_probe(struct drm_device *dev) +{ + int ret; - if (mode->flags & V_PVSYNC) - info->var.sync |= FB_SYNC_VERT_HIGH_ACT; + DRM_DEBUG("\n"); - if (mode->flags & V_INTERLACE) - info->var.vmode = FB_VMODE_INTERLACED; - else if (mode->flags & V_DBLSCAN) - info->var.vmode = FB_VMODE_DOUBLE; - else - info->var.vmode = FB_VMODE_NONINTERLACED; + /* something has changed in the lower levels of hell - deal with it + here */ + + /* two modes : a) 1 fb to rule all crtcs. + b) one fb per crtc. + two actions 1) new connected device + 2) device removed. + case a/1 : if the fb surface isn't big enough - resize the surface fb. + if the fb size isn't big enough - resize fb into surface. + if everything big enough configure the new crtc/etc. + case a/2 : undo the configuration + possibly resize down the fb to fit the new configuration. + case b/1 : see if it is on a new crtc - setup a new fb and add it. + case b/2 : teardown the new fb. + */ -#endif + /* mode a first */ + /* search for an fb */ + if (i915_fbpercrtc == 1) { + ret = -EINVAL; + goto fail; + } - if (register_framebuffer(info) < 0) - return -EINVAL; + ret = intelfb_single_fb_probe(dev); - printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, - info->fix.id); - return 0; fail: /* TODO */ return ret; -- cgit v1.2.3 From b31adb005afc5553fb30aa2c1710faee299bc730 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 15:55:03 +1000 Subject: drm/modesetting: more fb interface cleanups --- linux-core/intel_fb.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 2355bf3d..b4afb155 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -200,9 +200,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, static int intelfb_set_par(struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_device *dev = par->dev; struct fb_var_screeninfo *var = &info->var; - int found = 0; DRM_DEBUG("%d %d\n", var->xres, var->pixclock); @@ -215,6 +213,9 @@ static int intelfb_set_par(struct fb_info *info) struct drm_framebuffer *fb = &intel_fb->base; struct drm_display_mode *drm_mode, *search_mode; struct drm_connector *connector = NULL; + struct drm_device *dev = par->dev; + + int found = 0; switch (var->bits_per_pixel) { case 16: @@ -756,6 +757,7 @@ static int intelfb_create_crtcmodesets(struct intel_framebuffer *intel_fb, int n modeset->connectors = (struct drm_connector **)(modeset + 1); list_add_tail(&modeset->head, &par->mode_set_list); } + return 0; fail: list_for_each_entry(modeset, &par->mode_set_list, head) { @@ -860,7 +862,8 @@ static int intelfb_single_fb_probe(struct drm_device *dev) info->var.pixclock = -1; if (register_framebuffer(info) < 0) return -EINVAL; - } + } else + intelfb_set_par(info); printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); -- cgit v1.2.3 From d9ead89c79732124f54b4a9dfe698bc7aad7faee Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 16:32:41 +1000 Subject: drm/modeset: add more debugging and fixup some fb enable/disabe bits --- linux-core/intel_fb.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index b4afb155..5ec5bb8f 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -309,11 +309,9 @@ static int intelfb_set_par(struct fb_info *info) int ret; list_for_each_entry(modeset, &par->mode_set_list, head) { - if (modeset->num_connectors) { - ret = modeset->crtc->funcs->set_config(modeset); - if (ret) - return ret; - } + ret = modeset->crtc->funcs->set_config(modeset); + if (ret) + return ret; } return 0; } @@ -782,6 +780,7 @@ static int intelfb_single_fb_probe(struct drm_device *dev) struct intelfb_par *par; struct drm_mode_set *modeset; + DRM_DEBUG("\n"); /* first up get a count of crtcs now in use and new min/maxes width/heights */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (drm_helper_crtc_in_use(crtc)) { -- cgit v1.2.3 From 8387a232a3305d10c4ac4cd08f9ebd0888944e55 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 12:02:51 +1000 Subject: intelfb: move mode sets into the intel crtcs better place to store them. --- linux-core/intel_fb.c | 119 ++++++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 61 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 5ec5bb8f..71f71a0d 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -50,7 +50,8 @@ struct intelfb_par { struct drm_display_mode *our_mode; struct intel_framebuffer *intel_fb; int crtc_count; - struct list_head mode_set_list; + /* crtc currently bound to this */ + uint32_t crtc_ids[2]; }; /* static int @@ -69,12 +70,23 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_mode_set *modeset; + struct drm_device *dev = par->dev; + struct drm_crtc *crtc; + int i; - list_for_each_entry(modeset, &par->mode_set_list, head) { - struct drm_crtc *crtc = modeset->crtc; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_mode_set *modeset = &intel_crtc->mode_set; struct drm_framebuffer *fb = modeset->fb; + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + if (i == par->crtc_count) + continue; + + if (regno > 255) return 1; @@ -200,7 +212,9 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, static int intelfb_set_par(struct fb_info *info) { struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; struct fb_var_screeninfo *var = &info->var; + int i; DRM_DEBUG("%d %d\n", var->xres, var->pixclock); @@ -305,11 +319,20 @@ static int intelfb_set_par(struct fb_info *info) #endif return -EINVAL; } else { - struct drm_mode_set *modeset; + struct drm_crtc *crtc; int ret; - list_for_each_entry(modeset, &par->mode_set_list, head) { - ret = modeset->crtc->funcs->set_config(modeset); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + if (i == par->crtc_count) + continue; + + ret = crtc->funcs->set_config(&intel_crtc->mode_set); if (ret) return ret; } @@ -466,15 +489,30 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; struct drm_mode_set *modeset; + struct drm_crtc *crtc; + struct intel_crtc *intel_crtc; int ret = 0; + int i; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + if (i == par->crtc_count) + continue; + + intel_crtc = to_intel_crtc(crtc); + modeset = &intel_crtc->mode_set; - list_for_each_entry(modeset, &par->mode_set_list, head) { modeset->x = var->xoffset; modeset->y = var->yoffset; if (modeset->num_connectors) { - ret = modeset->crtc->funcs->set_config(modeset); + ret = crtc->funcs->set_config(modeset); if (!ret) { info->var.xoffset = var->xoffset; @@ -711,9 +749,8 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height fb->fbdev = info; - INIT_LIST_HEAD(&par->mode_set_list); - par->intel_fb = intel_fb; + par->dev = dev; /* To allow resizeing without swapping buffers */ printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width, @@ -724,48 +761,6 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height #define INTELFB_CONN_LIMIT 4 -static int intelfb_create_crtcmodesets(struct intel_framebuffer *intel_fb, int num_sets, int crtc_base) -{ - int i,j; - struct drm_device *dev = intel_fb->base.dev; - struct intelfb_par *par; - struct drm_mode_set *modeset; - struct drm_crtc *crtc; - struct fb_info *info; - - info = intel_fb->base.fbdev; - par = info->par; - - for (i = 0; i < num_sets; i++) { - modeset = kzalloc(sizeof(struct drm_mode_set) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); - if (!modeset) - goto fail; - - /* attach a CRTC to the modeset */ - j = 0; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (j == i + crtc_base) { - modeset->crtc = crtc; - break; - } - j++; - } - modeset->fb = &intel_fb->base; - - modeset->connectors = (struct drm_connector **)(modeset + 1); - list_add_tail(&modeset->head, &par->mode_set_list); - } - return 0; - -fail: - list_for_each_entry(modeset, &par->mode_set_list, head) { - list_del(&modeset->head); - kfree(modeset); - } - - return -ENOMEM; -} - static int intelfb_single_fb_probe(struct drm_device *dev) { struct drm_crtc *crtc; @@ -795,7 +790,8 @@ static int intelfb_single_fb_probe(struct drm_device *dev) surface_width = crtc->desired_mode->hdisplay; if (crtc->desired_mode->vdisplay > surface_height) - surface_height = crtc->desired_mode->vdisplay; + surface_height = crtc->desired_mode->vdisplay; + } crtc_count++; } @@ -813,11 +809,6 @@ static int intelfb_single_fb_probe(struct drm_device *dev) ret = intelfb_create(dev, fb_width, fb_height, surface_width, surface_height, &intel_fb); if (ret) return -EINVAL; - - /* create a set per crtc connected to this fb */ - ret = intelfb_create_crtcmodesets(intel_fb, dev->mode_config.num_crtc, 0); - if (ret) - return ret; new_fb = 1; } else { struct drm_framebuffer *fb; @@ -835,9 +826,12 @@ static int intelfb_single_fb_probe(struct drm_device *dev) info = intel_fb->base.fbdev; par = info->par; + crtc_count = 0; /* okay we need to setup new connector sets in the crtcs */ - list_for_each_entry(modeset, &par->mode_set_list, head) { - + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + modeset = &intel_crtc->mode_set; + modeset->fb = &intel_fb->base; conn_count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->encoder) @@ -852,10 +846,13 @@ static int intelfb_single_fb_probe(struct drm_device *dev) for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) modeset->connectors[i] = NULL; + par->crtc_ids[crtc_count++] = crtc->base.id; + modeset->num_connectors = conn_count; if (modeset->mode != modeset->crtc->desired_mode) modeset->mode = modeset->crtc->desired_mode; } + par->crtc_count = crtc_count; if (new_fb) { info->var.pixclock = -1; -- cgit v1.2.3 From fc08877b1759f569890665b9d24ea35d11352158 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 14:53:34 +1000 Subject: intelfb: admit fbdev is crap and punt on trying to resize to a larger fbdev. --- linux-core/intel_fb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 71f71a0d..9967f913 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -815,10 +815,12 @@ static int intelfb_single_fb_probe(struct drm_device *dev) fb = list_first_entry(&dev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head); intel_fb = to_intel_framebuffer(fb); - /* check if we are going to have a size issue */ - /* do a surface compare */ + /* if someone hotplugs something bigger than we have already allocated, we are pwned. + As really we can't resize an fbdev that is in the wild currently due to fbdev + not really being designed for the lower layers moving stuff around under it. + - so in the grand style of things - punt. */ if ((fb->width < surface_width) || (fb->height < surface_height)) { - DRM_ERROR("NEED BIGGER SURFACE DUDE\n"); + DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); return -EINVAL; } } -- cgit v1.2.3 From e6a3a1fdadd162e3cf12e88ad13c4342f9ee23a1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 14:55:03 +1000 Subject: intelfb: remove duplicate define --- linux-core/intel_fb.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 9967f913..d202649f 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -759,8 +759,6 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height return 0; } -#define INTELFB_CONN_LIMIT 4 - static int intelfb_single_fb_probe(struct drm_device *dev) { struct drm_crtc *crtc; -- cgit v1.2.3 From be501f00a3c91a8ae78189577873d8a6b8ea1c67 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 15:21:22 +1000 Subject: intelfb: add multi fb paths --- linux-core/intel_fb.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 4 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index d202649f..85a173e1 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -759,6 +759,94 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height return 0; } +static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_framebuffer *intel_fb; + struct drm_framebuffer *fb; + struct drm_connector *connector; + struct fb_info *info; + struct intelfb_par *par; + struct drm_mode_set *modeset; + unsigned int width, height; + int new_fb = 0; + int ret, i, conn_count; + + if (!drm_helper_crtc_in_use(crtc)) + return 0; + + if (!crtc->desired_mode) + return 0; + + width = crtc->desired_mode->hdisplay; + height = crtc->desired_mode->vdisplay; + + /* is there an fb bound to this crtc already */ + if (!intel_crtc->mode_set.fb) { + ret = intelfb_create(dev, width, height, width, height, &intel_fb); + if (ret) + return -EINVAL; + new_fb = 1; + } else { + fb = intel_crtc->mode_set.fb; + intel_fb = to_intel_framebuffer(fb); + if ((intel_fb->base.width < width) || (intel_fb->base.height < height)) + return -EINVAL; + } + + info = intel_fb->base.fbdev; + par = info->par; + + modeset = &intel_crtc->mode_set; + modeset->fb = &intel_fb->base; + conn_count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder) + if (connector->encoder->crtc == modeset->crtc) { + modeset->connectors[conn_count] = connector; + conn_count++; + if (conn_count > INTELFB_CONN_LIMIT) + BUG(); + } + } + + for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) + modeset->connectors[i] = NULL; + + par->crtc_ids[0] = crtc->base.id; + + modeset->num_connectors = conn_count; + if (modeset->mode != modeset->crtc->desired_mode) + modeset->mode = modeset->crtc->desired_mode; + + par->crtc_count = 1; + + if (new_fb) { + info->var.pixclock = -1; + if (register_framebuffer(info) < 0) + return -EINVAL; + } else + intelfb_set_par(info); + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + return 0; +} + +static int intelfb_multi_fb_probe(struct drm_device *dev) +{ + + struct drm_crtc *crtc; + int ret = 0; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + ret = intelfb_multi_fb_probe_crtc(dev, crtc); + if (ret) + return ret; + } + return ret; +} + static int intelfb_single_fb_probe(struct drm_device *dev) { struct drm_crtc *crtc; @@ -891,12 +979,11 @@ int intelfb_probe(struct drm_device *dev) /* mode a first */ /* search for an fb */ if (i915_fbpercrtc == 1) { - ret = -EINVAL; - goto fail; + ret = intelfb_multi_fb_probe(dev); + } else { + ret = intelfb_single_fb_probe(dev); } - ret = intelfb_single_fb_probe(dev); - fail: /* TODO */ return ret; -- cgit v1.2.3 From 00bb548c6129ee712742d0e893aaa50fc65e49fc Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 15:38:53 +1000 Subject: intel: don't set the mode on the framebuffer if isn't set to scanout our framebuffer --- linux-core/intel_fb.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 85a173e1..856ec868 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -218,7 +218,6 @@ static int intelfb_set_par(struct fb_info *info) DRM_DEBUG("%d %d\n", var->xres, var->pixclock); - if (var->pixclock != -1) { DRM_ERROR("PIXEL CLCOK SET\n"); @@ -332,9 +331,11 @@ static int intelfb_set_par(struct fb_info *info) if (i == par->crtc_count) continue; - ret = crtc->funcs->set_config(&intel_crtc->mode_set); - if (ret) - return ret; + if (crtc->fb == intel_crtc->mode_set.fb) { + ret = crtc->funcs->set_config(&intel_crtc->mode_set); + if (ret) + return ret; + } } return 0; } @@ -984,8 +985,6 @@ int intelfb_probe(struct drm_device *dev) ret = intelfb_single_fb_probe(dev); } -fail: - /* TODO */ return ret; } EXPORT_SYMBOL(intelfb_probe); -- cgit v1.2.3 From 4a2e29bf9982165deeeabb5c585fc0a8a659f380 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Jun 2008 15:59:01 -0700 Subject: Use GEM in modesetting Use GEM for ring buffer setup and framebuffer allocation. This means reworking the hardware status page stuff a bit (just use the basic range allocator for vram for now) and #ifdef'ing out the TTM & DRI2 code. Works well enough to load/unload several times and display fbcon on my T61 (though there's still some unexplained console corruption). --- linux-core/intel_fb.c | 79 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 32 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 856ec868..d53b22ff 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -590,9 +590,10 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb; struct drm_mode_fb_cmd mode_cmd; - struct drm_buffer_object *fbo = NULL; + struct drm_gem_object *fbo = NULL; + struct drm_i915_gem_object *obj_priv; struct device *device = &dev->pdev->dev; - int ret; + int size, aligned_size, ret; mode_cmd.width = surface_width;/* crtc->desired_mode->hdisplay; */ mode_cmd.height = surface_height;/* crtc->desired_mode->vdisplay; */ @@ -601,26 +602,28 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8); mode_cmd.depth = 24; - ret = drm_buffer_object_create(dev, mode_cmd.pitch * mode_cmd.height, - drm_bo_type_kernel, - DRM_BO_FLAG_READ | - DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_TT | - DRM_BO_FLAG_MEM_VRAM | - DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, 0, 0, - &fbo); - if (ret || !fbo) { + size = mode_cmd.pitch * mode_cmd.height; + aligned_size = ALIGN(size, PAGE_SIZE); + fbo = drm_gem_object_alloc(dev, aligned_size); + if (!fbo) { printk(KERN_ERR "failed to allocate framebuffer\n"); - return -EINVAL; + ret = -ENOMEM; + goto out; + } + obj_priv = fbo->driver_private; + + mutex_lock(&dev->struct_mutex); + ret = i915_gem_object_pin(fbo, PAGE_SIZE); + if (ret) { + DRM_ERROR("failed to pin fb: %d\n", ret); + goto out_unref; } - fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd); if (!fb) { - drm_bo_usage_deref_unlocked(&fbo); DRM_ERROR("failed to allocate fb.\n"); - return -EINVAL; + ret = -ENOMEM; + goto out_unref; } list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); @@ -628,11 +631,13 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height intel_fb = to_intel_framebuffer(fb); *intel_fb_p = intel_fb; - intel_fb->bo = fbo; + intel_fb->obj = fbo; info = framebuffer_alloc(sizeof(struct intelfb_par), device); - if (!info) - return -EINVAL; + if (!info) { + ret = -ENOMEM; + goto out_unref; + } par = info->par; @@ -651,19 +656,20 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height info->fbops = &intelfb_ops; info->fix.line_length = fb->pitch; - info->fix.smem_start = intel_fb->bo->offset + dev->mode_config.fb_base; - info->fix.smem_len = info->fix.line_length * fb->height; + info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset; + info->fix.smem_len = size; info->flags = FBINFO_DEFAULT; - ret = drm_bo_kmap(intel_fb->bo, 0, intel_fb->bo->num_pages, &intel_fb->kmap); - if (ret) - DRM_ERROR("error mapping fb: %d\n", ret); - - info->screen_base = intel_fb->kmap.virtual; - info->screen_size = info->fix.smem_len; /* FIXME */ + info->screen_base = ioremap(dev->agp->base + obj_priv->gtt_offset, + size); + if (!info->screen_base) { + ret = -ENOSPC; + goto out_unref; + } + info->screen_size = size; - memset(intel_fb->kmap.virtual, 0, info->screen_size); + memset(info->screen_base, 0, size); info->pseudo_palette = fb->pseudo_palette; info->var.xres_virtual = fb->width; @@ -754,10 +760,17 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height par->dev = dev; /* To allow resizeing without swapping buffers */ - printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width, - intel_fb->base.height, intel_fb->bo->offset, fbo); + printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width, + intel_fb->base.height, obj_priv->gtt_offset, fbo); + mutex_unlock(&dev->struct_mutex); return 0; + +out_unref: + drm_gem_object_unreference(fbo); + mutex_unlock(&dev->struct_mutex); +out: + return ret; } static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc) @@ -1001,8 +1014,10 @@ int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) if (info) { unregister_framebuffer(info); - drm_bo_kunmap(&intel_fb->kmap); - drm_bo_usage_deref_unlocked(&intel_fb->bo); + iounmap(info->screen_base); + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(intel_fb->obj); + mutex_unlock(&dev->struct_mutex); framebuffer_release(info); } return 0; -- cgit v1.2.3 From 7010d500072977f63a0bac08f2141d69dbd19595 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 18 Jun 2008 13:57:39 -0700 Subject: i915: switch back to fbcon on panic Normally when X is running, panic messages will be invisible and the machine will just appear to hard hang. This patch adds support for switching back to the fbcon framebuffer on panic (through the use of a panic notifier registration) so we can see what happened. Note that in order to be really useful, X will have to run its VT in something other than KD_GRAPHICS mode. Also, not all kernel errors result in panics, some go through BUG() which may trigger another type of event, not resulting in a switch. --- linux-core/intel_fb.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 856ec868..64a8fc94 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -581,6 +581,22 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) } EXPORT_SYMBOL(intelfb_resize); +static struct drm_mode_set panic_mode; + +int intelfb_panic(struct notifier_block *n, unsigned long ununsed, + void *panic_str) +{ + DRM_ERROR("panic occurred, switching back to text console\n"); + drm_crtc_helper_set_config(&panic_mode); + + return 0; +} +EXPORT_SYMBOL(intelfb_panic); + +static struct notifier_block paniced = { + .notifier_call = intelfb_panic, +}; + int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height, uint32_t surface_width, uint32_t surface_height, struct intel_framebuffer **intel_fb_p) @@ -831,6 +847,12 @@ static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc * printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); + + /* Switch back to kernel console on panic */ + panic_mode = *modeset; + atomic_notifier_chain_register(&panic_notifier_list, &paniced); + printk(KERN_INFO "registered panic notifier\n"); + return 0; } @@ -952,6 +974,12 @@ static int intelfb_single_fb_probe(struct drm_device *dev) printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); + + /* Switch back to kernel console on panic */ + panic_mode = *modeset; + atomic_notifier_chain_register(&panic_notifier_list, &paniced); + printk(KERN_INFO "registered panic notifier\n"); + return 0; } @@ -1005,6 +1033,9 @@ int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) drm_bo_usage_deref_unlocked(&intel_fb->bo); framebuffer_release(info); } + + atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); + memset(&panic_mode, 0, sizeof(struct drm_mode_set)); return 0; } EXPORT_SYMBOL(intelfb_remove); -- cgit v1.2.3 From c843d47b906e57fb3002af4a609d3cb95c5e195d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 18 Jun 2008 14:51:46 -0700 Subject: i915: use WC mapping for framebuffer screen_base --- linux-core/intel_fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index b082080c..16788411 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -677,8 +677,8 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height info->flags = FBINFO_DEFAULT; - info->screen_base = ioremap(dev->agp->base + obj_priv->gtt_offset, - size); + info->screen_base = ioremap_wc(dev->agp->base + obj_priv->gtt_offset, + size); if (!info->screen_base) { ret = -ENOSPC; goto out_unref; -- cgit v1.2.3 From f58e21c7d056017340dc0ecac7e53dee2b33fe3b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 18 Jun 2008 16:49:51 -0700 Subject: i915: add blanking support to intelfb Got tired of not having my LCD actually turn off when I left the machine at the console. --- linux-core/intel_fb.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 16788411..0780aae7 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -525,6 +525,92 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, return ret; } +static void intelfb_on(struct fb_info *info) +{ + struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + int i; + + /* + * For each CRTC in this fb, find all associated encoders + * and turn them off, then turn off the CRTC. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + crtc_funcs->dpms(crtc, DPMSModeOn); + + /* Found a CRTC on this fb, now find encoders */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + struct drm_encoder_helper_funcs *encoder_funcs; + encoder_funcs = encoder->helper_private; + encoder_funcs->dpms(encoder, DPMSModeOn); + } + } + } +} + +static void intelfb_off(struct fb_info *info, int dpms_mode) +{ + struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + int i; + + /* + * For each CRTC in this fb, find all associated encoders + * and turn them off, then turn off the CRTC. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + /* Found a CRTC on this fb, now find encoders */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + struct drm_encoder_helper_funcs *encoder_funcs; + encoder_funcs = encoder->helper_private; + encoder_funcs->dpms(encoder, dpms_mode); + } + } + if (dpms_mode == DPMSModeOff) + crtc_funcs->dpms(crtc, dpms_mode); + } +} + +int intelfb_blank(int blank, struct fb_info *info) +{ + switch (blank) { + case FB_BLANK_UNBLANK: + intelfb_on(info); + break; + case FB_BLANK_NORMAL: + intelfb_off(info, DPMSModeStandby); + break; + case FB_BLANK_HSYNC_SUSPEND: + intelfb_off(info, DPMSModeStandby); + break; + case FB_BLANK_VSYNC_SUSPEND: + intelfb_off(info, DPMSModeSuspend); + break; + case FB_BLANK_POWERDOWN: + intelfb_off(info, DPMSModeOff); + break; + } + return 0; +} + static struct fb_ops intelfb_ops = { .owner = THIS_MODULE, //.fb_open = intelfb_open, @@ -539,6 +625,7 @@ static struct fb_ops intelfb_ops = { .fb_copyarea = cfb_copyarea, //intelfb_copyarea, .fb_imageblit = cfb_imageblit, //intelfb_imageblit, .fb_pan_display = intelfb_pan_display, + .fb_blank = intelfb_blank, }; /** -- cgit v1.2.3 From d55629a13d0f287e186e93a4828ef86b36678eba Mon Sep 17 00:00:00 2001 From: root Date: Tue, 24 Jun 2008 23:18:29 +0100 Subject: silence warning --- linux-core/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 64a8fc94..cbd22ba6 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -882,7 +882,7 @@ static int intelfb_single_fb_probe(struct drm_device *dev) struct intel_framebuffer *intel_fb; struct fb_info *info; struct intelfb_par *par; - struct drm_mode_set *modeset; + struct drm_mode_set *modeset = NULL; DRM_DEBUG("\n"); /* first up get a count of crtcs now in use and new min/maxes width/heights */ -- cgit v1.2.3 From e810cb9243fe6c4905182869d9e3272d861a14cb Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 6 Jul 2008 10:52:25 +0200 Subject: modesetting-101: rename modeflags, as to avoid conflicts with the xorg definitions --- linux-core/intel_fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index cbd22ba6..5637ea2f 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -263,8 +263,8 @@ static int intelfb_set_par(struct fb_info *info) 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->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; + drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; drm_mode_set_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); -- cgit v1.2.3 From df9871064e8b564d9ae2e56d561b64434fd004af Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 26 Jul 2008 08:56:23 +1000 Subject: radeon: add initial atombios modesetting and GEM -> TTM translation layer. This is an initial import of the atom bios parser with modesetting support for r500 hw using atombios. It also includes a simple memory manager layer that translates a radeon GEM style interface onto TTM internally. So far this memory manager has only been used for pinned object allocation for the DDX to test modesetting. --- linux-core/intel_fb.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index bc056bc3..ce8ac3d9 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -544,14 +544,14 @@ static void intelfb_on(struct fb_info *info) if (crtc->base.id == par->crtc_ids[i]) break; - crtc_funcs->dpms(crtc, DPMSModeOn); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); /* Found a CRTC on this fb, now find encoders */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { struct drm_encoder_helper_funcs *encoder_funcs; encoder_funcs = encoder->helper_private; - encoder_funcs->dpms(encoder, DPMSModeOn); + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); } } } @@ -584,7 +584,7 @@ static void intelfb_off(struct fb_info *info, int dpms_mode) encoder_funcs->dpms(encoder, dpms_mode); } } - if (dpms_mode == DPMSModeOff) + if (dpms_mode == DRM_MODE_DPMS_OFF) crtc_funcs->dpms(crtc, dpms_mode); } } @@ -596,16 +596,16 @@ int intelfb_blank(int blank, struct fb_info *info) intelfb_on(info); break; case FB_BLANK_NORMAL: - intelfb_off(info, DPMSModeStandby); + intelfb_off(info, DRM_MODE_DPMS_STANDBY); break; case FB_BLANK_HSYNC_SUSPEND: - intelfb_off(info, DPMSModeStandby); + intelfb_off(info, DRM_MODE_DPMS_STANDBY); break; case FB_BLANK_VSYNC_SUSPEND: - intelfb_off(info, DPMSModeSuspend); + intelfb_off(info, DRM_MODE_DPMS_SUSPEND); break; case FB_BLANK_POWERDOWN: - intelfb_off(info, DPMSModeOff); + intelfb_off(info, DRM_MODE_DPMS_OFF); break; } return 0; -- cgit v1.2.3 From 893315d49ed678de95cf6ac553efb6093cc7343c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 16 Aug 2008 11:35:10 -0700 Subject: i915: set domain properly on fb mapping, flush out changes The user visible ioctl does this, but since we call into GEM internals directly, we have to flush things ourselves. Fixes initial fb console corruption. --- linux-core/intel_fb.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index ce8ac3d9..c1391c0a 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -716,12 +716,18 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height obj_priv = fbo->driver_private; mutex_lock(&dev->struct_mutex); + /* Flush everything out, we'll be doing GTT only from now on */ + i915_gem_object_set_domain(fbo, I915_GEM_DOMAIN_GTT, + I915_GEM_DOMAIN_GTT); + ret = i915_gem_object_pin(fbo, PAGE_SIZE); if (ret) { DRM_ERROR("failed to pin fb: %d\n", ret); goto out_unref; } + i915_gem_clflush_object(fbo); + fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd); if (!fb) { DRM_ERROR("failed to allocate fb.\n"); -- cgit v1.2.3 From 840c9a305481ed59820bbd87fbcf78dd242d5702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 23 Sep 2008 16:52:06 +1000 Subject: Update intel modesetting to use mm_private instead of mm_handle. --- linux-core/intel_fb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'linux-core/intel_fb.c') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index c1391c0a..3d786ea3 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -728,7 +728,7 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height i915_gem_clflush_object(fbo); - fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd); + fb = intel_framebuffer_create(dev, &mode_cmd, fbo); if (!fb) { DRM_ERROR("failed to allocate fb.\n"); ret = -ENOMEM; @@ -740,8 +740,6 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height intel_fb = to_intel_framebuffer(fb); *intel_fb_p = intel_fb; - intel_fb->obj = fbo; - info = framebuffer_alloc(sizeof(struct intelfb_par), device); if (!info) { ret = -ENOMEM; @@ -1137,7 +1135,7 @@ int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) unregister_framebuffer(info); iounmap(info->screen_base); mutex_lock(&dev->struct_mutex); - drm_gem_object_unreference(intel_fb->obj); + drm_gem_object_unreference(intel_fb->base.mm_private); mutex_unlock(&dev->struct_mutex); framebuffer_release(info); } -- cgit v1.2.3