2 * Copyright © 2007 David Airlie
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
30 #include <linux/module.h>
31 #include <linux/kernel.h>
32 #include <linux/errno.h>
33 #include <linux/string.h>
35 #include <linux/tty.h>
36 #include <linux/slab.h>
37 #include <linux/delay.h>
39 #include <linux/init.h>
48 struct drm_device *dev;
49 struct drm_crtc *crtc;
52 static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
53 unsigned blue, unsigned transp,
56 struct intelfb_par *par = info->par;
57 struct drm_framebuffer *fb = par->crtc->fb;
58 struct drm_crtc *crtc = par->crtc;
64 if (crtc->funcs->gamma_set)
65 crtc->funcs->gamma_set(crtc, red, green, blue, regno);
72 fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
73 ((green & 0xf800) >> 6) |
74 ((blue & 0xf800) >> 11);
77 fb->pseudo_palette[regno] = (red & 0xf800) |
78 ((green & 0xfc00) >> 5) |
79 ((blue & 0xf800) >> 11);
83 fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
85 ((blue & 0xff00) >> 8);
93 static int intelfb_check_var(struct fb_var_screeninfo *var,
96 struct intelfb_par *par = info->par;
97 struct drm_device *dev = par->dev;
98 struct drm_framebuffer *fb = par->crtc->fb;
99 struct drm_display_mode *drm_mode;
100 struct drm_output *output;
106 /* Need to resize the fb object !!! */
107 if (var->xres > fb->width || var->yres > fb->height) {
108 DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height);
109 DRM_ERROR("Need resizing code.\n");
113 switch (var->bits_per_pixel) {
115 depth = (var->green.length == 6) ? 16 : 15;
118 depth = (var->transp.length > 0) ? 32 : 24;
121 depth = var->bits_per_pixel;
128 var->green.offset = 0;
129 var->blue.offset = 0;
131 var->green.length = 8;
132 var->blue.length = 8;
133 var->transp.length = 0;
134 var->transp.offset = 0;
137 var->red.offset = 10;
138 var->green.offset = 5;
139 var->blue.offset = 0;
141 var->green.length = 5;
142 var->blue.length = 5;
143 var->transp.length = 1;
144 var->transp.offset = 15;
147 var->red.offset = 11;
148 var->green.offset = 6;
149 var->blue.offset = 0;
151 var->green.length = 6;
152 var->blue.length = 5;
153 var->transp.length = 0;
154 var->transp.offset = 0;
157 var->red.offset = 16;
158 var->green.offset = 8;
159 var->blue.offset = 0;
161 var->green.length = 8;
162 var->blue.length = 8;
163 var->transp.length = 0;
164 var->transp.offset = 0;
167 var->red.offset = 16;
168 var->green.offset = 8;
169 var->blue.offset = 0;
171 var->green.length = 8;
172 var->blue.length = 8;
173 var->transp.length = 8;
174 var->transp.offset = 24;
181 /* Here we walk the output mode list and look for modes. If we haven't
182 * got it, then bail. Not very nice, so this is disabled.
183 * In the set_par code, we create our mode based on the incoming
184 * parameters. Nicer, but may not be desired by some.
186 list_for_each_entry(output, &dev->mode_config.output_list, head) {
187 if (output->crtc == par->crtc)
191 list_for_each_entry(drm_mode, &output->modes, head) {
192 if (drm_mode->hdisplay == var->xres &&
193 drm_mode->vdisplay == var->yres &&
194 drm_mode->clock != 0)
205 /* this will let fbcon do the mode init */
206 /* FIXME: take mode config lock? */
207 static int intelfb_set_par(struct fb_info *info)
209 struct intelfb_par *par = info->par;
210 struct drm_framebuffer *fb = par->crtc->fb;
211 struct drm_device *dev = par->dev;
212 struct drm_display_mode *drm_mode;
213 struct fb_var_screeninfo *var = &info->var;
215 switch (var->bits_per_pixel) {
217 fb->depth = (var->green.length == 6) ? 16 : 15;
220 fb->depth = (var->transp.length > 0) ? 32 : 24;
223 fb->depth = var->bits_per_pixel;
227 fb->bits_per_pixel = var->bits_per_pixel;
229 info->fix.line_length = fb->pitch;
230 info->fix.smem_len = info->fix.line_length * fb->height;
231 info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
233 info->screen_size = info->fix.smem_len; /* ??? */
235 /* Should we walk the output's modelist or just create our own ???
236 * For now, we create and destroy a mode based on the incoming
237 * parameters. But there's commented out code below which scans
238 * the output list too.
241 list_for_each_entry(output, &dev->mode_config.output_list, head) {
242 if (output->crtc == par->crtc)
246 list_for_each_entry(drm_mode, &output->modes, head) {
247 if (drm_mode->hdisplay == var->xres &&
248 drm_mode->vdisplay == var->yres &&
249 drm_mode->clock != 0)
253 drm_mode = drm_mode_create(dev);
254 drm_mode->hdisplay = var->xres;
255 drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
256 drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
257 drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
258 drm_mode->vdisplay = var->yres;
259 drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
260 drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
261 drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
262 drm_mode->clock = PICOS2KHZ(var->pixclock);
263 drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
264 drm_mode_set_name(drm_mode);
265 drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V);
268 if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0))
271 /* Have to destroy our created mode if we're not searching the mode
275 drm_mode_destroy(dev, drm_mode);
282 static void intelfb_copyarea(struct fb_info *info,
283 const struct fb_copyarea *region)
285 struct intelfb_par *par = info->par;
286 struct drm_device *dev = par->dev;
287 struct drm_i915_private *dev_priv = dev->dev_private;
288 u32 src_x1, src_y1, dst_x1, dst_y1, dst_x2, dst_y2, offset;
289 u32 cmd, rop_depth_pitch, src_pitch;
292 cmd = XY_SRC_COPY_BLT_CMD;
297 dst_x2 = region->dx + region->width;
298 dst_y2 = region->dy + region->height;
299 offset = par->fb->offset;
300 rop_depth_pitch = BLT_ROP_GXCOPY | par->fb->pitch;
301 src_pitch = par->fb->pitch;
303 switch (par->fb->bits_per_pixel) {
305 rop_depth_pitch |= BLT_DEPTH_16_565;
308 rop_depth_pitch |= BLT_DEPTH_32;
309 cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
315 OUT_RING(rop_depth_pitch);
316 OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff));
317 OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff));
319 OUT_RING((src_y1 << 16) | (src_x1 & 0xffff));
325 #define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y))
326 #define ROUND_DOWN_TO(x, y) ((x) / (y) * (y))
328 void intelfb_imageblit(struct fb_info *info, const struct fb_image *image)
330 struct intelfb_par *par = info->par;
331 struct drm_device *dev = par->dev;
332 struct drm_i915_private *dev_priv = dev->dev_private;
333 u32 cmd, rop_pitch_depth, tmp;
334 int nbytes, ndwords, pad;
335 u32 dst_x1, dst_y1, dst_x2, dst_y2, offset, bg, fg;
340 /* size in bytes of a padded scanline */
341 nbytes = ROUND_UP_TO(image->width, 16) / 8;
343 /* Total bytes of padded scanline data to write out. */
344 nbytes *= image->height;
347 * Check if the glyph data exceeds the immediate mode limit.
348 * It would take a large font (1K pixels) to hit this limit.
350 if (nbytes > 128 || image->depth != 1)
351 return cfb_imageblit(info, image);
353 /* Src data is packaged a dword (32-bit) at a time. */
354 ndwords = ROUND_UP_TO(nbytes, 4) / 4;
357 * Ring has to be padded to a quad word. But because the command starts
358 with 7 bytes, pad only if there is an even number of ndwords
360 pad = !(ndwords % 2);
362 DRM_DEBUG("imageblit %dx%dx%d to (%d,%d)\n", image->width,
363 image->height, image->depth, image->dx, image->dy);
364 DRM_DEBUG("nbytes: %d, ndwords: %d, pad: %d\n", nbytes, ndwords, pad);
366 tmp = (XY_MONO_SRC_COPY_IMM_BLT & 0xff) + ndwords;
367 cmd = (XY_MONO_SRC_COPY_IMM_BLT & ~0xff) | tmp;
368 offset = par->fb->offset;
371 dst_x2 = image->dx + image->width;
372 dst_y2 = image->dy + image->height;
373 rop_pitch_depth = BLT_ROP_GXCOPY | par->fb->pitch;
375 switch (par->fb->bits_per_pixel) {
377 rop_pitch_depth |= BLT_DEPTH_8;
378 fg = image->fg_color;
379 bg = image->bg_color;
382 rop_pitch_depth |= BLT_DEPTH_16_565;
383 fg = par->fb->pseudo_palette[image->fg_color];
384 bg = par->fb->pseudo_palette[image->bg_color];
387 rop_pitch_depth |= BLT_DEPTH_32;
388 cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
389 fg = par->fb->pseudo_palette[image->fg_color];
390 bg = par->fb->pseudo_palette[image->bg_color];
393 DRM_ERROR("unknown depth %d\n", par->fb->bits_per_pixel);
397 BEGIN_LP_RING(8 + ndwords);
399 OUT_RING(rop_pitch_depth);
400 OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff));
401 OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff));
406 iw = ROUND_UP_TO(image->width, 8) / 8;
409 for (j = 0; j < 2; ++j) {
410 for (i = 0; i < 2; ++i) {
411 if (ix != iw || i == 0)
412 dat |= image->data[iy*iw + ix++] << (i+j*2)*8;
414 if (ix == iw && iy != (image->height - 1)) {
427 static struct fb_ops intelfb_ops = {
428 .owner = THIS_MODULE,
429 // .fb_open = intelfb_open,
430 // .fb_read = intelfb_read,
431 // .fb_write = intelfb_write,
432 // .fb_release = intelfb_release,
433 // .fb_ioctl = intelfb_ioctl,
434 .fb_check_var = intelfb_check_var,
435 .fb_set_par = intelfb_set_par,
436 .fb_setcolreg = intelfb_setcolreg,
437 .fb_fillrect = cfb_fillrect,
438 .fb_copyarea = cfb_copyarea, //intelfb_copyarea,
439 .fb_imageblit = cfb_imageblit, //intelfb_imageblit,
442 int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
444 struct fb_info *info;
445 struct intelfb_par *par;
446 struct device *device = &dev->pdev->dev;
447 struct drm_framebuffer *fb;
448 struct drm_display_mode *mode = crtc->desired_mode;
449 struct drm_buffer_object *fbo = NULL;
452 info = framebuffer_alloc(sizeof(struct intelfb_par), device);
457 fb = drm_framebuffer_create(dev);
459 framebuffer_release(info);
460 DRM_ERROR("failed to allocate fb.\n");
465 fb->width = crtc->desired_mode->hdisplay;
466 fb->height = crtc->desired_mode->vdisplay;
468 fb->bits_per_pixel = 32;
469 fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8);
471 ret = drm_buffer_object_create(dev, fb->width * fb->height * 4,
475 DRM_BO_FLAG_MEM_VRAM,
479 printk(KERN_ERR "failed to allocate framebuffer\n");
480 drm_framebuffer_destroy(fb);
481 framebuffer_release(info);
485 ret = drm_bo_set_pin(dev, fbo, 1);
487 printk(KERN_ERR "failed to pin framebuffer, aborting\n");
488 drm_framebuffer_destroy(fb);
489 framebuffer_release(info);
493 fb->offset = fbo->offset;
495 printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width,
496 fb->height, fbo->offset, fbo);
506 info->fbops = &intelfb_ops;
508 strcpy(info->fix.id, "intelfb");
509 info->fix.type = FB_TYPE_PACKED_PIXELS;
510 info->fix.visual = FB_VISUAL_TRUECOLOR;
511 info->fix.type_aux = 0;
512 info->fix.xpanstep = 8;
513 info->fix.ypanstep = 1;
514 info->fix.ywrapstep = 0;
515 info->fix.accel = FB_ACCEL_I830;
516 info->fix.type_aux = 0;
517 info->fix.mmio_start = 0;
518 info->fix.mmio_len = 0;
519 info->fix.line_length = fb->pitch;
520 info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
521 info->fix.smem_len = info->fix.line_length * fb->height;
523 info->flags = FBINFO_DEFAULT;
525 ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base);
527 DRM_ERROR("error mapping fb: %d\n", ret);
529 info->screen_base = fb->virtual_base;
530 info->screen_size = info->fix.smem_len; /* FIXME */
531 info->pseudo_palette = fb->pseudo_palette;
532 info->var.xres_virtual = fb->width;
533 info->var.yres_virtual = fb->height;
534 info->var.bits_per_pixel = fb->bits_per_pixel;
535 info->var.xoffset = 0;
536 info->var.yoffset = 0;
537 info->var.activate = FB_ACTIVATE_NOW;
538 info->var.height = -1;
539 info->var.width = -1;
540 info->var.vmode = FB_VMODE_NONINTERLACED;
542 info->var.xres = mode->hdisplay;
543 info->var.right_margin = mode->hsync_start - mode->hdisplay;
544 info->var.hsync_len = mode->hsync_end - mode->hsync_start;
545 info->var.left_margin = mode->htotal - mode->hsync_end;
546 info->var.yres = mode->vdisplay;
547 info->var.lower_margin = mode->vsync_start - mode->vdisplay;
548 info->var.vsync_len = mode->vsync_end - mode->vsync_start;
549 info->var.upper_margin = mode->vtotal - mode->vsync_end;
550 info->var.pixclock = 10000000 / mode->htotal * 1000 /
553 info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
555 info->pixmap.size = 64*1024;
556 info->pixmap.buf_align = 8;
557 info->pixmap.access_align = 32;
558 info->pixmap.flags = FB_PIXMAP_SYSTEM;
559 info->pixmap.scan_align = 1;
561 DRM_DEBUG("fb depth is %d\n", fb->depth);
562 DRM_DEBUG(" pitch is %d\n", fb->pitch);
565 info->var.red.offset = 0;
566 info->var.green.offset = 0;
567 info->var.blue.offset = 0;
568 info->var.red.length = 8; /* 8bit DAC */
569 info->var.green.length = 8;
570 info->var.blue.length = 8;
571 info->var.transp.offset = 0;
572 info->var.transp.length = 0;
575 info->var.red.offset = 10;
576 info->var.green.offset = 5;
577 info->var.blue.offset = 0;
578 info->var.red.length = info->var.green.length =
579 info->var.blue.length = 5;
580 info->var.transp.offset = 15;
581 info->var.transp.length = 1;
584 info->var.red.offset = 11;
585 info->var.green.offset = 5;
586 info->var.blue.offset = 0;
587 info->var.red.length = 5;
588 info->var.green.length = 6;
589 info->var.blue.length = 5;
590 info->var.transp.offset = 0;
593 info->var.red.offset = 16;
594 info->var.green.offset = 8;
595 info->var.blue.offset = 0;
596 info->var.red.length = info->var.green.length =
597 info->var.blue.length = 8;
598 info->var.transp.offset = 0;
599 info->var.transp.length = 0;
602 info->var.red.offset = 16;
603 info->var.green.offset = 8;
604 info->var.blue.offset = 0;
605 info->var.red.length = info->var.green.length =
606 info->var.blue.length = 8;
607 info->var.transp.offset = 24;
608 info->var.transp.length = 8;
614 if (register_framebuffer(info) < 0)
617 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
621 EXPORT_SYMBOL(intelfb_probe);
623 int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc)
625 struct drm_framebuffer *fb = crtc->fb;
626 struct fb_info *info = fb->fbdev;
629 unregister_framebuffer(info);
630 framebuffer_release(info);
631 drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base);
635 EXPORT_SYMBOL(intelfb_remove);
636 MODULE_LICENSE("GPL");