raspberry3_bare/fb.c

133 lines
4.0 KiB
C

#include "fb.h"
#include "mbox.h"
#include "uart.h"
#include "utils.h"
#include <stdint.h>
#define MBOX_TAG_FBALLOC 0x40001
#define MBOX_TAG_FBGETPITCH 0x40008
#define MBOX_TAG_FBSETPHYS 0x48003
#define MBOX_TAG_FBSETVIRT 0x48004
#define MBOX_TAG_FBSETDEPTH 0x48005
#define MBOX_TAG_FBSETPIXORD 0x48006
#define MBOX_TAG_FBSETOFF 0x48009
/* PC Screen Font as used by Linux Console */
typedef struct {
unsigned int magic;
unsigned int version;
unsigned int headersize;
unsigned int flags;
unsigned int numglyph;
unsigned int bytesperglyph;
unsigned int height;
unsigned int width;
unsigned char glyphs;
} __attribute__((packed)) psf_t;
extern volatile unsigned char _binary_font_psf_start;
static struct fbst fb;
unsigned char *fb_init()
{
// sending many tags at once
mbox[0] = 35 * 4;
mbox[1] = MBOX_REQUEST;
mbox[2] = MBOX_TAG_FBSETPHYS; // set phy wh
mbox[3] = 8;
mbox[4] = 0;
mbox[5] = 1920; // FrameBufferInfo.width
mbox[6] = 1080; // FrameBufferInfo.height
mbox[7] = MBOX_TAG_FBSETVIRT; // set virt wh
mbox[8] = 8;
mbox[9] = 0;
mbox[10] = 1920; // FrameBufferInfo.virtual_width
mbox[11] = 1080; // FrameBufferInfo.virtual_height
mbox[12] = MBOX_TAG_FBSETOFF; // set virt offset
mbox[13] = 8;
mbox[14] = 0;
mbox[15] = 0; // FrameBufferInfo.x_offset
mbox[16] = 0; // FrameBufferInfo.y.offset
mbox[17] = MBOX_TAG_FBSETDEPTH; // set depth
mbox[18] = 4;
mbox[19] = 0;
mbox[20] = 32; // FrameBufferInfo.depth
mbox[21] = MBOX_TAG_FBSETPIXORD; // set pixel order
mbox[22] = 4;
mbox[23] = 0;
mbox[24] = 1; // RGB, not BGR preferably
mbox[25] = MBOX_TAG_FBALLOC; // get framebuffer, gets alignment on request
mbox[26] = 8;
mbox[27] = 0;
mbox[28] = 4096; // FrameBufferInfo.pointer
mbox[29] = 0; // FrameBufferInfo.size
mbox[30] = MBOX_TAG_FBGETPITCH; // get pitch
mbox[31] = 4;
mbox[32] = 0;
mbox[33] = 0; // FrameBufferInfo.pitch
mbox[34] = MBOX_TAG_LAST;
if (mbox_call(MBOX_CH_PROP, mbox) == 0 && mbox[20] == 32 && mbox[28] != 0) {
mbox[28] &= 0x3FFFFFFF; // convert GPU address to ARM address
fb.width = mbox[5]; // get actual physical width
fb.height = mbox[6]; // get actual physical height
fb.pitch = mbox[33]; // get number of bytes per line
fb.isrgb = mbox[24]; // get the actual channel order
fb.fbp = (void *)((unsigned long)mbox[28]);
} else {
puts("Unable to set framebuffer!\r\n");
return 0;
}
return fb.fbp;
}
struct fbst * fb_get(){
return &fb;
}
void fb_print(int x, int y, char *s)
{
// get our font
psf_t *font = (psf_t *)&_binary_font_psf_start;
// draw next character if it's not zero
while (*s) {
// get the offset of the glyph. Need to adjust this to support unicode table
unsigned char *glyph =
(unsigned char *)&_binary_font_psf_start + font->headersize +
(*((unsigned char *)s) < font->numglyph ? *s : 0) * font->bytesperglyph;
// calculate the offset on screen
int offs = (y * fb.pitch) + (x * 4);
// variables
int line, mask, bytesperline = (font->width + 7) / 8;
// handle carrige return
if (*s == '\r') {
x = 0;
} else
// new line
if (*s == '\n') {
x = 0;
y += font->height;
} else {
// display a character
for (unsigned int j = 0; j < font->height; j++) {
// display one row
line = offs;
mask = 1 << (font->width - 1);
for (unsigned int i = 0; i < font->width; i++) {
// if bit set, we use white color, otherwise black
*((unsigned int *)(fb.fbp + line)) = ((int)*glyph) & mask ? 0xFFFFFF : 0;
mask >>= 1;
line += 4;
}
// adjust to next line
glyph += bytesperline;
offs += fb.pitch;
}
x += (font->width + 1);
}
// next character
s++;
}
}