diff --git a/os/src/drivers/framebuffer/omap4/driver.h b/os/src/drivers/framebuffer/omap4/driver.h new file mode 100644 index 000000000..c3903fe27 --- /dev/null +++ b/os/src/drivers/framebuffer/omap4/driver.h @@ -0,0 +1,246 @@ +/* + * \brief Frame-buffer driver for the OMAP4430 display-subsystem (HDMI) + * \author Norman Feske + * \author Martin Stein + * \date 2012-06-01 + */ + +/* + * Copyright (C) 2012 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 +#include + +/* local includes */ +#include +#include +#include +#include + + +namespace Framebuffer { + using namespace Genode; + class Driver; +} + + +class Framebuffer::Driver +{ + public: + + enum Mode { MODE_1024_768 }; + enum Format { FORMAT_RGB565 }; + + private: + + struct Timer_delayer : Timer::Connection, Delayer + { + /** + * Implementation of 'Delayer' interface + */ + void usleep(unsigned us) + { + /* polling */ + if (us == 0) + return; + + unsigned ms = us / 1000; + if (ms == 0) + ms = 1; + + Timer::Connection::msleep(ms); + } + } _delayer; + + /* memory map */ + enum { + DSS_MMIO_BASE = 0x58000000, + DSS_MMIO_SIZE = 0x00001000, + + DISPC_MMIO_BASE = 0x58001000, + DISPC_MMIO_SIZE = 0x1000, + + HDMI_MMIO_BASE = 0x58006000, + HDMI_MMIO_SIZE = 0x1000, + }; + + /* display sub system registers */ + Attached_io_mem_dataspace _dss_mmio; + Dss _dss; + + /* display controller registers */ + Attached_io_mem_dataspace _dispc_mmio; + Dispc _dispc; + + /* HDMI controller registers */ + Attached_io_mem_dataspace _hdmi_mmio; + Hdmi _hdmi; + + public: + + Driver(); + + static size_t bytes_per_pixel(Format format) + { + switch (format) { + case FORMAT_RGB565: return 2; + } + return 0; + } + + static size_t width(Mode mode) + { + switch (mode) { + case MODE_1024_768: return 1024; + } + return 0; + } + + static size_t height(Mode mode) + { + 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); +}; + + +Framebuffer::Driver::Driver() +: + _dss_mmio(DSS_MMIO_BASE, DSS_MMIO_SIZE), + _dss((addr_t)_dss_mmio.local_addr()), + + _dispc_mmio(DISPC_MMIO_BASE, DISPC_MMIO_SIZE), + _dispc((addr_t)_dispc_mmio.local_addr()), + + _hdmi_mmio(HDMI_MMIO_BASE, HDMI_MMIO_SIZE), + _hdmi((addr_t)_hdmi_mmio.local_addr()) +{ } + + +bool Framebuffer::Driver::init(Framebuffer::Driver::Mode mode, + Framebuffer::Driver::Format format, + Framebuffer::addr_t phys_base) +{ + /* enable display core clock and set divider to 1 */ + _dispc.write(1); + _dispc.write(1); + + /* set load mode */ + _dispc.write(Dispc::Config1::Load_mode::DATA_EVERY_FRAME); + + _hdmi.write(0); + + if (!_hdmi.issue_pwr_pll_command(Hdmi::Pwr_ctrl::ALL_OFF, _delayer)) { + PERR("Powering off HDMI timed out\n"); + return false; + } + + if (!_hdmi.issue_pwr_pll_command(Hdmi::Pwr_ctrl::BOTH_ON_ALL_CLKS, _delayer)) { + PERR("Powering on HDMI timed out\n"); + return false; + } + + if (!_hdmi.reset_pll(_delayer)) { + PERR("Resetting HDMI PLL timed out\n"); + return false; + } + + _hdmi.write(Hdmi::Pll_control::Mode::MANUAL); + + _hdmi.write(270); + _hdmi.write(15); + + _hdmi.write(0); + _hdmi.write(1); + _hdmi.write(0); + _hdmi.write(3); + _hdmi.write(2); + + _hdmi.write(1); + _hdmi.write(0x35555); + + if (!_hdmi.pll_go(_delayer)) { + PERR("HDMI PLL GO timed out"); + return false; + } + + if (!_hdmi.issue_pwr_phy_command(Hdmi::Pwr_ctrl::LDOON, _delayer)) { + PERR("HDMI Phy power on timed out"); + return false; + } + + _hdmi.write(1); + _hdmi.write(0xf0000000); + + if (!_hdmi.issue_pwr_phy_command(Hdmi::Pwr_ctrl::TXON, _delayer)) { + PERR("HDMI Txphy power on timed out"); + return false; + } + + _hdmi.write(160); + _hdmi.write(24); + _hdmi.write(136); + + _hdmi.write(29); + _hdmi.write(3); + _hdmi.write(6); + + _hdmi.write(Hdmi::Video_cfg::Packing_mode::PACK_24B); + + _hdmi.write(width(mode)); + _hdmi.write(height(mode)); + + _hdmi.write(0); + _hdmi.write(0); + _hdmi.write(0); + _hdmi.write(1); + + _dss.write(Dss::Ctrl::Venc_hdmi_switch::HDMI); + + _dispc.write(width(mode) - 1); + _dispc.write(height(mode) - 1); + + _hdmi.write(1); + + Dispc::Gfx_attributes::access_t pixel_format = 0; + switch (format) { + case FORMAT_RGB565: pixel_format = Dispc::Gfx_attributes::Format::RGB16; break; + } + _dispc.write(pixel_format); + + _dispc.write(phys_base); + + _dispc.write(width(mode) - 1); + _dispc.write(height(mode) - 1); + + _dispc.write(0x6d2240); + _dispc.write(1); + + _dispc.write(Dispc::Gfx_attributes::Channelout::TV); + _dispc.write(Dispc::Gfx_attributes::Channelout2::PRIMARY_LCD); + + _dispc.write(1); + + _dispc.write(1); + + if (!_dispc.wait_for(Dispc::Control1::Go_tv::HW_UPDATE_DONE, _delayer)) { + PERR("Go_tv timed out"); + return false; + } + + return true; +} diff --git a/os/src/drivers/framebuffer/omap4/main.cc b/os/src/drivers/framebuffer/omap4/main.cc index 38b64afd1..1f0718d54 100644 --- a/os/src/drivers/framebuffer/omap4/main.cc +++ b/os/src/drivers/framebuffer/omap4/main.cc @@ -1,8 +1,7 @@ /* * \brief Frame-buffer driver for the OMAP4430 display-subsystem (HDMI) * \author Norman Feske - * \author Martin Stein - * \date 2012-06-01 + * \date 2012-06-21 */ /* @@ -14,8 +13,6 @@ /* Genode includes */ #include -#include -#include #include #include #include @@ -23,186 +20,130 @@ #include /* local includes */ -#include -#include -#include -#include +#include + + +/** + * Root interface that hands out a statically created session + */ +template +class Static_root : public Genode::Rpc_object > +{ + private: + + typedef Genode::Capability Session_capability; + + Session_capability _session; + + public: + + /** + * Constructor + * + * \param session session to be provided to the client + */ + Static_root(Session_capability session) : _session(session) { } + + + /******************** + ** Root interface ** + ********************/ + + Genode::Session_capability session(Genode::Root::Session_args const &args) { return _session; } + void upgrade(Genode::Session_capability, Genode::Root::Upgrade_args const &) { } + void close(Genode::Session_capability) { } +}; + + +namespace Framebuffer { + using namespace Genode; + class Session_component; +}; + + +class Framebuffer::Session_component : public Genode::Rpc_object +{ + private: + + Driver::Mode _mode; + Driver::Format _format; + size_t _size; + Dataspace_capability _ds; + addr_t _phys_base; + + /** + * Convert Driver::Format to Framebuffer::Mode::Format + */ + static Mode::Format _convert_format(Driver::Format driver_format) + { + switch (driver_format) { + case Driver::FORMAT_RGB565: return Mode::RGB565; + } + return Mode::INVALID; + } + + public: + + Session_component(Driver &driver) + : + _mode(Driver::MODE_1024_768), + _format(Driver::FORMAT_RGB565), + _size(Driver::buffer_size(_mode, _format)), + _ds(env()->ram_session()->alloc(_size, false)), + _phys_base(Dataspace_client(_ds).phys_addr()) + { + if (!driver.init(_mode, _format, _phys_base)) { + PERR("Could not initialize display"); + struct Could_not_initialize_display : Exception { }; + throw Could_not_initialize_display(); + } + } + + /************************************ + ** Framebuffer::Session interface ** + ************************************/ + + Dataspace_capability dataspace() { return _ds; } + + void release() { } + + Mode mode() const + { + return Mode(Driver::width(_mode), + Driver::height(_mode), + _convert_format(_format)); + } + + void mode_sigh(Genode::Signal_context_capability) { } + + void refresh(int, int, int, int) { } +}; int main(int, char **) { - using namespace Genode; - printf("--- omap44xx framebuffer driver ---\n"); + using namespace Framebuffer; - struct Timer_delayer : Timer::Connection, Delayer - { - /** - * Implementation of 'Delayer' interface - */ - void usleep(unsigned us) - { - /* polling */ - if (us == 0) - return; - - unsigned ms = us / 1000; - if (ms == 0) - ms = 1; - - Timer::Connection::msleep(ms); - } - }; - - static Timer_delayer delayer; - - /* memory map */ - enum { - DSS_MMIO_BASE = 0x58000000, - DSS_MMIO_SIZE = 0x00001000, - - DISPC_MMIO_BASE = 0x58001000, - DISPC_MMIO_SIZE = 0x1000, - - HDMI_MMIO_BASE = 0x58006000, - HDMI_MMIO_SIZE = 0x1000, - }; + static Driver driver; /* - * Obtain MMIO resources + * Initialize server entry point */ + enum { STACK_SIZE = 4096 }; + static Cap_connection cap; + static Rpc_entrypoint ep(&cap, STACK_SIZE, "fb_ep"); - /* display sub system registers */ - Attached_io_mem_dataspace dss_mmio(DSS_MMIO_BASE, DSS_MMIO_SIZE); - Dss dss((addr_t)dss_mmio.local_addr()); + /* + * Let the entry point serve the framebuffer session and root interfaces + */ + static Session_component fb_session(driver); + static Static_root fb_root(ep.manage(&fb_session)); - /* display controller registers */ - Attached_io_mem_dataspace dispc_mmio(DISPC_MMIO_BASE, DISPC_MMIO_SIZE); - Dispc dispc((addr_t)dispc_mmio.local_addr()); + /* + * Announce service + */ + env()->parent()->announce(ep.manage(&fb_root)); - /* HDMI controller registers */ - Attached_io_mem_dataspace hdmi_mmio(HDMI_MMIO_BASE, HDMI_MMIO_SIZE); - Hdmi hdmi((addr_t)hdmi_mmio.local_addr()); - - /* enable display core clock and set divider to 1 */ - dispc.write(1); - dispc.write(1); - - /* set load mode */ - dispc.write(Dispc::Config1::Load_mode::DATA_EVERY_FRAME); - - hdmi.write(0); - - if (!hdmi.issue_pwr_pll_command(Hdmi::Pwr_ctrl::ALL_OFF, delayer)) { - PERR("Powering off HDMI timed out\n"); - return 1; - } - - if (!hdmi.issue_pwr_pll_command(Hdmi::Pwr_ctrl::BOTH_ON_ALL_CLKS, delayer)) { - PERR("Powering on HDMI timed out\n"); - return 2; - } - - if (!hdmi.reset_pll(delayer)) { - PERR("Resetting HDMI PLL timed out\n"); - return 3; - } - - hdmi.write(Hdmi::Pll_control::Mode::MANUAL); - - hdmi.write(270); - hdmi.write(15); - - hdmi.write(0); - hdmi.write(1); - hdmi.write(0); - hdmi.write(3); - hdmi.write(2); - - hdmi.write(1); - hdmi.write(0x35555); - - if (!hdmi.pll_go(delayer)) { - PERR("HDMI PLL GO timed out"); - return 4; - } - - if (!hdmi.issue_pwr_phy_command(Hdmi::Pwr_ctrl::LDOON, delayer)) { - PERR("HDMI Phy power on timed out"); - return 5; - } - - hdmi.write(1); - hdmi.write(0xf0000000); - - if (!hdmi.issue_pwr_phy_command(Hdmi::Pwr_ctrl::TXON, delayer)) { - PERR("HDMI Txphy power on timed out"); - return 6; - } - - hdmi.write(160); - hdmi.write(24); - hdmi.write(136); - - hdmi.write(29); - hdmi.write(3); - hdmi.write(6); - - hdmi.write(Hdmi::Video_cfg::Packing_mode::PACK_24B); - - hdmi.write(1024); - hdmi.write(768); - - hdmi.write(0); - hdmi.write(0); - hdmi.write(0); - hdmi.write(1); - - dss.write(Dss::Ctrl::Venc_hdmi_switch::HDMI); - - dispc.write(1024 - 1); - dispc.write(768 - 1); - - hdmi.write(1); - - dispc.write(Dispc::Gfx_attributes::Format::RGB16); - - typedef Genode::uint16_t pixel_t; - - Genode::Dataspace_capability fb_ds = - Genode::env()->ram_session()->alloc(1024*768*sizeof(pixel_t), false); - - Genode::addr_t fb_phys_base = Genode::Dataspace_client(fb_ds).phys_addr(); - - dispc.write(fb_phys_base); - - dispc.write(1024 - 1); - dispc.write(768 - 1); - - dispc.write(0x6d2240); - dispc.write(1); - - dispc.write(Dispc::Gfx_attributes::Channelout::TV); - dispc.write(Dispc::Gfx_attributes::Channelout2::PRIMARY_LCD); - - dispc.write(1); - - dispc.write(1); - - if (!dispc.wait_for(Dispc::Control1::Go_tv::HW_UPDATE_DONE, delayer)) { - PERR("Go_tv timed out"); - return 6; - } - - pixel_t *fb_local_base = Genode::env()->rm_session()->attach(fb_ds); - for (unsigned y = 0; y < 768; y++) { - for (unsigned x = 0; x < 1024; x++) { - fb_local_base[y*1024 + x] = (x & 0x1f); - fb_local_base[y*1024 + x] |= ((y) & 0x1f) << 11; - fb_local_base[y*1024 + x] |= ((x + y) & 0x3f) << 5; - } - } - - PINF("done"); sleep_forever(); return 0; }