From: Michael Schmitz <schmitzmic@gmail.com>
To: linux-m68k@vger.kernel.org, geert@linux-m68k.org
Cc: schmitzmic@gmail.com, Miro Kropacek <miro.kropacek@gmail.com>,
linux-fbdev@vger.kernel.org
Subject: [PATCH 4/5] fbdev: Add support for SuperVidel's SuperBlitter
Date: Fri, 14 Aug 2026 15:17:44 +1200 [thread overview]
Message-ID: <20260814031745.17140-5-schmitzmic@gmail.com> (raw)
In-Reply-To: <20260814031745.17140-1-schmitzmic@gmail.com>
From: Miro Kropacek <miro.kropacek@gmail.com>
The SuperVidel graphics FPGA includes a hardware blitter (bit block
transfer engine) operating within the SuperVidel DDR2 video RAM.
Two versions of this blitter exist. Later versions (>= 9) of the
SuperVidel firmware support an asynchronous command FIFO, older
versions must be polled for command completion.
Add hardware-accelerated copyarea, fillrect and imageblit fb
operations (falling back to the non-accelerated versions for
anything that exceeds blitter capabilities).
Signed-off-by: Miro Kropacek <miro.kropacek@gmail.com>
Reviewed-by: Michael Schmitz <schmitzmic@gmail.com>
Cc: <linux-fbdev@vger.kernel.org>
Link: https://lists.debian.org/debian-68k/2026/08/msg00000.html
---
drivers/video/fbdev/atafb.c | 197 ++++++++++++++++++++++++++++++++++++
1 file changed, 197 insertions(+)
diff --git a/drivers/video/fbdev/atafb.c b/drivers/video/fbdev/atafb.c
index 50853d7a08e3..dc2d4154e1b6 100644
--- a/drivers/video/fbdev/atafb.c
+++ b/drivers/video/fbdev/atafb.c
@@ -2304,6 +2304,185 @@ static int ext_detect(void)
return 1;
}
+/* ------------------- SuperVidel SuperBlitter ---------------------- */
+
+/*
+ * Hardware blitter in the SuperVidel FPGA, operating within SV DDR2 RAM.
+ * FW revision >= 9 provides a command FIFO (async operation); older
+ * revisions are programmed directly with busy-polling.
+ */
+#define SVBLIT_REGS_PHYS 0x80010000
+#define SVBLIT_SRC1 0x58 /* bits 26:0 */
+#define SVBLIT_SRC2 0x5c
+#define SVBLIT_DST 0x60
+#define SVBLIT_COUNT 0x64 /* bytes per line - 1 */
+#define SVBLIT_SRC1_OFFSET 0x68 /* line start to next line start */
+#define SVBLIT_SRC2_OFFSET 0x6c
+#define SVBLIT_DST_OFFSET 0x70
+#define SVBLIT_MASK_AND_LINES 0x74 /* bits 11:0: number of lines */
+#define SVBLIT_CONTROL 0x78 /* bit 0: busy/start, bits 4:1: mode */
+#define SVBLIT_VERSION 0x7c /* bits 9:0: FW revision */
+#define SVBLIT_FIFO 0x80 /* wr: data; rd: bit 0 empty, bit 1 full */
+
+/*
+ * SuperBlitter bug: Instead of declared 2048 bytes, 2032 is the real maximum.
+ */
+#define SVBLIT_MAX_SPAN 2032
+
+static void __iomem *svblit_regs;
+static int svblit_fw;
+
+static inline u32 svblit_rd(unsigned int reg)
+{
+ return __raw_readl(svblit_regs + reg);
+}
+
+static inline void svblit_wr(unsigned int reg, u32 val)
+{
+ __raw_writel(val, svblit_regs + reg);
+}
+
+/* wait until all queued blits have finished */
+static void svblit_wait(void)
+{
+ if (svblit_fw >= 9)
+ /* FIFO empty flag = fewer than 9 longwords queued */
+ while (!(svblit_rd(SVBLIT_FIFO) & 1))
+ cpu_relax();
+ while (svblit_rd(SVBLIT_CONTROL) & 1)
+ cpu_relax();
+}
+
+/*
+ * FW >= 9 queues commands through the 512-longword FIFO: a command is
+ * 9 longwords (registers 0x58..0x78 in order), executed whenever >= 9
+ * words are queued and the blitter is idle. The full flag rises at
+ * >= 500 queued words, so below it there is always room for a whole
+ * command — one flag check per command prevents overflow (dropped
+ * words would desync the 9-word framing until an SV reinit, which is
+ * exactly what overflowing did before this guard existed). Older FW
+ * is programmed directly with busy-polling.
+ *
+ * The line byte count field is 11 bits but see SVBLIT_MAX_SPAN.
+ */
+static void svblit_copy(u32 src, u32 dst, u32 nbytes, u32 src_offset,
+ u32 dst_offset, u32 lines)
+{
+ while (nbytes) {
+ u32 chunk = min(nbytes, SVBLIT_MAX_SPAN);
+
+ if (svblit_fw >= 9) {
+ while (svblit_rd(SVBLIT_FIFO) & 2)
+ cpu_relax();
+ svblit_wr(SVBLIT_FIFO, src);
+ svblit_wr(SVBLIT_FIFO, 0);
+ svblit_wr(SVBLIT_FIFO, dst);
+ svblit_wr(SVBLIT_FIFO, chunk - 1);
+ svblit_wr(SVBLIT_FIFO, src_offset);
+ svblit_wr(SVBLIT_FIFO, 0);
+ svblit_wr(SVBLIT_FIFO, dst_offset);
+ svblit_wr(SVBLIT_FIFO, lines);
+ svblit_wr(SVBLIT_FIFO, 0x01);
+ } else {
+ while (svblit_rd(SVBLIT_CONTROL) & 1)
+ cpu_relax();
+ svblit_wr(SVBLIT_SRC1, src);
+ svblit_wr(SVBLIT_SRC2, 0);
+ svblit_wr(SVBLIT_DST, dst);
+ svblit_wr(SVBLIT_COUNT, chunk - 1);
+ svblit_wr(SVBLIT_SRC1_OFFSET, src_offset);
+ svblit_wr(SVBLIT_SRC2_OFFSET, 0);
+ svblit_wr(SVBLIT_DST_OFFSET, dst_offset);
+ svblit_wr(SVBLIT_MASK_AND_LINES, lines);
+ svblit_wr(SVBLIT_CONTROL, 0x01);
+ }
+
+ src += chunk;
+ dst += chunk;
+ nbytes -= chunk;
+ }
+}
+
+static int svblit_sync(struct fb_info *info)
+{
+ svblit_wait();
+ return 0;
+}
+
+static void svblit_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ u32 bytespp = info->var.bits_per_pixel / 8;
+ u32 pitch = info->fix.line_length;
+
+ /*
+ * The blitter walks lines in ascending order, so overlapping
+ * moves down/right would read already overwritten data. Those
+ * are rare for fbcon (scrolling backwards); leave them and
+ * oversized areas to the CPU.
+ */
+ if (area->height > 4095 ||
+ area->dy > area->sy ||
+ (area->dy == area->sy && area->dx > area->sx)) {
+ svblit_wait();
+ cfb_copyarea(info, area);
+ return;
+ }
+
+ svblit_copy(external_addr + area->sy * pitch + area->sx * bytespp,
+ external_addr + area->dy * pitch + area->dx * bytespp,
+ area->width * bytespp, pitch, pitch, area->height);
+ /* async: every CPU access to the fb goes through svblit_wait() */
+}
+
+static void svblit_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ u32 bytespp = info->var.bits_per_pixel / 8;
+ u32 pitch = info->fix.line_length;
+ u8 *line;
+ u32 pix;
+
+ svblit_wait(); /* the CPU is about to touch the fb */
+
+ if (rect->rop != ROP_COPY || rect->height <= 1 ||
+ rect->height > 4096) {
+ cfb_fillrect(info, rect);
+ return;
+ }
+
+ pix = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
+ ((u32 *)info->pseudo_palette)[rect->color] : rect->color;
+
+ /* draw the first line with the CPU ... */
+ line = (u8 *)info->screen_base + rect->dy * pitch +
+ rect->dx * bytespp;
+ switch (bytespp) {
+ case 1:
+ memset(line, pix, rect->width);
+ break;
+ case 2:
+ memset16((u16 *)line, pix, rect->width);
+ break;
+ default:
+ memset32((u32 *)line, pix, rect->width);
+ break;
+ }
+
+ /* ... and let the blitter replicate it into the other lines */
+ svblit_copy(external_addr + rect->dy * pitch + rect->dx * bytespp,
+ external_addr + (rect->dy + 1) * pitch +
+ rect->dx * bytespp,
+ rect->width * bytespp, 0, pitch, rect->height - 1);
+}
+
+static void svblit_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ svblit_wait(); /* CPU rendering must not race queued blits */
+ cfb_imageblit(info, image);
+}
+
#endif /* ATAFB_EXT */
/* ------ This is the same for most hardware types -------- */
@@ -3168,6 +3347,24 @@ static int __init atafb_probe(struct platform_device *pdev)
phys_screen_base = external_addr;
screen_len = external_len & PAGE_MASK;
memset (screen_base, 0, external_len);
+
+ /* framebuffer in SV RAM: enable the SuperBlitter */
+ if (external_addr >= 0xa0000000) {
+ svblit_regs = ioremap(SVBLIT_REGS_PHYS, 0x100);
+ if (svblit_regs) {
+ svblit_fw = svblit_rd(SVBLIT_VERSION) & 0x1ff;
+ atafb_ops.fb_fillrect = svblit_fillrect;
+ atafb_ops.fb_copyarea = svblit_copyarea;
+ atafb_ops.fb_imageblit = svblit_imageblit;
+ atafb_ops.fb_sync = svblit_sync;
+ fb_info.flags |= FBINFO_HWACCEL_COPYAREA |
+ FBINFO_HWACCEL_FILLRECT;
+ dev_info(&pdev->dev,
+ "SuperBlitter enabled, FW revision %d (%s)\n",
+ svblit_fw, svblit_fw >= 9 ?
+ "async FIFO" : "sync");
+ }
+ }
}
#endif /* ATAFB_EXT */
--
2.17.1
next prev parent reply other threads:[~2026-08-14 3:17 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-14 3:17 [PATCH 0/5] m68k SuperVidel patches Michael Schmitz
2026-08-14 3:17 ` [PATCH 1/5] m68k: Fix atari mouse movement Michael Schmitz
2026-08-14 7:53 ` Geert Uytterhoeven
2026-08-14 3:17 ` [PATCH 2/5] fbdev: Give atafb proper parent Michael Schmitz
2026-08-14 7:50 ` Helge Deller
2026-08-14 3:17 ` [PATCH 3/5] fbdev: Add support for further video bit depths on atafb:external Michael Schmitz
2026-08-14 3:17 ` Michael Schmitz [this message]
2026-08-14 3:17 ` [PATCH 5/5] m68k: Add support for Svethlana Michael Schmitz
2026-08-14 8:07 ` Geert Uytterhoeven
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260814031745.17140-5-schmitzmic@gmail.com \
--to=schmitzmic@gmail.com \
--cc=geert@linux-m68k.org \
--cc=linux-fbdev@vger.kernel.org \
--cc=linux-m68k@vger.kernel.org \
--cc=miro.kropacek@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.