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.
main
Jesse Barnes 2007-05-17 09:00:06 -07:00
parent b589b846e7
commit a18b4befb9
11 changed files with 400 additions and 19 deletions

View File

@ -14,14 +14,14 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
drm_memory_debug.o ati_pcigart.o drm_sman.o \
drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \
drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \
drm_edid.o drm_modes.o drm_fb.o
drm_edid.o drm_modes.o
tdfx-objs := tdfx_drv.o
r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o
mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
i810-objs := i810_drv.o i810_dma.o
i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \
i915_buffer.o intel_display.o intel_crt.o intel_lvds.o \
intel_sdvo.o intel_modes.o intel_i2c.o i915_init.o
intel_sdvo.o intel_modes.o intel_i2c.o i915_init.o intel_fb.o
nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
nouveau_object.o nouveau_irq.o \
nv04_timer.o \

View File

@ -661,6 +661,10 @@ struct drm_driver {
unsigned long (*get_reg_ofs) (struct drm_device * dev);
void (*set_version) (struct drm_device * dev, drm_set_version_t * sv);
/* FB routines, if present */
int (*fb_probe)(struct drm_device *dev, struct drm_framebuffer *fb);
int (*fb_remove)(struct drm_device *dev, struct drm_framebuffer *fb);
struct drm_fence_driver *fence_driver;
struct drm_bo_driver *bo_driver;

View File

@ -910,10 +910,8 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow)
/* FB config is max of above desired resolutions */
/* FIXME: per-output FBs/CRTCs */
if (des_mode->hdisplay > fb->width) {
if (des_mode->hdisplay > fb->width)
fb->width = des_mode->hdisplay;
fb->pitch = fb->width;
}
if (des_mode->vdisplay > fb->height)
fb->height = des_mode->vdisplay;
}
@ -921,6 +919,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow)
/* FIXME: multiple depths */
bytes_per_pixel = 4;
fb->bits_per_pixel = bytes_per_pixel * 8;
fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8);
fb->depth = bytes_per_pixel * 8;
size = fb->width * fb->height * bytes_per_pixel;
drm_buffer_object_create(dev, size, drm_bo_type_kernel,
@ -932,7 +931,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow)
fb->height, fbo->offset, fbo);
fb->offset = fbo->offset;
fb->bo = fbo;
drmfb_probe(dev, fb);
dev->driver->fb_probe(dev, fb);
return false;
}
@ -964,7 +963,7 @@ void drm_mode_config_cleanup(drm_device_t *dev)
}
list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
drmfb_remove(dev, fb);
dev->driver->fb_remove(dev, fb);
/* If this FB was the kernel one, free it */
if (fb->bo->type == drm_bo_type_kernel) {
mutex_lock(&dev->struct_mutex);
@ -1528,7 +1527,7 @@ int drm_mode_addfb(struct inode *inode, struct file *filp,
if (copy_to_user(argp, &r, sizeof(r)))
return -EFAULT;
drmfb_probe(dev, fb);
dev->driver->fb_probe(dev, fb);
return 0;
}
@ -1564,7 +1563,7 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp,
return -EINVAL;
}
drmfb_remove(dev, fb);
dev->driver->fb_remove(dev, fb);
/* TODO check if we own the buffer */
/* TODO release all crtc connected to the framebuffer */
/* bind the fb to the crtc for now */
@ -1645,7 +1644,7 @@ void drm_fb_release(struct file *filp)
list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
list_del(&fb->filp_head);
drmfb_remove(dev, fb);
dev->driver->fb_remove(dev, fb);
drm_framebuffer_destroy(fb);
}

View File

@ -106,8 +106,6 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
struct fb_info *info;
struct drmfb_par *par;
struct device *device = &dev->pdev->dev;
struct fb_var_screeninfo *var_info;
unsigned long base, size;
int ret;
info = framebuffer_alloc(sizeof(struct drmfb_par), device);
@ -126,7 +124,7 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
strcpy(info->fix.id, "drmfb");
info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
info->fix.smem_len = (8*1024*1024);
info->fix.smem_len = fb->bo->mem.size;
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_DIRECTCOLOR;
info->fix.accel = FB_ACCEL_NONE;
@ -142,7 +140,7 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
DRM_ERROR("error mapping fb: %d\n", ret);
info->screen_base = fb->virtual_base;
info->screen_size = size;
info->screen_size = fb->bo->mem.size;
info->pseudo_palette = fb->pseudo_palette;
info->var.xres = fb->width;
info->var.xres_virtual = fb->pitch;

