135 lines
4.2 KiB
C

/**
* Framebuffer initialization of Asagiri
* Copyright (C) 2023 Asagiri contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <bits/alltypes.h>
#include <device.h>
#include <fb.h>
#include <fdt.h>
#include <hal.h>
#include <stdio.h>
#include <string.h>
/* The buffer must be 16-byte aligned as only the upper 28 bits of the address
* can be passed via the mailbox */
volatile unsigned int __attribute__((aligned(16))) mbox[36];
unsigned int width, height, pitch, bpp, rgb;
unsigned char *fb;
void pixel_draw(int x, int y, int r, int g, int b) {
fb[(pitch * y) + (x * bpp) + 0] = r;
fb[(pitch * y) + (x * bpp) + 1] = g;
fb[(pitch * y) + (x * bpp) + 2] = b;
}
unsigned int mbox_call(unsigned char ch) {
unsigned int m = ((unsigned int)((long)&mbox) & ~0xF)
| (ch & 0xF); /* 28-bit address (MSB), 4-bit value (LSB) */
while (1)
if (!(mmio_read(MBOX_STATUS) & MBOX_FULL))
break;
mmio_write(MBOX_WRITE, m);
while (1) {
while (1)
if (!(mmio_read(MBOX_STATUS) & MBOX_EMPTY))
break; /* Wait for a reply */
if (m == mmio_read(MBOX_READ)) { /* Look for a message on MBOX_READ */
if (mbox[1] == MBOX_RESPONSE)
return 1; /* Success! */
else
return 0;
}
}
return 0;
}
void fb_init() {
fdt_prop mailbox_path = fdt_get_prop(fdt_get_addr("/__symbols__/mailbox"));
fdt_prop mailbox_reg = fdt_get_prop(fdt_get_addr(strcat((char *)mailbox_path.data, "/reg")));
MBOX_BASE = SWAP_UINT32(*mailbox_reg.data) - MMIO_BASE;
MBOX_READ = (MBOX_BASE + 0x0);
MBOX_POLL = (MBOX_BASE + 0x10);
MBOX_SENDER = (MBOX_BASE + 0x14);
MBOX_STATUS = (MBOX_BASE + 0x18);
MBOX_CONFIG = (MBOX_BASE + 0x1C);
MBOX_WRITE = (MBOX_BASE + 0x20);
mbox[0] = 35 * 4; /* Length of message in bytes */
mbox[1] = MBOX_REQUEST;
mbox[2] = MBOX_TAG_SETPHYWH;
mbox[3] = 8; /* Value size in bytes */
mbox[4] = 0;
mbox[5] = 640; /* Width, hardcoded for now */
mbox[6] = 480; /* Height, hardcoded for now */
mbox[7] = MBOX_TAG_SETVIRTWH;
mbox[8] = 8;
mbox[9] = 8;
mbox[10] = 640;
mbox[11] = 480;
mbox[12] = MBOX_TAG_SETVIRTOFF;
mbox[13] = 8;
mbox[14] = 8;
mbox[15] = 0; /* X coordinate */
mbox[16] = 0; /* Y coordinate */
mbox[17] = MBOX_TAG_SETDEPTH;
mbox[18] = 4;
mbox[19] = 4;
mbox[20] = 32; /* Bits per pixel */
mbox[21] = MBOX_TAG_SETPXLORDR;
mbox[22] = 4;
mbox[23] = 4;
mbox[24] = 1; /* RGB */
mbox[25] = MBOX_TAG_GETFB;
mbox[26] = 8;
mbox[27] = 8;
mbox[28] = 4096; /* FrameBufferInfo.pointer */
mbox[29] = 0; /* FrameBufferInfo.size */
mbox[30] = MBOX_TAG_GETPITCH;
mbox[31] = 4;
mbox[32] = 4;
mbox[33] = 0; /* Bytes per line */
mbox[34] = MBOX_TAG_LAST;
/* Check if mailbox says we're good and that the depth is what we asked for
* and that it gave us a pointer */
if (mbox_call(MBOX_CH_PROP) && mbox[20] == 32 && mbox[28] != 0) {
mbox[28] &= 0x3FFFFFFF; /* Convert GPU address to ARM address */
width = mbox[10]; /* Actual physical width */
height = mbox[11]; /* Actual physical height */
pitch = mbox[33]; /* Number of bytes per line */
rgb = mbox[24]; /* Pixel order */
fb = (unsigned char *)((long)mbox[28]);
bpp = pitch / width;
printf("Initialized framebuffer.\n");
}
memset(fb, 0x00, pitch * height);
}