diff --git a/Kernel/Prekernel/Arch/aarch64/Framebuffer.cpp b/Kernel/Prekernel/Arch/aarch64/Framebuffer.cpp new file mode 100644 index 0000000000..acc74a35ec --- /dev/null +++ b/Kernel/Prekernel/Arch/aarch64/Framebuffer.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2021, Marcin Undak + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Prekernel { + +Framebuffer::Framebuffer() +{ + // FIXME: query HDMI for best mode + // https://github.com/raspberrypi/userland/blob/master/host_applications/linux/apps/tvservice/tvservice.c + m_width = 1280; + m_height = 720; + m_depth = 32; + m_initialized = false; + + struct __attribute__((aligned(16))) { + Mailbox::MessageHeader header; + FramebufferSetPhysicalSizeMboxMessage set_physical_size; + FramebufferSetVirtualSizeMboxMessage set_virtual_size; + FramebufferSetVirtualOffsetMboxMessage set_virtual_offset; + FramebufferSetDepthMboxMessage set_depth; + FramebufferSetPixelOrderMboxMessage set_pixel_order; + FramebufferAllocateBufferMboxMessage allocate_buffer; + FramebufferGetPithMboxMessage get_pitch; + Mailbox::MessageTail tail; + } message_queue; + + message_queue.header.set_queue_size(sizeof(message_queue)); + message_queue.set_physical_size.width = m_width; + message_queue.set_physical_size.height = m_height; + message_queue.set_virtual_size.width = m_width; + message_queue.set_virtual_size.height = m_height; + + // FIXME! those next 2 lines crash... + // message_queue.set_virtual_offset.x = 0; + // message_queue.set_virtual_offset.y = 0; + + message_queue.set_depth.depth_bits = 32; + message_queue.set_pixel_order.pixel_order = FramebufferSetPixelOrderMboxMessage::PixelOrder::RGB; + message_queue.allocate_buffer.alignment = 4096; + + if (!Mailbox::the().send_queue(&message_queue, sizeof(message_queue))) { + warnln("Framebuffer(): Mailbox send failed."); + return; + } + + // Now message queue contains responses. Process them. + + if (message_queue.set_physical_size.width != m_width || message_queue.set_physical_size.height != m_height) { + warnln("Framebuffer(): Setting physical dimension failed."); + return; + } + + if (message_queue.set_virtual_size.width != m_width || message_queue.set_virtual_size.height != m_height) { + warnln("Framebuffer(): Setting virtual dimension failed."); + return; + } + + if (message_queue.set_virtual_offset.x != 0 || message_queue.set_virtual_offset.y != 0) { + warnln("Framebuffer(): Setting virtual offset failed."); + return; + } + + if (message_queue.set_depth.depth_bits != m_depth) { + warnln("Framebuffer(): Setting depth failed."); + return; + } + + if (message_queue.allocate_buffer.size == 0 || message_queue.allocate_buffer.address == 0) { + warnln("Framebuffer(): Allocating buffer failed."); + return; + } + + if (message_queue.get_pitch.pitch == 0) { + warnln("Framebuffer(): Retrieving pitch failed."); + return; + } + + // Convert GPU address space to RAM + // GPU maps memory from 0x80000000 instead of 0x00000000 + m_gpu_buffer = reinterpret_cast(message_queue.allocate_buffer.address & 0x3FFFFFFF); + + m_buffer_size = message_queue.allocate_buffer.size; + m_pitch = message_queue.get_pitch.pitch; + + switch (message_queue.set_pixel_order.pixel_order) { + case FramebufferSetPixelOrderMboxMessage::PixelOrder::RGB: + m_pixel_order = PixelOrder::RGB; + break; + case FramebufferSetPixelOrderMboxMessage::PixelOrder::BGR: + m_pixel_order = PixelOrder::BGR; + break; + default: + warnln("Framebuffer(): Unsupported pixel order reported by GPU."); + m_pixel_order = PixelOrder::RGB; + break; + } + + dbgln("Initialized framebuffer: 1280 x 720 @ 32 bits"); + m_initialized = true; +} + +Framebuffer& Framebuffer::the() +{ + static Framebuffer instance; + return instance; +} +} diff --git a/Kernel/Prekernel/Arch/aarch64/Framebuffer.h b/Kernel/Prekernel/Arch/aarch64/Framebuffer.h new file mode 100644 index 0000000000..2cde37dfdb --- /dev/null +++ b/Kernel/Prekernel/Arch/aarch64/Framebuffer.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021, Marcin Undak + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Prekernel { + +class Framebuffer { +public: + enum class PixelOrder { + RGB, + BGR, + }; + + static Framebuffer& the(); + + bool initialized() const { return m_initialized; } + u16 width() const { return m_width; } + u16 height() const { return m_height; } + u8 depth() const { return m_depth; } + u8* gpu_buffer() const { return m_gpu_buffer; } + u32 buffer_size() const { return m_buffer_size; } + u32 pitch() const { return m_pitch; } + PixelOrder pixel_order() { return m_pixel_order; } + +private: + u16 m_width; + u16 m_height; + u8 m_depth; + u8* m_gpu_buffer; + u32 m_buffer_size; + u32 m_pitch; + bool m_initialized; + PixelOrder m_pixel_order; + + Framebuffer(); +}; +} diff --git a/Kernel/Prekernel/Arch/aarch64/FramebufferMailboxMessages.h b/Kernel/Prekernel/Arch/aarch64/FramebufferMailboxMessages.h index 3b11bf869c..672857ac31 100644 --- a/Kernel/Prekernel/Arch/aarch64/FramebufferMailboxMessages.h +++ b/Kernel/Prekernel/Arch/aarch64/FramebufferMailboxMessages.h @@ -22,6 +22,7 @@ public: height = 0; } }; +static_assert(sizeof(FramebufferSetPhysicalSizeMboxMessage) == 20); class FramebufferSetVirtualSizeMboxMessage : public Mailbox::Message { public: @@ -35,6 +36,7 @@ public: height = 0; } }; +static_assert(sizeof(FramebufferSetVirtualSizeMboxMessage) == 20); class FramebufferSetVirtualOffsetMboxMessage : public Mailbox::Message { public: @@ -48,6 +50,7 @@ public: y = 0; } }; +static_assert(sizeof(FramebufferSetVirtualOffsetMboxMessage) == 20); class FramebufferSetDepthMboxMessage : public Mailbox::Message { public: @@ -59,6 +62,7 @@ public: depth_bits = 0; } }; +static_assert(sizeof(FramebufferSetDepthMboxMessage) == 16); class FramebufferSetPixelOrderMboxMessage : public Mailbox::Message { public: @@ -75,6 +79,7 @@ public: pixel_order = PixelOrder::BGR; } }; +static_assert(sizeof(FramebufferSetPixelOrderMboxMessage) == 16); class FramebufferAllocateBufferMboxMessage : public Mailbox::Message { public: @@ -91,6 +96,7 @@ public: size = 0; } }; +static_assert(sizeof(FramebufferAllocateBufferMboxMessage) == 20); class FramebufferGetPithMboxMessage : public Mailbox::Message { public: @@ -102,4 +108,6 @@ public: pitch = 0; } }; +static_assert(sizeof(FramebufferGetPithMboxMessage) == 16); + } diff --git a/Kernel/Prekernel/CMakeLists.txt b/Kernel/Prekernel/CMakeLists.txt index c501fcb4f7..bdedd59c9a 100644 --- a/Kernel/Prekernel/CMakeLists.txt +++ b/Kernel/Prekernel/CMakeLists.txt @@ -5,14 +5,15 @@ set(SOURCES if ("${SERENITY_ARCH}" STREQUAL "aarch64") set(SOURCES ${SOURCES} + Arch/aarch64/Aarch64_asm_utils.S Arch/aarch64/GPIO.cpp + Arch/aarch64/Framebuffer.cpp Arch/aarch64/Mailbox.cpp Arch/aarch64/MainIdRegister.cpp Arch/aarch64/MMIO.cpp Arch/aarch64/Timer.cpp Arch/aarch64/UART.cpp Arch/aarch64/Utils.cpp - Arch/aarch64/Aarch64_asm_utils.S Arch/aarch64/boot.S Arch/aarch64/init.cpp )