aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/ps3fb.c65
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
146struct ps3fb_res_table { 147struct 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
446out: 447out:
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)
561static int ps3fb_set_par(struct fb_info *info) 558static 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
647static 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)