View File

@ -30,6 +30,7 @@
#include "drmP.h"
#include "drm.h"
#include "i915_drm.h"
#include "intel_drv.h"
#include "i915_drv.h"
#include "drm_pciids.h"
@ -92,6 +93,8 @@ static struct drm_driver driver = {
.reclaim_buffers = drm_core_reclaim_buffers,
.get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs,
.fb_probe = intelfb_probe,
.fb_remove = intelfb_remove,
.ioctls = i915_ioctls,
.fops = {
.owner = THIS_MODULE,

View File

@ -370,7 +370,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
Start = crtc->fb->offset;
Offset = ((y * crtc->fb->pitch + x) * (crtc->fb->bits_per_pixel / 8));
Offset = y * crtc->fb->pitch + x;
DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y);
if (IS_I965G(dev)) {
@ -911,7 +911,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
((adjusted_mode->crtc_vblank_end - 1) << 16));
I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
((adjusted_mode->crtc_vsync_end - 1) << 16));
I915_WRITE(dspstride_reg, crtc->fb->pitch * (crtc->fb->bits_per_pixel / 8));
I915_WRITE(dspstride_reg, crtc->fb->pitch);
/* pipesrc and dspsize control the size that is scaled from, which should
* always be the user's requested size.
*/

View File

@ -76,4 +76,7 @@ extern struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev,
extern void intel_wait_for_vblank(drm_device_t *dev);
extern struct drm_crtc *intel_get_crtc_from_pipe(drm_device_t *dev, int pipe);
extern int intelfb_probe(struct drm_device *dev, struct drm_framebuffer *fb);
extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
#endif /* __INTEL_DRV_H__ */

358
linux-core/intel_fb.c Normal file
View File

@ -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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include "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");

View File

@ -130,7 +130,7 @@ static int i915_dma_resume(drm_device_t * dev)
DRM_DEBUG("%s\n", __FUNCTION__);
I915_WRITE(0x02080, dev_priv->dma_status_page);
I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page);
DRM_DEBUG("Enabled hardware status page\n");
return 0;

View File

@ -317,6 +317,8 @@ extern void intel_modeset_cleanup(drm_device_t *dev);
I915_WRITE(LP_RING + RING_TAIL, outring); \
} while(0)
#define MI_NOOP (0x00 << 23)
extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
/*
@ -356,6 +358,7 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define BB1_UNPROTECTED (0<<0)
#define BB2_END_ADDR_MASK (~0x7)
#define I915REG_HWS_PGA 0x02080
#define I915REG_HWSTAM 0x02098
#define I915REG_INT_IDENTITY_R 0x020a4
#define I915REG_INT_MASK_R 0x020a8
@ -460,8 +463,14 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|4)
#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
#define XY_MONO_SRC_COPY_IMM_BLT ((2<<29)|(0x71<<22)|5)
#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
#define BLT_DEPTH_8 (0<<24)
#define BLT_DEPTH_16_565 (1<<24)
#define BLT_DEPTH_16_1555 (2<<24)
#define BLT_DEPTH_32 (3<<24)
#define BLT_ROP_GXCOPY (0xcc<<16)
#define MI_BATCH_BUFFER ((0x30<<23)|1)
#define MI_BATCH_BUFFER_START (0x31<<23)

View File

@ -211,6 +211,13 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags)
dev_priv->sarea_priv->pf_current_page = 0;
memset((void *)(dev_priv->ring.virtual_start), 0, dev_priv->ring.Size);
I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start);
I915_WRITE(LP_RING + RING_LEN,
((dev_priv->ring.Size - 4096) & RING_NR_PAGES) |
(RING_NO_REPORT | RING_VALID));
/* We are using separate values as placeholders for mechanisms for
* private backbuffer/depthbuffer usage.
*/
@ -236,7 +243,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags)
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
I915_WRITE(0x02080, dev_priv->dma_status_page);
I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page);
DRM_DEBUG("Enabled hardware status page\n");
intel_modeset_init(dev);
@ -255,7 +262,7 @@ int i915_driver_unload(drm_device_t *dev)
dev_priv->hw_status_page = NULL;
dev_priv->dma_status_page = 0;
/* Need to rewrite hardware status page */
I915_WRITE(0x02080, 0x1ffff000);
I915_WRITE(I915REG_HWS_PGA, 0x1ffff000);
}
I915_WRITE(LP_RING + RING_LEN, 0);