@@ -1368,6 +1368,109 @@ static void clear_screen(struct fb_info *info)
gif_write(&base_package->gif, package - base_package);
}
+/**
+ * write_cb_pan_display - write console buffer pan operation to the GIF
+ * @var: screen info object
+ * @info: frame buffer info object
+ *
+ * XPAN, YPAN and YWRAP are hardware accelerated. YWRAP is implemented using
+ * the two independent rectangular area read output circuits of the Graphics
+ * Synthesizer. The DISPLAY1 register outputs the upper part and the DISPLAY2
+ * register outputs the lower part.
+ */
+static void write_cb_pan_display(const struct fb_var_screeninfo *var,
+ const struct fb_info *info)
+{
+ const struct gs_display display = gs_read_display1();
+ const int psm = var_to_psm(var, info);
+ const int fbw = var_to_fbw(var);
+ const int yo = var->yoffset % var->yres_virtual;
+ const int dh1 = min_t(int, var->yres_virtual - yo, var->yres);
+ const int dh2 = var->yres - dh1;
+
+ GS_WRITE_DISPLAY1(
+ .dh = dh1 - 1,
+ .dw = display.dw,
+ .magv = display.magv,
+ .magh = display.magh,
+ .dy = display.dy,
+ .dx = display.dx,
+ );
+
+ GS_WRITE_DISPLAY2(
+ .dh = dh2 - 1,
+ .dw = display.dw,
+ .magv = display.magv,
+ .magh = display.magh,
+ .dy = display.dy + dh1,
+ .dx = display.dx,
+ );
+
+ GS_WRITE_DISPFB1(
+ .fbw = fbw,
+ .psm = psm,
+ .dbx = var->xoffset,
+ .dby = yo
+ );
+
+ GS_WRITE_DISPFB2(
+ .fbw = fbw,
+ .psm = psm,
+ .dbx = var->xoffset,
+ .dby = 0,
+ );
+
+ GS_WRITE_PMODE(
+ .en1 = 1,
+ .en2 = dh2 ? 1 : 0,
+ .crtmd = 1
+ );
+}
+
+/**
+ * changed_cb_pan_display - is display panning needed?
+ * @var: screen info object
+ *
+ * Panning is undefined until the DISPFB1 register has been set.
+ *
+ * Return: %true if the horizontal or vertical panning is needed, otherwise
+ * %false
+ */
+static bool changed_cb_pan_display(const struct fb_var_screeninfo *var)
+{
+ if (gs_valid_dispfb1()) {
+ const struct gs_dispfb dspfb12 = gs_read_dispfb1();
+ const int yo = var->yoffset % var->yres_virtual;
+
+ return dspfb12.dbx != var->xoffset || dspfb12.dby != yo;
+ }
+
+ return false; /* DISPFB1 is incomparable before video mode is set. */
+}
+
+/**
+ * ps2fb_cb_pan_display - pan the display
+ * @var: screen info object
+ * @info: frame buffer info object
+ *
+ * Return: 0 on success, otherwise a negative error number
+ */
+static int ps2fb_cb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct ps2fb_par *par = info->par;
+ unsigned long flags;
+
+ spin_lock_irqsave(&par->lock, flags);
+
+ if (changed_cb_pan_display(var))
+ write_cb_pan_display(var, info);
+
+ spin_unlock_irqrestore(&par->lock, flags);
+
+ return 0;
+}
+
/**
* bits_per_pixel_fits - does the given resolution fit the given buffer size?
* @xres_virtual: virtual x resolution in pixels
@@ -1438,8 +1541,11 @@ static int ps2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->yres < 1 || 2048 < var->yres)
return -EINVAL;
- var->xres_virtual = var->xres;
- var->yres_virtual = var->yres;
+ /* Check virtual resolution. */
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
var->xoffset = 0;
var->yoffset = 0;
@@ -1833,8 +1939,8 @@ static int ps2fb_set_par(struct fb_info *info)
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_TRUECOLOR;
- info->fix.xpanstep = 0;
- info->fix.ypanstep = 0;
+ info->fix.xpanstep = var->xres_virtual > var->xres ? 1 : 0;
+ info->fix.ypanstep = var->yres_virtual > var->yres ? 1 : 0;
info->fix.ywrapstep = 1;
info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
@@ -1883,6 +1989,7 @@ static int ps2fb_cb_set_par(struct fb_info *info)
par->cb.block_count = var_to_block_count(info);
write_cb_environment(info);
+ write_cb_pan_display(&info->var, info);
clear_screen(info);
}
@@ -1928,6 +2035,7 @@ static int init_console_buffer(struct platform_device *pdev,
.fb_setcolreg = ps2fb_setcolreg,
.fb_set_par = ps2fb_cb_set_par,
.fb_check_var = ps2fb_cb_check_var,
+ .fb_pan_display = ps2fb_cb_pan_display,
};
static struct fb_tile_ops tileops = {
@@ -1954,6 +2062,10 @@ static int init_console_buffer(struct platform_device *pdev,
FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT |
FBINFO_HWACCEL_IMAGEBLIT |
+ FBINFO_HWACCEL_XPAN |
+ FBINFO_HWACCEL_YPAN |
+ FBINFO_HWACCEL_YWRAP |
+ FBINFO_PARTIAL_PAN_OK |
FBINFO_READS_FAST;
info->flags |= FBINFO_MISC_TILEBLITTING;
XPAN, YPAN and YWRAP are hardware accelerated. YWRAP is implemented using the two independent rectangular area read output circuits of the Graphics Synthesizer[1]. The DISPLAY1 register outputs the upper part and the DISPLAY2 register outputs the lower part. References: [1] "GS User's Manual", version 6.0, Sony Computer Entertainment Inc., p. 82. Signed-off-by: Fredrik Noring <noring@nocrew.org> --- drivers/video/fbdev/ps2fb.c | 120 ++++++++++++++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 4 deletions(-)