diff --git a/os/run/framebuffer.run b/os/run/framebuffer.run index 08c9f6d0f..e4fce354f 100755 --- a/os/run/framebuffer.run +++ b/os/run/framebuffer.run @@ -60,7 +60,7 @@ append_if [have_spec omap4] config { - + } @@ -88,7 +88,7 @@ lappend_if [have_spec sdl] boot_modules fb_sdl lappend_if [have_spec pci] boot_modules pci_drv lappend_if [have_spec vesa] boot_modules vesa_drv lappend_if [have_spec pl11x] boot_modules pl11x_drv -lappend_if [have_spec omap4] boot_modules omap44xx_fb_drv +lappend_if [have_spec omap4] boot_modules omap4_fb_drv build_boot_image $boot_modules diff --git a/os/src/drivers/framebuffer/omap4/dispc.h b/os/src/drivers/framebuffer/omap4/dispc.h new file mode 100644 index 000000000..fa1a3ee0a --- /dev/null +++ b/os/src/drivers/framebuffer/omap4/dispc.h @@ -0,0 +1,111 @@ +/* + * \brief Display controller + * \author Martin Stein + * \author Norman Feske + * \date 2012-06-11 + */ + +#ifndef _DISPC_H_ +#define _DISPC_H_ + +/* local includes */ +#include + +struct Dispc : Mmio +{ + /** + * Configures the display controller module for outputs LCD 1 and TV + */ + struct Control1 : Register<0x40, 32> + { + struct Tv_enable : Bitfield<1, 1> { }; + + struct Go_tv : Bitfield<6, 1> + { + enum { HW_UPDATE_DONE = 0x0, /* set by HW after updating */ + REQUEST_HW_UPDATE = 0x1 }; /* must be set by user */ + }; + }; + + /** + * Configures the display controller module for outputs LCD 1 and TV + */ + struct Config1 : Register<0x44, 32> + { + /** + * Loading of palette/gamma table + */ + struct Load_mode : Bitfield<1, 2> + { + enum { DATA_EVERY_FRAME = 0x2, }; + }; + }; + + struct Size_tv : Register<0x78, 32> + { + struct Width : Bitfield<0, 11> { }; + struct Height : Bitfield<16, 11> { }; + }; + + /** + * Configures base address of the graphics buffer + */ + struct Gfx_ba1 : Register<0x80, 32> { }; + + /** + * Configures the size of the graphics window + */ + struct Gfx_size : Register<0x8c, 32> + { + struct Sizex : Bitfield<0,11> { }; + struct Sizey : Bitfield<16,11> { }; + }; + + /** + * Configures the graphics attributes + */ + struct Gfx_attributes : Register<0xa0, 32> + { + struct Enable : Bitfield<0, 1> { }; + + struct Format : Bitfield<1, 5> + { + enum { RGB16 = 0x6, + ARGB32 = 0xc, + RGBA32 = 0xd }; + }; + + /** + * Select GFX channel output + */ + struct Channelout : Bitfield<8, 1> + { + enum { TV = 0x1 }; + }; + + struct Channelout2 : Bitfield<30, 2> + { + enum { PRIMARY_LCD = 0 }; + }; + }; + + struct Global_buffer : Register<0x800, 32> { }; + + struct Divisor : Register<0x804, 32> + { + struct Enable : Bitfield<0, 1> { }; + struct Lcd : Bitfield<16, 8> { }; + }; + + /** + * Constructor + * + * \param mmio_base base address of DISPC MMIO + */ + Dispc(Genode::addr_t const mmio_base) + : + Mmio(mmio_base) + { } +}; + +#endif /* _DISPC_H_ */ diff --git a/os/src/drivers/framebuffer/omap4/dss.h b/os/src/drivers/framebuffer/omap4/dss.h new file mode 100644 index 000000000..3090ea160 --- /dev/null +++ b/os/src/drivers/framebuffer/omap4/dss.h @@ -0,0 +1,29 @@ +/* + * \brief General display subsystem registers + * \author Norman Feske + * \date 2012-06-11 + */ + +#ifndef _DSS_H_ +#define _DSS_H_ + +/* local includes */ +#include + +struct Dss : Genode::Mmio +{ + Dss(Genode::addr_t const mmio_base) : Genode::Mmio(mmio_base) { } + + struct Sysstatus : Register<0x14, 32> { }; + + struct Ctrl : Register<0x40, 32> + { + struct Venc_hdmi_switch : Bitfield<15, 1> + { + enum { HDMI = 1 }; + }; + }; + struct Status : Register<0x5c, 32> { }; +}; + +#endif /* _DSS_H_ */ diff --git a/os/src/drivers/framebuffer/omap4/hdmi.h b/os/src/drivers/framebuffer/omap4/hdmi.h new file mode 100644 index 000000000..d153e7496 --- /dev/null +++ b/os/src/drivers/framebuffer/omap4/hdmi.h @@ -0,0 +1,156 @@ +/* + * \brief HDMI subsystem registers + * \author Norman Feske + * \date 2012-06-11 + */ + +#ifndef _HDMI_H_ +#define _HDMI_H_ + +/* local includes */ +#include + +struct Hdmi : Mmio +{ + struct Pwr_ctrl : Register<0x40, 32> + { + enum Pll_cmd_type { ALL_OFF = 0, + BOTH_ON_ALL_CLKS = 2, }; + + struct Pll_cmd : Bitfield<2, 2> { }; + struct Pll_status : Bitfield<0, 2> { }; + + enum Phy_cmd_type { LDOON = 1, + TXON = 2 }; + + struct Phy_cmd : Bitfield<6, 2> { }; + struct Phy_status : Bitfield<4, 2> { }; + + }; + + struct Video_cfg : Register<0x50, 32> + { + struct Start : Bitfield<31, 1> { }; + + struct Packing_mode : Bitfield<8, 3> + { + enum { PACK_24B = 1 }; + }; + + struct Vsp : Bitfield<7, 1> { }; + struct Hsp : Bitfield<6, 1> { }; + struct Interlacing : Bitfield<3, 1> { }; + struct Tm : Bitfield<0, 2> { }; + }; + + struct Video_size : Register<0x60, 32> + { + struct X : Bitfield<0, 16> { }; + struct Y : Bitfield<16, 16> { }; + }; + + struct Video_timing_h : Register<0x68, 32> + { + struct Bp : Bitfield<20, 12> { }; + struct Fp : Bitfield<8, 12> { }; + struct Sw : Bitfield<0, 8> { }; + }; + + struct Video_timing_v : Register<0x6c, 32> + { + struct Bp : Bitfield<20, 12> { }; + struct Fp : Bitfield<8, 12> { }; + struct Sw : Bitfield<0, 8> { }; + }; + + /** + * \return true on success + */ + bool issue_pwr_pll_command(Pwr_ctrl::Pll_cmd_type cmd, Delayer &delayer) + { + write(cmd); + + return wait_for(cmd, delayer); + } + + bool issue_pwr_phy_command(Pwr_ctrl::Phy_cmd_type cmd, Delayer &delayer) + { + write(cmd); + + return wait_for(cmd, delayer); + } + + struct Pll_control : Register<0x200, 32> + { + struct Mode : Bitfield<0, 1> + { + enum { MANUAL = 0 }; + }; + + struct Reset : Bitfield<3, 1> { }; + }; + + struct Pll_status : Register<0x204, 32> + { + struct Reset_done : Bitfield<0, 1> { }; + struct Pll_locked : Bitfield<1, 1> { }; + }; + + bool wait_until_pll_locked(Delayer &delayer) + { + return wait_for(1, delayer); + }; + + struct Pll_go : Register<0x208, 32> + { + struct Go : Bitfield<0, 1> { }; + }; + + bool pll_go(Delayer &delayer) + { + write(1); + + /* wait for PLL_GO bit change and the PLL reaching locked state */ + return wait_for(1, delayer) + && wait_until_pll_locked(delayer); + } + + struct Cfg1 : Register<0x20c, 32> + { + struct Regm : Bitfield<9, 12> { }; + struct Regn : Bitfield<1, 8> { }; + }; + + struct Cfg2 : Register<0x210, 32> + { + struct Highfreq_div_by_2 : Bitfield<12, 1> { }; + struct Refen : Bitfield<13, 1> { }; + struct Clkinen : Bitfield<14, 1> { }; + struct Refsel : Bitfield<21, 2> { }; + struct Freq_divider : Bitfield<1, 3> { }; + }; + + struct Cfg4 : Register<0x220, 32> + { + struct Regm2 : Bitfield<18, 7> { }; + struct Regmf : Bitfield<0, 18> { }; + }; + + bool reset_pll(Delayer &delayer) + { + write(0); + + return wait_for(1, delayer); + }; + + struct Txphy_tx_ctrl : Register<0x300, 32> + { + struct Freqout : Bitfield<30, 2> { }; + }; + + struct Txphy_digital_ctrl : Register<0x304, 32> { }; + + Hdmi(Genode::addr_t const mmio_base) : Mmio(mmio_base) { } +}; + +#endif /* _HDMI_H_ */ diff --git a/os/src/drivers/framebuffer/omap4/main.cc b/os/src/drivers/framebuffer/omap4/main.cc new file mode 100644 index 000000000..38b64afd1 --- /dev/null +++ b/os/src/drivers/framebuffer/omap4/main.cc @@ -0,0 +1,209 @@ +/* + * \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 +#include +#include +#include +#include +#include +#include + +/* local includes */ +#include +#include +#include +#include + + +int main(int, char **) +{ + using namespace Genode; + printf("--- omap44xx framebuffer driver ---\n"); + + 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, + }; + + /* + * Obtain MMIO resources + */ + + /* display sub system registers */ + Attached_io_mem_dataspace dss_mmio(DSS_MMIO_BASE, DSS_MMIO_SIZE); + Dss dss((addr_t)dss_mmio.local_addr()); + + /* display controller registers */ + Attached_io_mem_dataspace dispc_mmio(DISPC_MMIO_BASE, DISPC_MMIO_SIZE); + Dispc dispc((addr_t)dispc_mmio.local_addr()); + + /* 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; +} + diff --git a/os/src/drivers/framebuffer/omap4/mmio.h b/os/src/drivers/framebuffer/omap4/mmio.h new file mode 100644 index 000000000..2166b5849 --- /dev/null +++ b/os/src/drivers/framebuffer/omap4/mmio.h @@ -0,0 +1,42 @@ +/* + * \brief Utilities for accessing MMIO registers + * \author Norman Feske + * \date 2012-06-15 + */ + +#ifndef _MMIO_H_ +#define _MMIO_H_ + +#include + +/* Genode includes */ +#include + +struct Delayer +{ + virtual void usleep(unsigned us) = 0; +}; + +/** + * Extend 'Genode::Mmio' framework with the ability to poll for bitfield states + */ +struct Mmio : Genode::Mmio +{ + template + inline bool wait_for(typename BITFIELD::Compound_reg::access_t const value, + Delayer &delayer, + unsigned max_attempts = 500, + unsigned delay_us = 1000) + { + for (unsigned i = 0; i < max_attempts; i++, delayer.usleep(delay_us)) + if (read() == value) + return true; + + return false; + } + + Mmio(Genode::addr_t mmio_base) : Genode::Mmio(mmio_base) { } +}; + + +#endif /* _MMIO_H_ */ diff --git a/os/src/drivers/framebuffer/omap4/target.mk b/os/src/drivers/framebuffer/omap4/target.mk new file mode 100644 index 000000000..378aa2c82 --- /dev/null +++ b/os/src/drivers/framebuffer/omap4/target.mk @@ -0,0 +1,14 @@ +# +# \brief Framebuffer driver specific for OMAP44xx systems +# \author Martin Stein +# \date 2012-05-02 +# + +TARGET = omap4_fb_drv +REQUIRES = omap4 +SRC_CC = main.cc +LIBS = cxx env server +INC_DIR += $(PRG_DIR) + +vpath main.cc $(PRG_DIR) +