feat: standard vga support (mode switching, framebuffer remapping)
[lunaix-os.git] / lunaix-os / hal / gfxa / vga / vga_mmio_ops.c
diff --git a/lunaix-os/hal/gfxa/vga/vga_mmio_ops.c b/lunaix-os/hal/gfxa/vga/vga_mmio_ops.c
new file mode 100644 (file)
index 0000000..4ec8c3e
--- /dev/null
@@ -0,0 +1,90 @@
+#include "vga.h"
+
+typedef volatile u8_t vga_reg8;
+
+#define regaddr(type, i, vga)                                                  \
+    ((vga_reg8*)(vga_gfx_regmap[type][i] + (vga)->io_off))
+
+#define arx_reset(v) (void)(*regaddr(VGA_STATX, 1, v))
+
+// Port IO Address - 0x3C0
+static u32_t vga_gfx_regmap[][2] = {
+    [VGA_ARX] = { 0x0, 0x1 },    [VGA_SRX] = { 0x04, 0x05 },
+    [VGA_GRX] = { 0x0E, 0x0F },  [VGA_CRX] = { 0x14, 0x15 },
+    [VGA_DACX] = { 0x08, 0x09 }, [VGA_MISCX] = { 0x02, 0x0C },
+    [VGA_STATX] = { 0x02, 0x1A }
+};
+
+static u32_t
+vga_mmio_read(struct vga* v, u32_t type, u32_t index, u32_t mask)
+{
+    vga_reg8* reg_ix = regaddr(type, VGA_REG_X, v);
+    vga_reg8* reg_rd = regaddr(type, VGA_REG_D, v);
+    *reg_ix = (u8_t)index;
+    return ((u32_t)*reg_rd) & mask;
+}
+
+static void
+vga_mmio_write(struct vga* v, u32_t type, u32_t index, u32_t val, u32_t mask)
+{
+    index = index & 0xff;
+    val = val & mask;
+    vga_reg8* reg_ix = regaddr(type, VGA_REG_X, v);
+    if (type == VGA_ARX) {
+        // reset ARX filp-flop
+        arx_reset(v);
+        *reg_ix = ((u8_t)index) | 0x20;
+        *reg_ix = val;
+        return;
+    } else if (type == VGA_MISCX) {
+        *reg_ix = val;
+        return;
+    }
+
+    *((u16_t*)reg_ix) = (u16_t)(((val) << 8) | index);
+}
+
+static void
+vga_mmio_set_regs(struct vga* v, u32_t type, size_t off, u32_t* seq, size_t len)
+{
+    vga_reg8* reg_ix = regaddr(type, VGA_REG_X, v);
+    if (type == VGA_ARX) {
+        arx_reset(v);
+        for (size_t i = 0; i < len; i++) {
+            *reg_ix = (u8_t)(off + i) | 0x20;
+            *reg_ix = seq[i];
+        }
+
+    } else {
+        for (size_t i = 0; i < len; i++) {
+            *((u16_t*)reg_ix) = (u16_t)((seq[i] << 8) | ((off + i) & 0xff));
+        }
+    }
+}
+
+static void
+vga_mmio_set_dacp(struct vga* v)
+{
+#define R(c) (u8_t)(((c) & 0xff0000) >> 16)
+#define G(c) (u8_t)(((c) & 0x00ff00) >> 8)
+#define B(c) (u8_t)(((c) & 0x0000ff))
+
+    vga_reg8* reg_ix = regaddr(VGA_DACX, VGA_REG_X, v);
+    vga_reg8* reg_dat = regaddr(VGA_DACX, VGA_REG_D, v);
+
+    u32_t* color_map = v->lut.colors;
+
+    *reg_ix = 0;
+    for (size_t i = 0; i < v->lut.len; i++) {
+        u32_t color = color_map[i];
+        *reg_dat = R(color);
+        *reg_dat = G(color);
+        *reg_dat = B(color);
+    }
+}
+
+struct vga_regops vga_default_mmio_ops = { .read = vga_mmio_read,
+                                           .write = vga_mmio_write,
+                                           .set_seq = vga_mmio_set_regs,
+                                           .set_dac_palette =
+                                             vga_mmio_set_dacp };
\ No newline at end of file