diff options
| -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) |
