|
@@ -141,6 +141,7 @@ struct ps3fb_par {
|
|
unsigned int height;
|
|
unsigned int height;
|
|
unsigned long full_offset; /* start of fullscreen DDR fb */
|
|
unsigned long full_offset; /* start of fullscreen DDR fb */
|
|
unsigned long fb_offset; /* start of actual DDR fb */
|
|
unsigned long fb_offset; /* start of actual DDR fb */
|
|
|
|
+ unsigned long pan_offset;
|
|
};
|
|
};
|
|
|
|
|
|
struct ps3fb_res_table {
|
|
struct ps3fb_res_table {
|
|
@@ -440,8 +441,8 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
|
|
base = frame * yres * line_length;
|
|
base = frame * yres * line_length;
|
|
|
|
|
|
ps3fb_sync_image(info->device, base + par->full_offset,
|
|
ps3fb_sync_image(info->device, base + par->full_offset,
|
|
- base + par->fb_offset, base, par->width, par->height,
|
|
|
|
- line_length);
|
|
|
|
|
|
+ base + par->fb_offset, base + par->pan_offset,
|
|
|
|
+ par->width, par->height, line_length);
|
|
|
|
|
|
out:
|
|
out:
|
|
release_console_sem();
|
|
release_console_sem();
|
|
@@ -488,27 +489,23 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
|
|
if (!mode)
|
|
if (!mode)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- /*
|
|
|
|
- * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
|
|
|
|
- * as FB_VMODE_SMOOTH_XPAN is only used internally
|
|
|
|
- */
|
|
|
|
|
|
+ /* Virtual screen */
|
|
|
|
+ if (var->xres_virtual < var->xres)
|
|
|
|
+ var->xres_virtual = var->xres;
|
|
|
|
+ if (var->yres_virtual < var->yres)
|
|
|
|
+ var->yres_virtual = var->yres;
|
|
|
|
|
|
- if (var->vmode & FB_VMODE_CONUPDATE) {
|
|
|
|
- var->vmode |= FB_VMODE_YWRAP;
|
|
|
|
- var->xoffset = info->var.xoffset;
|
|
|
|
- var->yoffset = info->var.yoffset;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Virtual screen and panning are not supported */
|
|
|
|
- if (var->xres_virtual > var->xres || var->yres_virtual > var->yres ||
|
|
|
|
- var->xoffset || var->yoffset) {
|
|
|
|
|
|
+ if (var->xres_virtual > line_length / BPP) {
|
|
dev_dbg(info->device,
|
|
dev_dbg(info->device,
|
|
- "Virtual screen and panning are not supported\n");
|
|
|
|
|
|
+ "Horizontal virtual screen size too large\n");
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
- var->xres_virtual = var->xres;
|
|
|
|
- var->yres_virtual = var->yres;
|
|
|
|
|
|
+ if (var->xoffset + var->xres > var->xres_virtual ||
|
|
|
|
+ var->yoffset + var->yres > var->yres_virtual) {
|
|
|
|
+ dev_dbg(info->device, "panning out-of-range\n");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
|
|
/* We support ARGB8888 only */
|
|
/* We support ARGB8888 only */
|
|
if (var->bits_per_pixel > 32 || var->grayscale ||
|
|
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)
|
|
}
|
|
}
|
|
|
|
|
|
/* Memory limit */
|
|
/* Memory limit */
|
|
- if (var->yres * line_length > ps3fb.xdr_size) {
|
|
|
|
|
|
+ if (var->yres_virtual * line_length > ps3fb.xdr_size) {
|
|
dev_dbg(info->device, "Not enough memory\n");
|
|
dev_dbg(info->device, "Not enough memory\n");
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
@@ -561,7 +558,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
|
|
static int ps3fb_set_par(struct fb_info *info)
|
|
static int ps3fb_set_par(struct fb_info *info)
|
|
{
|
|
{
|
|
struct ps3fb_par *par = info->par;
|
|
struct ps3fb_par *par = info->par;
|
|
- unsigned int mode, lines, maxlines;
|
|
|
|
|
|
+ unsigned int mode, line_length, lines, maxlines;
|
|
int i;
|
|
int i;
|
|
unsigned long offset, dst;
|
|
unsigned long offset, dst;
|
|
|
|
|
|
@@ -569,7 +566,7 @@ static int ps3fb_set_par(struct fb_info *info)
|
|
info->var.xres, info->var.xres_virtual,
|
|
info->var.xres, info->var.xres_virtual,
|
|
info->var.yres, info->var.yres_virtual, info->var.pixclock);
|
|
info->var.yres, info->var.yres_virtual, info->var.pixclock);
|
|
|
|
|
|
- mode = ps3fb_find_mode(&info->var, &info->fix.line_length);
|
|
|
|
|
|
+ mode = ps3fb_find_mode(&info->var, &line_length);
|
|
if (!mode)
|
|
if (!mode)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
@@ -578,6 +575,10 @@ static int ps3fb_set_par(struct fb_info *info)
|
|
|
|
|
|
info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
|
|
info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
|
|
info->fix.smem_len = ps3fb.xdr_size;
|
|
info->fix.smem_len = ps3fb.xdr_size;
|
|
|
|
+ info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
|
|
|
|
+ info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
|
|
|
|
+ info->fix.line_length = line_length;
|
|
|
|
+
|
|
info->screen_base = (char __iomem *)ps3fb.xdr_ea;
|
|
info->screen_base = (char __iomem *)ps3fb.xdr_ea;
|
|
|
|
|
|
par->num_frames = info->fix.smem_len/
|
|
par->num_frames = info->fix.smem_len/
|
|
@@ -591,6 +592,8 @@ static int ps3fb_set_par(struct fb_info *info)
|
|
offset = VP_OFF(i);
|
|
offset = VP_OFF(i);
|
|
par->fb_offset = GPU_ALIGN_UP(offset);
|
|
par->fb_offset = GPU_ALIGN_UP(offset);
|
|
par->full_offset = par->fb_offset - offset;
|
|
par->full_offset = par->fb_offset - offset;
|
|
|
|
+ par->pan_offset = info->var.yoffset * line_length +
|
|
|
|
+ info->var.xoffset * BPP;
|
|
|
|
|
|
if (par->new_mode_id != par->mode_id) {
|
|
if (par->new_mode_id != par->mode_id) {
|
|
if (ps3av_set_video_mode(par->new_mode_id)) {
|
|
if (ps3av_set_video_mode(par->new_mode_id)) {
|
|
@@ -607,11 +610,11 @@ static int ps3fb_set_par(struct fb_info *info)
|
|
lines = ps3fb_res[i].yres * par->num_frames;
|
|
lines = ps3fb_res[i].yres * par->num_frames;
|
|
if (par->full_offset)
|
|
if (par->full_offset)
|
|
lines++;
|
|
lines++;
|
|
- maxlines = ps3fb.xdr_size / info->fix.line_length;
|
|
|
|
- for (dst = 0; lines; dst += maxlines * info->fix.line_length) {
|
|
|
|
|
|
+ maxlines = ps3fb.xdr_size / line_length;
|
|
|
|
+ for (dst = 0; lines; dst += maxlines * line_length) {
|
|
unsigned int l = min(lines, maxlines);
|
|
unsigned int l = min(lines, maxlines);
|
|
ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l,
|
|
ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l,
|
|
- info->fix.line_length);
|
|
|
|
|
|
+ line_length);
|
|
lines -= l;
|
|
lines -= l;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -641,6 +644,16 @@ static int ps3fb_setcolreg(unsigned int regno, unsigned int red,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int ps3fb_pan_display(struct fb_var_screeninfo *var,
|
|
|
|
+ struct fb_info *info)
|
|
|
|
+{
|
|
|
|
+ struct ps3fb_par *par = info->par;
|
|
|
|
+
|
|
|
|
+ par->pan_offset = var->yoffset * info->fix.line_length +
|
|
|
|
+ var->xoffset * BPP;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* As we have a virtual frame buffer, we need our own mmap function
|
|
* As we have a virtual frame buffer, we need our own mmap function
|
|
*/
|
|
*/
|
|
@@ -965,6 +978,7 @@ static struct fb_ops ps3fb_ops = {
|
|
.fb_check_var = ps3fb_check_var,
|
|
.fb_check_var = ps3fb_check_var,
|
|
.fb_set_par = ps3fb_set_par,
|
|
.fb_set_par = ps3fb_set_par,
|
|
.fb_setcolreg = ps3fb_setcolreg,
|
|
.fb_setcolreg = ps3fb_setcolreg,
|
|
|
|
+ .fb_pan_display = ps3fb_pan_display,
|
|
.fb_fillrect = sys_fillrect,
|
|
.fb_fillrect = sys_fillrect,
|
|
.fb_copyarea = sys_copyarea,
|
|
.fb_copyarea = sys_copyarea,
|
|
.fb_imageblit = sys_imageblit,
|
|
.fb_imageblit = sys_imageblit,
|
|
@@ -1115,7 +1129,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
|
|
info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
|
|
info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
|
|
info->fix.smem_len = ps3fb.xdr_size;
|
|
info->fix.smem_len = ps3fb.xdr_size;
|
|
info->pseudo_palette = par->pseudo_palette;
|
|
info->pseudo_palette = par->pseudo_palette;
|
|
- info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST;
|
|
|
|
|
|
+ info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
|
|
|
|
+ FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
|
|
|
|
|
|
retval = fb_alloc_cmap(&info->cmap, 256, 0);
|
|
retval = fb_alloc_cmap(&info->cmap, 256, 0);
|
|
if (retval < 0)
|
|
if (retval < 0)
|