Skip to content

Commit

Permalink
Add BCM2708 arch framebuffer implementation for rPi.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mmlr committed Nov 27, 2012
1 parent 57e6aff commit 8b95626
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/system/boot/platform/raspberrypi_arm/Jamfile
Expand Up @@ -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
Expand Down
181 changes: 181 additions & 0 deletions 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 <string.h>

#include <arm_mmu.h>

#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;
}

0 comments on commit 8b95626

Please sign in to comment.