From 93bf62580a68533dc8252b9a2a055c02f34ecb67 Mon Sep 17 00:00:00 2001
From: Christian Cunningham <cc@localhost>
Date: Thu, 24 Mar 2022 09:38:08 -0700
Subject: Modularized

---
 kernel/graphics/lfb.c  | 218 +++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/graphics/mbox.c |  37 +++++++++
 2 files changed, 255 insertions(+)
 create mode 100644 kernel/graphics/lfb.c
 create mode 100644 kernel/graphics/mbox.c

(limited to 'kernel/graphics')

diff --git a/kernel/graphics/lfb.c b/kernel/graphics/lfb.c
new file mode 100644
index 0000000..8c41b1c
--- /dev/null
+++ b/kernel/graphics/lfb.c
@@ -0,0 +1,218 @@
+#include <drivers/uart.h>
+#include <globals.h>
+#include <graphics/glyphs.h>
+#include <graphics/lfb.h>
+#include <graphics/mbox.h>
+#include <lib/strings.h>
+
+unsigned char *lfb;                         /* raw frame buffer address */
+
+#define SCR_WIDTH  1920
+#define SCR_HEIGHT 1080
+
+/**
+ * Set screen resolution
+ */
+void lfb_init(void)
+{
+	mbox[0] = 35*4;
+	mbox[1] = MBOX_REQUEST;
+
+	mbox[2] = 0x48003;  //set phy wh
+	mbox[3] = 8;
+	mbox[4] = 8;
+	mbox[5] = SCR_WIDTH;         //FrameBufferInfo.width
+	mbox[6] = SCR_HEIGHT;          //FrameBufferInfo.height
+
+	mbox[7] = 0x48004;  //set virt wh
+	mbox[8] = 8;
+	mbox[9] = 8;
+	mbox[10] = SCR_WIDTH;        //FrameBufferInfo.virtual_width
+	mbox[11] = SCR_HEIGHT;         //FrameBufferInfo.virtual_height
+
+	mbox[12] = 0x48009; //set virt offset
+	mbox[13] = 8;
+	mbox[14] = 8;
+	mbox[15] = 0;           //FrameBufferInfo.x_offset
+	mbox[16] = 0;           //FrameBufferInfo.y.offset
+
+	mbox[17] = 0x48005; //set depth
+	mbox[18] = 4;
+	mbox[19] = 4;
+	mbox[20] = 32;          //FrameBufferInfo.depth
+
+	mbox[21] = 0x48006; //set pixel order
+	mbox[22] = 4;
+	mbox[23] = 4;
+	mbox[24] = 1;           //RGB, not BGR preferably
+
+	mbox[25] = 0x40001; //get framebuffer, gets alignment on request
+	mbox[26] = 8;
+	mbox[27] = 8;
+	mbox[28] = 4096;        //FrameBufferInfo.pointer
+	mbox[29] = 0;           //FrameBufferInfo.size
+
+	mbox[30] = 0x40008; //get pitch
+	mbox[31] = 4;
+	mbox[32] = 4;
+	mbox[33] = 0;           //FrameBufferInfo.pitch
+
+	mbox[34] = MBOX_TAG_LAST;
+
+	//this might not return exactly what we asked for, could be
+	//the closest supported resolution instead
+	if(mbox_call(MBOX_CH_PROP) && mbox[20]==32 && mbox[28]!=0) {
+		mbox[28]&=0x3FFFFFFF;   //convert GPU address to ARM address
+		gwidth=mbox[5];          //get actual physical width
+		gheight=mbox[6];         //get actual physical height
+		gpitch=mbox[33];         //get number of bytes per line
+		gisrgb=mbox[24];         //get the actual channel order
+		lfb=(void*)((unsigned long)mbox[28]);
+	} else {
+		uart_string("Unable to set screen resolution to 1024x768x32\n");
+	}
+}
+
+void clear_screen(void)
+{
+	unsigned char *ptr=lfb;
+	for(unsigned int y = 0; y < gheight; y++) {
+		for(unsigned int x = 0; x < gwidth; x++) {
+			*(unsigned int*)ptr = 0x000000;
+			ptr += 4;
+		}
+	}
+}
+
+/**
+ * Show a picture
+ */
+void lfb_showpicture(void)
+{
+	clear_screen();
+#define FWIDTH 240
+#define FHEIGHT 80
+	draw_cbox(SCR_WIDTH-FWIDTH, SCR_HEIGHT-FHEIGHT*2, FWIDTH, FHEIGHT, 0x0057b7);
+	draw_cbox(SCR_WIDTH-FWIDTH, SCR_HEIGHT-FHEIGHT, FWIDTH, FHEIGHT, 0xffd700);
+}
+
+void draw_cpixel(unsigned int lx, unsigned int ly, unsigned int c)
+{
+	unsigned char* ptr = lfb;
+	ptr += (gpitch*ly+lx*4);
+	*((unsigned int*)ptr) = gisrgb ? (unsigned int)((c&0xFF)<<16 | (c&0xFF00) | (c&0xFF0000)>>16) : c;
+}
+
+void draw_cbox(unsigned int lx, unsigned int ly, unsigned int dx, unsigned int dy, unsigned int c)
+{
+	unsigned char* ptr = lfb;
+	ptr += (gpitch*ly+lx*4);
+	for(unsigned int y = 0; y < dy; y++) {
+		for(unsigned int x = 0; x < dx; x++) {
+			*((unsigned int*)ptr) = gisrgb ? (unsigned int)((c&0xFF)<<16 | (c&0xFF00) | (c&0xFF0000)>>16) : c;
+			ptr += 4;
+		}
+		ptr += gpitch - dx*4;
+	}
+}
+
+void draw_cbyte(unsigned int lx, unsigned int ly, unsigned char letter, unsigned int c)
+{
+	unsigned int x, y;
+	unsigned char* ptr = lfb;
+	ptr += (gpitch*ly*GLYPH_Y+lx*4*GLYPH_X);
+	unsigned char ltr = (letter & 0xF) + 0x30;
+	if (ltr > 0x39) {
+		ltr += 7;
+	}
+	for(y=0; y<GLYPH_Y; y++) {
+		for(x=0; x<GLYPH_X; x++) {
+			if((0x80 >> ((GLYPH_X-1)-x)) & glyphs[y+GLYPH_Y*(ltr)]) {
+				*((unsigned int*)ptr) = gisrgb ? (unsigned int)((c&0xFF)<<16 | (c&0xFF00) | (c&0xFF0000)>>16) : c;
+			} else {
+				*((unsigned int*)ptr) = 0x000000;
+			}
+			ptr += 4;
+		}
+		ptr += gpitch - GLYPH_X*4;
+	}
+}
+
+void draw_byte(unsigned int lx, unsigned int ly, unsigned char letter)
+{
+	draw_cbyte(lx, ly, letter, 0xFFFFFF);
+}
+
+void draw_cletter(unsigned int lx, unsigned int ly, unsigned char letter, unsigned int c)
+{
+	unsigned int x, y;
+	unsigned char* ptr = lfb;
+	ptr += (gpitch*ly*GLYPH_Y+lx*4*GLYPH_X);
+	unsigned char ltr = letter & 0x7F;
+	for(y=0; y<GLYPH_Y; y++) {
+		for(x=0; x<GLYPH_X; x++) {
+			if((0x80 >> ((GLYPH_X-1)-x)) & glyphs[y+GLYPH_Y*(ltr)]) {
+				*((unsigned int*)ptr) = gisrgb ? (unsigned int)((c&0xFF)<<16 | (c&0xFF00) | (c&0xFF0000)>>16) : c;
+			} else {
+				*((unsigned int*)ptr) = 0x000000;
+			}
+			ptr += 4;
+		}
+		ptr += gpitch - GLYPH_X*4;
+	}
+}
+
+void draw_letter(unsigned int lx, unsigned int ly, unsigned char letter)
+{
+	draw_cletter(lx, ly, letter, 0xFFFFFF);
+}
+
+void draw_cstring(unsigned int lx, unsigned int ly, char* s, unsigned int c)
+{
+	unsigned int x = lx % GG_MAX_X, y = ly % GG_MAX_Y;
+	unsigned int idx = 0;
+	while(s[idx] != 0) {
+		draw_cletter(x++, y, s[idx++], c);
+		if (x > GG_MAX_X) {
+			y += 1;
+			x = 0;
+		}
+		// CHECK Y EVENTUALLY
+	}
+}
+
+void draw_string(unsigned int lx, unsigned int ly, char* s)
+{
+	draw_cstring(lx, ly, s, 0xFFFFFF);
+}
+
+void draw_chex32(unsigned int lx, unsigned int ly, unsigned long val, unsigned int c)
+{
+	unsigned int x = lx % GG_MAX_X, y = ly % GG_MAX_Y;
+	for(unsigned int i = 0; i < GLYPH_X; i++) {
+		draw_cbyte(x++, y, 0xF & (val >> ((GLYPH_X-1)-i)*4), c);
+		if (x > GG_MAX_X) {
+			y += 1;
+			x = 0;
+		}
+		// CHECK Y EVENTUALLY
+	}
+}
+
+void draw_hex32(unsigned int lx, unsigned int ly, unsigned long val)
+{
+	draw_chex32(lx, ly, val, 0xFFFFFF);
+}
+
+unsigned long draw_cu10(unsigned int lx, unsigned int ly, unsigned long val, unsigned int c)
+{
+	string_t vals = u32_to_str(val);
+	unsigned long len = strlen(vals);
+	draw_cstring(lx, ly, vals, c);
+	return len;
+}
+
+unsigned long draw_u10(unsigned int lx, unsigned int ly, unsigned long val)
+{
+	return draw_cu10(lx, ly, val, 0xFFFFFF);
+}
diff --git a/kernel/graphics/mbox.c b/kernel/graphics/mbox.c
new file mode 100644
index 0000000..0dac497
--- /dev/null
+++ b/kernel/graphics/mbox.c
@@ -0,0 +1,37 @@
+#include <symbols.h>
+
+/* mailbox message buffer */
+volatile unsigned int  __attribute__((aligned(16))) mbox[36];
+
+#define VIDEOCORE_MBOX  (MMIO_BASE+0x0000B880)
+#define MBOX_READ       ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0))
+#define MBOX_POLL       ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10))
+#define MBOX_SENDER     ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14))
+#define MBOX_STATUS     ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18))
+#define MBOX_CONFIG     ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C))
+#define MBOX_WRITE      ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20))
+#define MBOX_RESPONSE   0x80000000
+#define MBOX_FULL       0x80000000
+#define MBOX_EMPTY      0x40000000
+
+/**
+ * Make a mailbox call. Returns 0 on failure, non-zero on success
+ */
+int mbox_call(unsigned char ch)
+{
+    unsigned int r = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF));
+    /* wait until we can write to the mailbox */
+    do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL);
+    /* write the address of our message to the mailbox with channel identifier */
+    *MBOX_WRITE = r;
+    /* now wait for the response */
+    while(1) {
+        /* is there a response? */
+        do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY);
+        /* is it a response to our message? */
+        if(r == *MBOX_READ)
+            /* is it a valid successful response? */
+            return mbox[1]==MBOX_RESPONSE;
+    }
+    return 0;
+}
-- 
cgit v1.2.1