genode/os/src/drivers/framebuffer/pl11x/main.cc

226 lines
6.2 KiB
C++

/*
* \brief PL11x frame-buffer driver
* \author Norman Feske
* \author Stefan Kalkowski
* \date 2010-02-17
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <base/sleep.h>
#include <base/rpc_server.h>
#include <io_mem_session/connection.h>
#include <cap_session/connection.h>
#include <dataspace/client.h>
#include <timer_session/connection.h>
#include <framebuffer_session/framebuffer_session.h>
#include <root/component.h>
#include <os/ring_buffer.h>
/* device configuration */
#include <pl11x_defs.h>
#include <sp810_defs.h>
#include <video_memory.h>
/***********************************************
** Implementation of the framebuffer service **
***********************************************/
namespace Framebuffer
{
enum {
SCR_WIDTH = 640,
SCR_HEIGHT = 480,
LEFT_MARGIN = 64,
RIGHT_MARGIN = 32,
UPPER_MARGIN = 9,
LOWER_MARGIN = 11,
HSYNC_LEN = 64,
VSYNC_LEN = 25,
BYTES_PER_PIXEL = 2,
FRAMEBUFFER_SIZE = SCR_WIDTH*SCR_HEIGHT*BYTES_PER_PIXEL,
};
class Session_component : public Genode::Rpc_object<Session>
{
private:
Genode::Dataspace_capability _fb_ds_cap;
Genode::Dataspace_client _fb_ds;
Genode::addr_t _regs_base;
Genode::addr_t _sys_regs_base;
Timer::Connection _timer;
enum {
/**
* Bit definitions of the lcd control register
*/
CTRL_ENABLED = 1 << 0,
CTRL_BPP16 = 4 << 1,
CTRL_BPP16_565 = 6 << 1,
CTRL_TFT = 1 << 5,
CTRL_BGR = 1 << 8,
CTRL_POWER = 1 << 11,
CTRL_VCOMP = 1 << 12,
/**
* Bit definitions for CLCDC timing.
*/
CLCDC_IVS = 1 << 11,
CLCDC_IHS = 1 << 12,
CLCDC_BCD = 1 << 26,
};
void sys_reg_write(unsigned reg, long value) {
*(volatile long *)(_sys_regs_base + sizeof(long)*reg) = value; }
long sys_reg_read(unsigned reg) {
return *(volatile long *)(_sys_regs_base + sizeof(long)*reg); }
void reg_write(unsigned reg, long value) {
*(volatile long *)(_regs_base + sizeof(long)*reg) = value; }
long reg_read(unsigned reg) {
return *(volatile long *)(_regs_base + sizeof(long)*reg); }
public:
/**
* Constructor
*/
Session_component(void *regs_base, void *sys_regs_base,
Genode::Dataspace_capability fb_ds_cap)
: _fb_ds_cap(fb_ds_cap), _fb_ds(_fb_ds_cap),
_regs_base((Genode::addr_t)regs_base),
_sys_regs_base((Genode::addr_t)sys_regs_base)
{
using namespace Genode;
uint32_t tim0 = (SCR_WIDTH/16 - 1) << 2
| (HSYNC_LEN - 1) << 8
| (RIGHT_MARGIN - 1) << 16
| (LEFT_MARGIN - 1) << 24;
uint32_t tim1 = (SCR_HEIGHT - 1)
| (VSYNC_LEN - 1) << 10
| LOWER_MARGIN << 16
| UPPER_MARGIN << 24;
uint32_t tim2 = ((SCR_WIDTH - 1) << 16)
| CLCDC_IVS | CLCDC_IHS | CLCDC_BCD;
uint32_t tim3 = 0;
uint32_t ctrl = reg_read(PL11X_REG_CTRL);
/* reset video if already enabled */
if (ctrl & CTRL_POWER) {
ctrl &= ~CTRL_POWER;
reg_write(PL11X_REG_CTRL, ctrl);
_timer.msleep(100);
}
if (ctrl & CTRL_ENABLED) {
ctrl &= ~CTRL_ENABLED;
reg_write(PL11X_REG_CTRL, ctrl);
_timer.msleep(100);
}
ctrl = CTRL_BGR | CTRL_ENABLED | CTRL_TFT | CTRL_VCOMP | CTRL_BPP16_565;
/* init color-lcd oscillator */
sys_reg_write(SP810_REG_LOCK, 0xa05f);
sys_reg_write(SP810_REG_OSCCLCD, 0x2c77);
sys_reg_write(SP810_REG_LOCK, 0);
/* init video timing */
reg_write(PL11X_REG_TIMING0, tim0);
reg_write(PL11X_REG_TIMING1, tim1);
reg_write(PL11X_REG_TIMING2, tim2);
reg_write(PL11X_REG_TIMING3, tim3);
/* set framebuffer address and ctrl register */
reg_write(PL11X_REG_UPBASE, _fb_ds.phys_addr());
reg_write(PL11X_REG_LPBASE, 0);
reg_write(PL11X_REG_IMSC, 0);
reg_write(PL11X_REG_CTRL, ctrl);
_timer.msleep(100);
/* power on */
reg_write(PL11X_REG_CTRL, ctrl | CTRL_POWER);
}
Genode::Dataspace_capability dataspace() { return _fb_ds_cap; }
Mode mode() const { return Mode(SCR_WIDTH, SCR_HEIGHT, Mode::RGB565); }
void mode_sigh(Genode::Signal_context_capability) { }
void refresh(int x, int y, int w, int h) { }
};
class Root : public Genode::Root_component<Session_component>
{
private:
void *_lcd_regs_base;
void *_sys_regs_base;
Genode::Dataspace_capability _fb_ds_cap;
protected:
Session_component *_create_session(const char *args) {
return new (md_alloc()) Session_component(_lcd_regs_base,
_sys_regs_base,
_fb_ds_cap); }
public:
Root(Genode::Rpc_entrypoint *session_ep, Genode::Allocator *md_alloc,
void *lcd_regs_base, void *sys_regs_base,
Genode::Dataspace_capability fb_ds_cap)
: Genode::Root_component<Session_component>(session_ep, md_alloc),
_lcd_regs_base(lcd_regs_base), _sys_regs_base(sys_regs_base),
_fb_ds_cap(fb_ds_cap) { }
};
}
using namespace Genode;
int main(int, char **)
{
printf("--- pl11x framebuffer driver ---\n");
/* locally map LCD control registers */
Io_mem_connection lcd_io_mem(PL11X_LCD_PHYS, PL11X_LCD_SIZE);
void *lcd_base = env()->rm_session()->attach(lcd_io_mem.dataspace());
/* locally map system control registers */
Io_mem_connection sys_mem(SP810_PHYS, SP810_SIZE);
void *sys_base = env()->rm_session()->attach(sys_mem.dataspace());
enum { STACK_SIZE = 4096 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "fb_ep");
Dataspace_capability fb_ds_cap =
Framebuffer::alloc_video_memory(Framebuffer::FRAMEBUFFER_SIZE);
/*
* Let the entry point serve the framebuffer and input root interfaces
*/
static Framebuffer::Root fb_root(&ep, env()->heap(), lcd_base, sys_base, fb_ds_cap);
env()->parent()->announce(ep.manage(&fb_root));
sleep_forever();
return 0;
}