Implement LCD output and config parsing for omap4

Fixes #743
This commit is contained in:
Alexander Tarasikov 2013-05-11 08:51:26 +04:00 committed by Norman Feske
parent ee28a69c98
commit 3cb6de2e69
3 changed files with 129 additions and 42 deletions

View File

@ -18,8 +18,13 @@ struct Dispc : Genode::Mmio
*/ */
struct Control1 : Register<0x40, 32> struct Control1 : Register<0x40, 32>
{ {
struct Lcd_enable : Bitfield<0, 1> { };
struct Tv_enable : Bitfield<1, 1> { }; struct Tv_enable : Bitfield<1, 1> { };
struct Go_lcd : Bitfield<5, 1>
{
enum { HW_UPDATE_DONE = 0x0, /* set by HW after updating */
REQUEST_HW_UPDATE = 0x1 }; /* must be set by user */
};
struct Go_tv : Bitfield<6, 1> struct Go_tv : Bitfield<6, 1>
{ {
enum { HW_UPDATE_DONE = 0x0, /* set by HW after updating */ enum { HW_UPDATE_DONE = 0x0, /* set by HW after updating */
@ -46,11 +51,17 @@ struct Dispc : Genode::Mmio
struct Width : Bitfield<0, 11> { }; struct Width : Bitfield<0, 11> { };
struct Height : Bitfield<16, 11> { }; struct Height : Bitfield<16, 11> { };
}; };
struct Size_lcd : Register<0x7c, 32>
{
struct Width : Bitfield<0, 11> { };
struct Height : Bitfield<16, 11> { };
};
/** /**
* Configures base address of the graphics buffer * Configures base address of the graphics buffer
*/ */
struct Gfx_ba1 : Register<0x80, 32> { }; struct Gfx_ba0 : Register<0x80, 32> { };
struct Gfx_ba1 : Register<0x84, 32> { };
/** /**
* Configures the size of the graphics window * Configures the size of the graphics window

View File

@ -34,11 +34,15 @@ class Framebuffer::Driver
{ {
public: public:
enum Mode { MODE_1024_768 };
enum Format { FORMAT_RGB565 }; enum Format { FORMAT_RGB565 };
enum Output { OUTPUT_LCD, OUTPUT_HDMI };
private: private:
bool _init_lcd(addr_t phys_base);
bool _init_hdmi(addr_t phys_base);
struct Timer_delayer : Timer::Connection, Mmio::Delayer struct Timer_delayer : Timer::Connection, Mmio::Delayer
{ {
/** /**
@ -62,6 +66,10 @@ class Framebuffer::Driver
Attached_io_mem_dataspace _hdmi_mmio; Attached_io_mem_dataspace _hdmi_mmio;
Hdmi _hdmi; Hdmi _hdmi;
size_t _fb_width;
size_t _fb_height;
Format _fb_format;
public: public:
Driver(); Driver();
@ -74,28 +82,13 @@ class Framebuffer::Driver
return 0; return 0;
} }
static size_t width(Mode mode) size_t buffer_size(size_t width, size_t height, Format format)
{ {
switch (mode) { return bytes_per_pixel(format)*width*height;
case MODE_1024_768: return 1024;
}
return 0;
} }
static size_t height(Mode mode) bool init(size_t width, size_t height, Format format,
{ Output output, addr_t phys_base);
switch (mode) {
case MODE_1024_768: return 768;
}
return 0;
}
static size_t buffer_size(Mode mode, Format format)
{
return bytes_per_pixel(format)*width(mode)*height(mode);
}
bool init(Mode mode, Format format, addr_t phys_base);
}; };
@ -108,13 +101,47 @@ Framebuffer::Driver::Driver()
_dispc((addr_t)_dispc_mmio.local_addr<void>()), _dispc((addr_t)_dispc_mmio.local_addr<void>()),
_hdmi_mmio(Board_base::HDMI_MMIO_BASE, Board_base::HDMI_MMIO_SIZE), _hdmi_mmio(Board_base::HDMI_MMIO_BASE, Board_base::HDMI_MMIO_SIZE),
_hdmi((addr_t)_hdmi_mmio.local_addr<void>()) _hdmi((addr_t)_hdmi_mmio.local_addr<void>()),
_fb_width(0),
_fb_height(0),
_fb_format(FORMAT_RGB565)
{ } { }
bool Framebuffer::Driver::init(Framebuffer::Driver::Mode mode, bool Framebuffer::Driver::_init_lcd(Framebuffer::addr_t phys_base)
Framebuffer::Driver::Format format, {
Framebuffer::addr_t phys_base) /* disable LCD to allow editing configuration */
_dispc.write<Dispc::Control1::Lcd_enable>(0);
/* set load mode */
_dispc.write<Dispc::Config1::Load_mode>(Dispc::Config1::Load_mode::DATA_EVERY_FRAME);
_dispc.write<Dispc::Size_lcd::Width>(_fb_width - 1);
_dispc.write<Dispc::Size_lcd::Height>(_fb_height - 1);
Dispc::Gfx_attributes::access_t pixel_format = 0;
switch (_fb_format) {
case FORMAT_RGB565: pixel_format = Dispc::Gfx_attributes::Format::RGB16; break;
}
_dispc.write<Dispc::Gfx_attributes::Format>(pixel_format);
_dispc.write<Dispc::Gfx_ba0>(phys_base);
_dispc.write<Dispc::Gfx_ba1>(phys_base);
_dispc.write<Dispc::Gfx_size::Sizex>(_fb_width - 1);
_dispc.write<Dispc::Gfx_size::Sizey>(_fb_height - 1);
_dispc.write<Dispc::Global_buffer>(0x6d2240);
_dispc.write<Dispc::Gfx_attributes::Enable>(1);
_dispc.write<Dispc::Control1::Lcd_enable>(1);
_dispc.write<Dispc::Control1::Go_lcd>(1);
return true;
}
bool Framebuffer::Driver::_init_hdmi(Framebuffer::addr_t phys_base)
{ {
/* enable display core clock and set divider to 1 */ /* enable display core clock and set divider to 1 */
_dispc.write<Dispc::Divisor::Lcd>(1); _dispc.write<Dispc::Divisor::Lcd>(1);
@ -182,8 +209,8 @@ bool Framebuffer::Driver::init(Framebuffer::Driver::Mode mode,
_hdmi.write<Hdmi::Video_cfg::Packing_mode>(Hdmi::Video_cfg::Packing_mode::PACK_24B); _hdmi.write<Hdmi::Video_cfg::Packing_mode>(Hdmi::Video_cfg::Packing_mode::PACK_24B);
_hdmi.write<Hdmi::Video_size::X>(width(mode)); _hdmi.write<Hdmi::Video_size::X>(_fb_height);
_hdmi.write<Hdmi::Video_size::Y>(height(mode)); _hdmi.write<Hdmi::Video_size::Y>(_fb_width);
_hdmi.write<Hdmi::Video_cfg::Vsp>(0); _hdmi.write<Hdmi::Video_cfg::Vsp>(0);
_hdmi.write<Hdmi::Video_cfg::Hsp>(0); _hdmi.write<Hdmi::Video_cfg::Hsp>(0);
@ -192,21 +219,22 @@ bool Framebuffer::Driver::init(Framebuffer::Driver::Mode mode,
_dss.write<Dss::Ctrl::Venc_hdmi_switch>(Dss::Ctrl::Venc_hdmi_switch::HDMI); _dss.write<Dss::Ctrl::Venc_hdmi_switch>(Dss::Ctrl::Venc_hdmi_switch::HDMI);
_dispc.write<Dispc::Size_tv::Width>(width(mode) - 1); _dispc.write<Dispc::Size_tv::Width>(_fb_width - 1);
_dispc.write<Dispc::Size_tv::Height>(height(mode) - 1); _dispc.write<Dispc::Size_tv::Height>(_fb_height - 1);
_hdmi.write<Hdmi::Video_cfg::Start>(1); _hdmi.write<Hdmi::Video_cfg::Start>(1);
Dispc::Gfx_attributes::access_t pixel_format = 0; Dispc::Gfx_attributes::access_t pixel_format = 0;
switch (format) { switch (_fb_format) {
case FORMAT_RGB565: pixel_format = Dispc::Gfx_attributes::Format::RGB16; break; case FORMAT_RGB565: pixel_format = Dispc::Gfx_attributes::Format::RGB16; break;
} }
_dispc.write<Dispc::Gfx_attributes::Format>(pixel_format); _dispc.write<Dispc::Gfx_attributes::Format>(pixel_format);
_dispc.write<Dispc::Gfx_ba0>(phys_base);
_dispc.write<Dispc::Gfx_ba1>(phys_base); _dispc.write<Dispc::Gfx_ba1>(phys_base);
_dispc.write<Dispc::Gfx_size::Sizex>(width(mode) - 1); _dispc.write<Dispc::Gfx_size::Sizex>(_fb_width - 1);
_dispc.write<Dispc::Gfx_size::Sizey>(height(mode) - 1); _dispc.write<Dispc::Gfx_size::Sizey>(_fb_height - 1);
_dispc.write<Dispc::Global_buffer>(0x6d2240); _dispc.write<Dispc::Global_buffer>(0x6d2240);
_dispc.write<Dispc::Gfx_attributes::Enable>(1); _dispc.write<Dispc::Gfx_attributes::Enable>(1);
@ -215,7 +243,6 @@ bool Framebuffer::Driver::init(Framebuffer::Driver::Mode mode,
_dispc.write<Dispc::Gfx_attributes::Channelout2>(Dispc::Gfx_attributes::Channelout2::PRIMARY_LCD); _dispc.write<Dispc::Gfx_attributes::Channelout2>(Dispc::Gfx_attributes::Channelout2::PRIMARY_LCD);
_dispc.write<Dispc::Control1::Tv_enable>(1); _dispc.write<Dispc::Control1::Tv_enable>(1);
_dispc.write<Dispc::Control1::Go_tv>(1); _dispc.write<Dispc::Control1::Go_tv>(1);
if (!_dispc.wait_for<Dispc::Control1::Go_tv>(Dispc::Control1::Go_tv::HW_UPDATE_DONE, _delayer)) { if (!_dispc.wait_for<Dispc::Control1::Go_tv>(Dispc::Control1::Go_tv::HW_UPDATE_DONE, _delayer)) {
@ -225,3 +252,27 @@ bool Framebuffer::Driver::init(Framebuffer::Driver::Mode mode,
return true; return true;
} }
bool Framebuffer::Driver::init(size_t width, size_t height,
Framebuffer::Driver::Format format,
Output output,
Framebuffer::addr_t phys_base)
{
_fb_width = width;
_fb_height = height;
_fb_format = format;
bool ret = false;
switch (output) {
case OUTPUT_LCD:
ret = _init_lcd(phys_base);
break;
case OUTPUT_HDMI:
ret = _init_hdmi(phys_base);
break;
default:
PERR("Unknown output %d specified", output);
}
return ret;
}

View File

@ -17,6 +17,7 @@
#include <dataspace/client.h> #include <dataspace/client.h>
#include <base/printf.h> #include <base/printf.h>
#include <base/sleep.h> #include <base/sleep.h>
#include <os/config.h>
#include <os/static_root.h> #include <os/static_root.h>
/* local includes */ /* local includes */
@ -33,7 +34,8 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Framebuffer::Se
{ {
private: private:
Driver::Mode _mode; size_t _width;
size_t _height;
Driver::Format _format; Driver::Format _format;
size_t _size; size_t _size;
Dataspace_capability _ds; Dataspace_capability _ds;
@ -52,15 +54,17 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Framebuffer::Se
public: public:
Session_component(Driver &driver) Session_component(Driver &driver, size_t width, size_t height,
Driver::Output output)
: :
_mode(Driver::MODE_1024_768), _width(width),
_height(height),
_format(Driver::FORMAT_RGB565), _format(Driver::FORMAT_RGB565),
_size(Driver::buffer_size(_mode, _format)), _size(driver.buffer_size(width, height, _format)),
_ds(env()->ram_session()->alloc(_size, false)), _ds(env()->ram_session()->alloc(_size, false)),
_phys_base(Dataspace_client(_ds).phys_addr()) _phys_base(Dataspace_client(_ds).phys_addr())
{ {
if (!driver.init(_mode, _format, _phys_base)) { if (!driver.init(width, height, _format, output, _phys_base)) {
PERR("Could not initialize display"); PERR("Could not initialize display");
struct Could_not_initialize_display : Exception { }; struct Could_not_initialize_display : Exception { };
throw Could_not_initialize_display(); throw Could_not_initialize_display();
@ -77,8 +81,8 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Framebuffer::Se
Mode mode() const Mode mode() const
{ {
return Mode(Driver::width(_mode), return Mode(_width,
Driver::height(_mode), _height,
_convert_format(_format)); _convert_format(_format));
} }
@ -92,6 +96,27 @@ int main(int, char **)
{ {
using namespace Framebuffer; using namespace Framebuffer;
size_t width = 1024;
size_t height = 768;
Driver::Output output = Driver::OUTPUT_HDMI;
try {
char out[5] = {};
Genode::Xml_node config_node = Genode::config()->xml_node();
config_node.attribute("width").value(&width);
config_node.attribute("height").value(&height);
config_node.attribute("output").value(out, sizeof(out));
if (!Genode::strcmp(out, "LCD")) {
output = Driver::OUTPUT_LCD;
}
}
catch (Genode::Xml_node::Nonexistent_attribute) {
PERR("incorrect configuration, aborting");
throw Root::Invalid_args();
}
catch (Genode::Xml_node::Nonexistent_sub_node) {
PDBG("using default configuration: HDMI@%dx%d", width, height);
}
static Driver driver; static Driver driver;
/* /*
@ -104,7 +129,7 @@ int main(int, char **)
/* /*
* Let the entry point serve the framebuffer session and root interfaces * Let the entry point serve the framebuffer session and root interfaces
*/ */
static Session_component fb_session(driver); static Session_component fb_session(driver, width, height, output);
static Static_root<Framebuffer::Session> fb_root(ep.manage(&fb_session)); static Static_root<Framebuffer::Session> fb_root(ep.manage(&fb_session));
/* /*