From 8b9562633f9405b25877806609fa4db771fe1313 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Tue, 27 Nov 2012 20:38:03 +0100 Subject: [PATCH] Add BCM2708 arch framebuffer implementation for rPi. It uses the mailbox mechanism to instruct the VideoCore to configure the desired video mode and fills it with a black and white test pattern. --- .../boot/platform/raspberrypi_arm/Jamfile | 2 + .../arch_framebuffer_bcm2708.cpp | 181 ++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 src/system/boot/platform/raspberrypi_arm/arch_framebuffer_bcm2708.cpp diff --git a/src/system/boot/platform/raspberrypi_arm/Jamfile b/src/system/boot/platform/raspberrypi_arm/Jamfile index 09761f20957..c9c481a10a2 100644 --- a/src/system/boot/platform/raspberrypi_arm/Jamfile +++ b/src/system/boot/platform/raspberrypi_arm/Jamfile @@ -34,6 +34,8 @@ BootMergeObject boot_platform_raspberrypi_arm.o : serial.cpp video.cpp + arch_framebuffer_bcm2708.cpp + $(genericPlatformSources) : -fno-pic : boot_platform_generic.a diff --git a/src/system/boot/platform/raspberrypi_arm/arch_framebuffer_bcm2708.cpp b/src/system/boot/platform/raspberrypi_arm/arch_framebuffer_bcm2708.cpp new file mode 100644 index 00000000000..becbf92673d --- /dev/null +++ b/src/system/boot/platform/raspberrypi_arm/arch_framebuffer_bcm2708.cpp @@ -0,0 +1,181 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz, mmlr@mlotz.ch + */ + +#include + +#include + +#include "arch_mmu.h" + +#include "arch_framebuffer.h" + +#include "bcm2708.h" +#include "mailbox.h" +#include "platform_debug.h" + + +struct framebuffer_config { + uint32 width; + uint32 height; + uint32 virtual_width; + uint32 virtual_height; + uint32 bytes_per_row; // from GPU + uint32 bits_per_pixel; + uint32 x_offset; + uint32 y_offset; + uint32 frame_buffer_address; // from GPU + uint32 screen_size; // from GPU + uint16 color_map[256]; +}; + + +static framebuffer_config sFramebufferConfig __attribute__((aligned(16))); + + +class ArchFramebufferBCM2708 : public ArchFramebuffer { +public: + ArchFramebufferBCM2708(); +virtual ~ArchFramebufferBCM2708(); + +virtual status_t Init(); +virtual status_t Probe(); +virtual status_t SetDefaultMode(); +virtual status_t SetVideoMode(int width, int height, int depth); +}; + + +static ArchFramebufferBCM2708 sArchFramebuffer; + + +extern "C" ArchFramebuffer* +arch_get_framebuffer_arm_bcm2708() +{ + return &sArchFramebuffer; +} + + +ArchFramebufferBCM2708::ArchFramebufferBCM2708() + : ArchFramebuffer(0) +{ +} + + +ArchFramebufferBCM2708::~ArchFramebufferBCM2708() +{ +} + + +status_t +ArchFramebufferBCM2708::Init() +{ + return B_OK; +} + + +status_t +ArchFramebufferBCM2708::Probe() +{ + return B_OK; +} + + +status_t +ArchFramebufferBCM2708::SetDefaultMode() +{ + status_t result; + do { + result = SetVideoMode(1920, 1080, 16); + } while (result != B_OK); + + return B_OK; +} + + +status_t +ArchFramebufferBCM2708::SetVideoMode(int width, int height, int depth) +{ + debug_assert(((uint32)&sFramebufferConfig & 0x0f) == 0); + + sFramebufferConfig.width = width; + sFramebufferConfig.height = height; + sFramebufferConfig.virtual_width = sFramebufferConfig.width; + sFramebufferConfig.virtual_height = sFramebufferConfig.height; + sFramebufferConfig.bytes_per_row = 0; // from GPU + sFramebufferConfig.bits_per_pixel = depth; + sFramebufferConfig.x_offset = 0; + sFramebufferConfig.y_offset = 0; + sFramebufferConfig.frame_buffer_address = 0; // from GPU + sFramebufferConfig.screen_size = 0; // from GPU + + if (depth < 16) { + const int colorMapEntries = sizeof(sFramebufferConfig.color_map) + / sizeof(sFramebufferConfig.color_map[0]); + for (int i = 0; i < colorMapEntries; i++) + sFramebufferConfig.color_map[i] = 0x1111 * i; + } + + status_t result = write_mailbox(ARM_MAILBOX_CHANNEL_FRAMEBUFFER, + (uint32)&sFramebufferConfig | BCM2708_VIDEO_CORE_L2_COHERENT); + if (result != B_OK) + return result; + + uint32 value; + result = read_mailbox(ARM_MAILBOX_CHANNEL_FRAMEBUFFER, value); + if (result != B_OK) + return result; + + if (value != 0) { + dprintf("failed to configure framebuffer: %" B_PRIx32 "\n", value); + debug_toggle_led(5, DEBUG_DELAY_SHORT); + return B_ERROR; + } + + if (sFramebufferConfig.frame_buffer_address == 0) { + dprintf("didn't get the framebuffer address\n"); + debug_toggle_led(10, DEBUG_DELAY_SHORT); + return B_ERROR; + } + + debug_assert(sFramebufferConfig.x_offset == 0 + && sFramebufferConfig.y_offset == 0 + && sFramebufferConfig.width == (uint32)width + && sFramebufferConfig.height == (uint32)height + && sFramebufferConfig.virtual_width == sFramebufferConfig.width + && sFramebufferConfig.virtual_height == sFramebufferConfig.height + && sFramebufferConfig.bits_per_pixel == (uint32)depth + && sFramebufferConfig.bytes_per_row + >= sFramebufferConfig.bits_per_pixel / 8 + * sFramebufferConfig.width + && sFramebufferConfig.screen_size >= sFramebufferConfig.bytes_per_row + * sFramebufferConfig.height); + +#if 1 + fBase = BCM2708_BUS_TO_PHYSICAL(sFramebufferConfig.frame_buffer_address); +#else + // TODO: Enable when the MMU works. + fBase = (addr_t)mmu_map_physical_memory( + BCM2708_BUS_TO_PHYSICAL(sFramebufferConfig.frame_buffer_address), + sFramebufferConfig.screen_size, MMU_L2_FLAG_AP_RW | MMU_L2_FLAG_C); +#endif + + uint8* line = (uint8*)fBase; + for (uint32 y = 0; y < sFramebufferConfig.height; y++) { + volatile uint16* pixel = (volatile uint16*)line; + for (uint32 x = 0; x < sFramebufferConfig.width; x++) + *(pixel++) = y % 2 == 0 ? 0xffff : 0x0000; + + line += sFramebufferConfig.bytes_per_row; + } + + fCurrentWidth = width; + fCurrentHeight = height; + fCurrentDepth = depth; + fCurrentBytesPerRow = sFramebufferConfig.bytes_per_row; + return B_OK; +} +