diff options
author | Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com> | 2007-10-16 04:29:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:22 -0400 |
commit | fc7028b7487cc57ef44c7efc5e286f06bef8fc13 (patch) | |
tree | 09a9430862d615363e6e2856d1c1454570e8327d /drivers/video | |
parent | f1664ed8ae98d17b294e01a5a0220f635f207824 (diff) |
ps3fb: add virtual screen and panning support
ps3fb: Add virtual screen and panning support:
- The vertical virtual screen size is limited by the amount of memory
reserved for ps3fb,
- The horizontal virtual screen size is limited to the fullscreen width,
- Advertise that we support panning, so fbcon will use it if the virtual
screen is enabled.
Enabling a virtual screen (using `fbset -vyres nnn') can speed up text
console scrolling by a factor of 10-15, depending on the video mode.
Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/ps3fb.c | 65 |
1 files changed, 40 insertions, 25 deletions
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 88e15d4b5684..64af173d18f9 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c | |||
@@ -141,6 +141,7 @@ struct ps3fb_par { | |||
141 | unsigned int height; | 141 | unsigned int height; |
142 | unsigned long full_offset; /* start of fullscreen DDR fb */ | 142 | unsigned long full_offset; /* start of fullscreen DDR fb */ |
143 | unsigned long fb_offset; /* start of actual DDR fb */ | 143 | unsigned long fb_offset; /* start of actual DDR fb */ |
144 | unsigned long pan_offset; | ||
144 | }; | 145 | }; |
145 | 146 | ||
146 | struct ps3fb_res_table { | 147 | struct ps3fb_res_table { |
@@ -440,8 +441,8 @@ static int ps3fb_sync(struct fb_info *info, u32 frame) | |||
440 | base = frame * yres * line_length; | 441 | base = frame * yres * line_length; |
441 | 442 | ||
442 | ps3fb_sync_image(info->device, base + par->full_offset, | 443 | ps3fb_sync_image(info->device, base + par->full_offset, |
443 | base + par->fb_offset, base, par->width, par->height, | 444 | base + par->fb_offset, base + par->pan_offset, |
444 | line_length); | 445 | par->width, par->height, line_length); |
445 | 446 | ||
446 | out: | 447 | out: |
447 | release_console_sem(); | 448 | release_console_sem(); |
@@ -488,27 +489,23 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
488 | if (!mode) | 489 | if (!mode) |
489 | return -EINVAL; | 490 | return -EINVAL; |
490 | 491 | ||
491 | /* | 492 | /* Virtual screen */ |
492 | * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! | 493 | if (var->xres_virtual < var->xres) |
493 | * as FB_VMODE_SMOOTH_XPAN is only used internally | 494 | var->xres_virtual = var->xres; |
494 | */ | 495 | if (var->yres_virtual < var->yres) |
496 | var->yres_virtual = var->yres; | ||
495 | 497 | ||
496 | if (var->vmode & FB_VMODE_CONUPDATE) { | 498 | if (var->xres_virtual > line_length / BPP) { |
497 | var->vmode |= FB_VMODE_YWRAP; | ||
498 | var->xoffset = info->var.xoffset; | ||
499 | var->yoffset = info->var.yoffset; | ||
500 | } | ||
501 | |||
502 | /* Virtual screen and panning are not supported */ | ||
503 | if (var->xres_virtual > var->xres || var->yres_virtual > var->yres || | ||
504 | var->xoffset || var->yoffset) { | ||
505 | dev_dbg(info->device, | 499 | dev_dbg(info->device, |
506 | "Virtual screen and panning are not supported\n"); | 500 | "Horizontal virtual screen size too large\n"); |
507 | return -EINVAL; | 501 | return -EINVAL; |
508 | } | 502 | } |
509 | 503 | ||
510 | var->xres_virtual = var->xres; | 504 | if (var->xoffset + var->xres > var->xres_virtual || |
511 | var->yres_virtual = var->yres; | 505 | var->yoffset + var->yres > var->yres_virtual) { |
506 | dev_dbg(info->device, "panning out-of-range\n"); | ||
507 | return -EINVAL; | ||
508 | } | ||
512 | 509 | ||
513 | /* We support ARGB8888 only */ | 510 | /* We support ARGB8888 only */ |
514 | if (var->bits_per_pixel > 32 || var->grayscale || | 511 | if (var->bits_per_pixel > 32 || var->grayscale || |
@@ -543,7 +540,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
543 | } | 540 | } |
544 | 541 | ||
545 | /* Memory limit */ | 542 | /* Memory limit */ |
546 | if (var->yres * line_length > ps3fb.xdr_size) { | 543 | if (var->yres_virtual * line_length > ps3fb.xdr_size) { |
547 | dev_dbg(info->device, "Not enough memory\n"); | 544 | dev_dbg(info->device, "Not enough memory\n"); |
548 | return -ENOMEM; | 545 | return -ENOMEM; |
549 | } | 546 | } |
@@ -561,7 +558,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
561 | static int ps3fb_set_par(struct fb_info *info) | 558 | static int ps3fb_set_par(struct fb_info *info) |
562 | { | 559 | { |
563 | struct ps3fb_par *par = info->par; | 560 | struct ps3fb_par *par = info->par; |
564 | unsigned int mode, lines, maxlines; | 561 | unsigned int mode, line_length, lines, maxlines; |
565 | int i; | 562 | int i; |
566 | unsigned long offset, dst; | 563 | unsigned long offset, dst; |
567 | 564 | ||
@@ -569,7 +566,7 @@ static int ps3fb_set_par(struct fb_info *info) | |||
569 | info->var.xres, info->var.xres_virtual, | 566 | info->var.xres, info->var.xres_virtual, |
570 | info->var.yres, info->var.yres_virtual, info->var.pixclock); | 567 | info->var.yres, info->var.yres_virtual, info->var.pixclock); |
571 | 568 | ||
572 | mode = ps3fb_find_mode(&info->var, &info->fix.line_length); | 569 | mode = ps3fb_find_mode(&info->var, &line_length); |
573 | if (!mode) | 570 | if (!mode) |
574 | return -EINVAL; | 571 | return -EINVAL; |
575 | 572 | ||
@@ -578,6 +575,10 @@ static int ps3fb_set_par(struct fb_info *info) | |||
578 | 575 | ||
579 | info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); | 576 | info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); |
580 | info->fix.smem_len = ps3fb.xdr_size; | 577 | info->fix.smem_len = ps3fb.xdr_size; |
578 | info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0; | ||
579 | info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0; | ||
580 | info->fix.line_length = line_length; | ||
581 | |||
581 | info->screen_base = (char __iomem *)ps3fb.xdr_ea; | 582 | info->screen_base = (char __iomem *)ps3fb.xdr_ea; |
582 | 583 | ||
583 | par->num_frames = info->fix.smem_len/ | 584 | par->num_frames = info->fix.smem_len/ |
@@ -591,6 +592,8 @@ static int ps3fb_set_par(struct fb_info *info) | |||
591 | offset = VP_OFF(i); | 592 | offset = VP_OFF(i); |
592 | par->fb_offset = GPU_ALIGN_UP(offset); | 593 | par->fb_offset = GPU_ALIGN_UP(offset); |
593 | par->full_offset = par->fb_offset - offset; | 594 | par->full_offset = par->fb_offset - offset; |
595 | par->pan_offset = info->var.yoffset * line_length + | ||
596 | info->var.xoffset * BPP; | ||
594 | 597 | ||
595 | if (par->new_mode_id != par->mode_id) { | 598 | if (par->new_mode_id != par->mode_id) { |
596 | if (ps3av_set_video_mode(par->new_mode_id)) { | 599 | if (ps3av_set_video_mode(par->new_mode_id)) { |
@@ -607,11 +610,11 @@ static int ps3fb_set_par(struct fb_info *info) | |||
607 | lines = ps3fb_res[i].yres * par->num_frames; | 610 | lines = ps3fb_res[i].yres * par->num_frames; |
608 | if (par->full_offset) | 611 | if (par->full_offset) |
609 | lines++; | 612 | lines++; |
610 | maxlines = ps3fb.xdr_size / info->fix.line_length; | 613 | maxlines = ps3fb.xdr_size / line_length; |
611 | for (dst = 0; lines; dst += maxlines * info->fix.line_length) { | 614 | for (dst = 0; lines; dst += maxlines * line_length) { |
612 | unsigned int l = min(lines, maxlines); | 615 | unsigned int l = min(lines, maxlines); |
613 | ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l, | 616 | ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l, |
614 | info->fix.line_length); | 617 | line_length); |
615 | lines -= l; | 618 | lines -= l; |
616 | } | 619 | } |
617 | 620 | ||
@@ -641,6 +644,16 @@ static int ps3fb_setcolreg(unsigned int regno, unsigned int red, | |||
641 | return 0; | 644 | return 0; |
642 | } | 645 | } |
643 | 646 | ||
647 | static int ps3fb_pan_display(struct fb_var_screeninfo *var, | ||
648 | struct fb_info *info) | ||
649 | { | ||
650 | struct ps3fb_par *par = info->par; | ||
651 | |||
652 | par->pan_offset = var->yoffset * info->fix.line_length + | ||
653 | var->xoffset * BPP; | ||
654 | return 0; | ||
655 | } | ||
656 | |||
644 | /* | 657 | /* |
645 | * As we have a virtual frame buffer, we need our own mmap function | 658 | * As we have a virtual frame buffer, we need our own mmap function |
646 | */ | 659 | */ |
@@ -965,6 +978,7 @@ static struct fb_ops ps3fb_ops = { | |||
965 | .fb_check_var = ps3fb_check_var, | 978 | .fb_check_var = ps3fb_check_var, |
966 | .fb_set_par = ps3fb_set_par, | 979 | .fb_set_par = ps3fb_set_par, |
967 | .fb_setcolreg = ps3fb_setcolreg, | 980 | .fb_setcolreg = ps3fb_setcolreg, |
981 | .fb_pan_display = ps3fb_pan_display, | ||
968 | .fb_fillrect = sys_fillrect, | 982 | .fb_fillrect = sys_fillrect, |
969 | .fb_copyarea = sys_copyarea, | 983 | .fb_copyarea = sys_copyarea, |
970 | .fb_imageblit = sys_imageblit, | 984 | .fb_imageblit = sys_imageblit, |
@@ -1115,7 +1129,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | |||
1115 | info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); | 1129 | info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); |
1116 | info->fix.smem_len = ps3fb.xdr_size; | 1130 | info->fix.smem_len = ps3fb.xdr_size; |
1117 | info->pseudo_palette = par->pseudo_palette; | 1131 | info->pseudo_palette = par->pseudo_palette; |
1118 | info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST; | 1132 | info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST | |
1133 | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; | ||
1119 | 1134 | ||
1120 | retval = fb_alloc_cmap(&info->cmap, 256, 0); | 1135 | retval = fb_alloc_cmap(&info->cmap, 256, 0); |
1121 | if (retval < 0) | 1136 | if (retval < 0) |