@@ -426,6 +426,33 @@ static struct tile_texture texture_for_tile(const u32 tile_index,
};
}
+/**
+ * valid_bitbltbuf_width - is the BITBLTBUF width valid?
+ * @width: width in pixels to check
+ * @psm: pixel storage mode
+ *
+ * In local-to-local BITBLTBUF transmissions, the following restrictions
+ * to the TRXREG register width field apply depending on the pixel storage
+ * mode[1]:
+ *
+ * - multiple of 2: PSMCT32, PSMZ32
+ * - multiple of 4: PSMCT16, PSMCT16S, PSMZ16, PSMZ16S
+ * - multiple of 8: PSMCT24, PSMZ24, PSMT8, PSMT8H, PSMT4, PSMT4HL, PSMT4HH
+ *
+ * Return: %true if the given width is valid, otherwise %false
+ */
+static bool valid_bitbltbuf_width(int width, enum gs_psm psm)
+{
+ if (width < 1)
+ return false;
+ if (psm == gs_psm_ct32 && (width & 1) != 0)
+ return false;
+ if (psm == gs_psm_ct16 && (width & 3) != 0)
+ return false;
+
+ return true;
+}
+
/**
* display_buffer_size - display buffer size for a given video resolution
*
@@ -629,6 +656,103 @@ void write_cb_environment(struct fb_info *info)
fb_err(info, "Failed to write GS environment, GIF is busy\n");
}
+/**
+ * package_copyarea - package copy area tags and data for the GIF
+ * @package: DMA buffer to put packages in
+ * @area: area to copy
+ * @info: frame buffer info object
+ *
+ * Return: number of generated GIF packages in 16-byte unit
+ */
+static size_t package_copyarea(union package *package,
+ const struct fb_copyarea *area, const struct fb_info *info)
+{
+ const struct fb_var_screeninfo *var = &info->var;
+ union package * const base_package = package;
+ const int psm = var_to_psm(var, info);
+ const int fbw = var_to_fbw(var);
+
+ GIF_PACKAGE_TAG(package) {
+ .flg = gif_packed_mode,
+ .reg0 = gif_reg_ad,
+ .nreg = 1,
+ .nloop = 4
+ };
+ GIF_PACKAGE_AD(package) {
+ .addr = gs_addr_bitbltbuf,
+ .data.bitbltbuf = {
+ .spsm = psm, .sbw = fbw,
+ .dpsm = psm, .dbw = fbw
+ }
+ };
+ GIF_PACKAGE_AD(package) {
+ .addr = gs_addr_trxpos,
+ .data.trxpos = {
+ .ssax = area->sx, .ssay = area->sy,
+ .dsax = area->dx, .dsay = area->dy,
+ .dir = area->dy < area->sy ||
+ (area->dy == area->sy && area->dx < area->sx) ?
+ gs_trxpos_dir_ul_lr : gs_trxpos_dir_lr_ul
+ }
+ };
+ GIF_PACKAGE_AD(package) {
+ .addr = gs_addr_trxreg,
+ .data.trxreg = {
+ .rrw = area->width,
+ .rrh = area->height
+ }
+ };
+ GIF_PACKAGE_AD(package) {
+ .addr = gs_addr_trxdir,
+ .data.trxdir = { .xdir = gs_trxdir_local_to_local }
+ };
+
+ return package - base_package;
+}
+
+/**
+ * ps2fb_cb_copyarea - copy console buffer area
+ * @area: area to copy
+ * @info: frame buffer info object
+ */
+void ps2fb_cb_copyarea(const struct fb_copyarea *area, struct fb_info *info)
+{
+ const enum gs_psm psm = var_to_psm(&info->var, info);
+ struct ps2fb_par *par = info->par;
+ unsigned long flags;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
+ if (area->width < 1 || area->height < 1)
+ return;
+ if (!valid_bitbltbuf_width(area->width, psm)) {
+ /*
+ * Some widths are not entirely supported with BITBLTBUF,
+ * but there will be more graphical glitches by refusing
+ * to proceed. Besides, info->pixmap.blit_x says that
+ * they are unsupported so unless someone wants to have
+ * odd fonts we will not end up here anyway. Warn once
+ * here for the protocol.
+ */
+ fb_warn_once(info, "%s: "
+ "Unsupported width %u for pixel storage format %u\n",
+ __func__, area->width, psm);
+ }
+
+ spin_lock_irqsave(&par->lock, flags);
+
+ if (gif_wait()) {
+ union package * const base_package = par->package.buffer;
+ union package *package = base_package;
+
+ package += package_copyarea(package, area, info);
+
+ gif_write(&base_package->gif, package - base_package);
+ }
+
+ spin_unlock_irqrestore(&par->lock, flags);
+}
+
/**
* pixel - background or foreground pixel palette index for given coordinates
* @image: image to sample pixel from
@@ -844,6 +968,28 @@ static void ps2fb_cb_settile(struct fb_info *info, struct fb_tilemap *map)
ps2fb_cb_texflush(info);
}
+/**
+ * ps2fb_cb_tilecopy - copy console buffer tiles
+ * @info: frame buffer info object
+ * @area: tile area to copy
+ */
+static void ps2fb_cb_tilecopy(struct fb_info *info, struct fb_tilearea *area)
+{
+ const struct ps2fb_par *par = info->par;
+ const u32 tw = par->cb.tile.width;
+ const u32 th = par->cb.tile.height;
+ const struct fb_copyarea a = {
+ .dx = tw * area->dx,
+ .dy = th * area->dy,
+ .width = tw * area->width,
+ .height = th * area->height,
+ .sx = tw * area->sx,
+ .sy = th * area->sy
+ };
+
+ ps2fb_cb_copyarea(&a, info);
+}
+
/**
* ps2fb_cb_get_tilemax - maximum number of tiles
* @info: frame buffer info object
@@ -1507,6 +1653,7 @@ static int init_console_buffer(struct platform_device *pdev,
static struct fb_tile_ops tileops = {
.fb_settile = ps2fb_cb_settile,
+ .fb_tilecopy = ps2fb_cb_tilecopy,
.fb_get_tilemax = ps2fb_cb_get_tilemax
};
@@ -1522,6 +1669,7 @@ static int init_console_buffer(struct platform_device *pdev,
info->fbops = &fbops;
info->flags = FBINFO_DEFAULT |
+ FBINFO_HWACCEL_COPYAREA |
FBINFO_READS_FAST;
info->flags |= FBINFO_MISC_TILEBLITTING;
In local-to-local BITBLTBUF transmissions, the following restrictions to the TRXREG register width field apply depending on the pixel storage mode[1]: - multiple of 2: PSMCT32, PSMZ32 - multiple of 4: PSMCT16, PSMCT16S, PSMZ16, PSMZ16S - multiple of 8: PSMCT24, PSMZ24, PSMT8, PSMT8H, PSMT4, PSMT4HL, PSMT4HH References: [1] "GS User's Manual", version 6.0, Sony Computer Entertainment Inc., p. 76. Signed-off-by: Fredrik Noring <noring@nocrew.org> --- drivers/video/fbdev/ps2fb.c | 148 ++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+)