From 0950b2f34005e812d0d5029b31b0cad68c494674 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Tue, 30 Apr 2013 15:19:18 +0200 Subject: [PATCH] Rework i.MX53 framebuffer driver * Simplify IPU register definitions using templates * Distinguish between i.MX53 QSB and SMD board in driver * Support IPU specific overlay mechanism by framebuffer session extension --- .../platform/imx53/drivers/board_base.h | 6 + .../imx53/imx_framebuffer_session/client.h | 46 + .../imx_framebuffer_session/connection.h | 74 ++ .../imx_framebuffer_session.h | 48 ++ .../platform/imx53/platform_session/client.h | 1 + .../imx53/platform_session/platform_session.h | 15 +- os/src/drivers/framebuffer/imx53/driver.h | 69 +- os/src/drivers/framebuffer/imx53/ipu.h | 803 +++++++++++------- os/src/drivers/framebuffer/imx53/main.cc | 24 +- os/src/drivers/framebuffer/imx53/pwm.h | 36 + os/src/drivers/platform/imx53/ccm.h | 18 +- os/src/drivers/platform/imx53/iim.h | 39 + os/src/drivers/platform/imx53/iomux.h | 25 +- os/src/drivers/platform/imx53/main.cc | 27 +- 14 files changed, 894 insertions(+), 337 deletions(-) create mode 100644 os/include/platform/imx53/imx_framebuffer_session/client.h create mode 100644 os/include/platform/imx53/imx_framebuffer_session/connection.h create mode 100644 os/include/platform/imx53/imx_framebuffer_session/imx_framebuffer_session.h create mode 100644 os/src/drivers/framebuffer/imx53/pwm.h create mode 100644 os/src/drivers/platform/imx53/iim.h diff --git a/base/include/platform/imx53/drivers/board_base.h b/base/include/platform/imx53/drivers/board_base.h index 0799b39bd..1b8879f37 100644 --- a/base/include/platform/imx53/drivers/board_base.h +++ b/base/include/platform/imx53/drivers/board_base.h @@ -49,6 +49,9 @@ namespace Genode IOMUXC_BASE = 0x53fa8000, IOMUXC_SIZE = 0x00004000, + PWM2_BASE = 0x53fb8000, + PWM2_SIZE = 0x00004000, + IPU_ERR_IRQ = 10, IPU_SYNC_IRQ = 11, IPU_BASE = 0x18000000, @@ -60,6 +63,9 @@ namespace Genode CCM_BASE = 0x53FD4000, CCM_SIZE = 0x00004000, + IIM_BASE = 0x63f98000, + IIM_SIZE = 0x00004000, + SECURITY_EXTENSION = 1, }; }; diff --git a/os/include/platform/imx53/imx_framebuffer_session/client.h b/os/include/platform/imx53/imx_framebuffer_session/client.h new file mode 100644 index 000000000..384211675 --- /dev/null +++ b/os/include/platform/imx53/imx_framebuffer_session/client.h @@ -0,0 +1,46 @@ +/* + * \brief Client-side i.MX53 specific framebuffer interface + * \author Stefan Kalkowski + * \date 2013-02-26 + */ + +/* + * Copyright (C) 2006-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. + */ + +#ifndef _INCLUDE__IMX_FRAMEBUFFER_SESSION__CLIENT_H_ +#define _INCLUDE__IMX_FRAMEBUFFER_SESSION__CLIENT_H_ + +#include +#include +#include + +namespace Framebuffer { + + struct Imx_client : Genode::Rpc_client + { + explicit Imx_client(Capability session) + : Genode::Rpc_client(session) { } + + Genode::Dataspace_capability dataspace() { + return call(); } + + void release() { call(); } + + Mode mode() const { return call(); } + + void mode_sigh(Genode::Signal_context_capability sigh) { + call(sigh); } + + void refresh(int x, int y, int w, int h) { + call(x, y, w, h); } + + void overlay(Genode::addr_t phys_addr, int x, int y, int alpha) { + call(phys_addr, x, y, alpha); } + }; +} + +#endif /* _INCLUDE__IMX_FRAMEBUFFER_SESSION__CLIENT_H_ */ diff --git a/os/include/platform/imx53/imx_framebuffer_session/connection.h b/os/include/platform/imx53/imx_framebuffer_session/connection.h new file mode 100644 index 000000000..24855dda1 --- /dev/null +++ b/os/include/platform/imx53/imx_framebuffer_session/connection.h @@ -0,0 +1,74 @@ +/* + * \brief Connection to i.MX53 specific frame-buffer service + * \author Stefan Kalkowski + * \date 2013-02-26 + */ + +/* + * Copyright (C) 2008-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. + */ + +#ifndef _INCLUDE__IMX_FRAMEBUFFER_SESSION__CONNECTION_H_ +#define _INCLUDE__IMX_FRAMEBUFFER_SESSION__CONNECTION_H_ + +#include +#include +#include + +namespace Framebuffer { + + class Imx_connection : public Genode::Connection, + public Imx_client + { + private: + + /** + * Create session and return typed session capability + */ + Capability _connect(unsigned width, unsigned height, + Mode::Format format) + { + using namespace Genode; + + enum { ARGBUF_SIZE = 128 }; + char argbuf[ARGBUF_SIZE]; + + /* donate ram quota for storing server-side meta data */ + strncpy(argbuf, "ram_quota=8K", sizeof(argbuf)); + + /* set optional session-constructor arguments */ + if (width) + Arg_string::set_arg(argbuf, sizeof(argbuf), "fb_width", width); + if (height) + Arg_string::set_arg(argbuf, sizeof(argbuf), "fb_height", height); + if (format != Mode::INVALID) + Arg_string::set_arg(argbuf, sizeof(argbuf), "fb_format", format); + + return session(argbuf); + } + + public: + + /** + * Constructor + * + * \param width desired frame-buffer width + * \param height desired frame-buffer height + * \param mode desired pixel format + * + * The specified values are not enforced. After creating the + * session, you should validate the actual frame-buffer attributes + * by calling the 'info' function of the frame-buffer interface. + */ + Imx_connection(unsigned width = 0, + unsigned height = 0, + Mode::Format format = Mode::INVALID) + : Genode::Connection(_connect(width, height, format)), + Imx_client(cap()) { } + }; +} + +#endif /* _INCLUDE__IMX_FRAMEBUFFER_SESSION__CONNECTION_H_ */ diff --git a/os/include/platform/imx53/imx_framebuffer_session/imx_framebuffer_session.h b/os/include/platform/imx53/imx_framebuffer_session/imx_framebuffer_session.h new file mode 100644 index 000000000..873ebb3fb --- /dev/null +++ b/os/include/platform/imx53/imx_framebuffer_session/imx_framebuffer_session.h @@ -0,0 +1,48 @@ +/* + * \brief i.MX53 specific framebuffer session extension + * \author Stefan Kalkowski + * \date 2013-02-26 + */ + +/* + * Copyright (C) 2011-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. + */ + +#ifndef _INCLUDE__IMX_FRAMEBUFFER_SESSION__IMX_FRAMEBUFFER_SESSION_H_ +#define _INCLUDE__IMX_FRAMEBUFFER_SESSION__IMX_FRAMEBUFFER_SESSION_H_ + +#include +#include +#include + +namespace Framebuffer { + + struct Imx_session : Session + { + virtual ~Imx_session() { } + + /** + * Set overlay properties + * + * \param phys_base physical base address of overlay framebuffer + * \param x horizontal position in pixel + * \param y vertical position in pixel + * \param alpha alpha transparency value of overlay (0-255) + */ + virtual void overlay(Genode::addr_t phys_base, int x, int y, int alpha) = 0; + + + /********************* + ** RPC declaration ** + *********************/ + + GENODE_RPC(Rpc_overlay, void, overlay, Genode::addr_t, int, int, int); + + GENODE_RPC_INTERFACE_INHERIT(Session, Rpc_overlay); + }; +} + +#endif /* _INCLUDE__IMX_FRAMEBUFFER_SESSION__IMX_FRAMEBUFFER_SESSION_H_ */ diff --git a/os/include/platform/imx53/platform_session/client.h b/os/include/platform/imx53/platform_session/client.h index 40bcb872e..840c6df1a 100644 --- a/os/include/platform/imx53/platform_session/client.h +++ b/os/include/platform/imx53/platform_session/client.h @@ -29,6 +29,7 @@ namespace Platform { void disable(Device dev) { call(dev); } void clock_rate(Device dev, unsigned long rate) { call(dev, rate); } + Board_revision revision() { return call(); } }; } diff --git a/os/include/platform/imx53/platform_session/platform_session.h b/os/include/platform/imx53/platform_session/platform_session.h index 3223e6912..e30e8e634 100644 --- a/os/include/platform/imx53/platform_session/platform_session.h +++ b/os/include/platform/imx53/platform_session/platform_session.h @@ -23,13 +23,20 @@ namespace Platform { { enum Device { IPU }; + enum Board_revision { + SMD = 2, /* Freescale i.MX53 SMD Tablet */ + QSB = 3, /* Freescale i.MX53 low-cost Quickstart board */ + UNKNOWN, + }; + static const char *service_name() { return "Platform"; } virtual ~Session() { } - virtual void enable(Device dev) = 0; - virtual void disable(Device dev) = 0; + virtual void enable(Device dev) = 0; + virtual void disable(Device dev) = 0; virtual void clock_rate(Device dev, unsigned long rate) = 0; + virtual Board_revision revision() = 0; /********************* @@ -39,8 +46,10 @@ namespace Platform { GENODE_RPC(Rpc_enable, void, enable, Device); GENODE_RPC(Rpc_disable, void, disable, Device); GENODE_RPC(Rpc_clock_rate, void, clock_rate, Device, unsigned long); + GENODE_RPC(Rpc_revision, Board_revision, revision); - GENODE_RPC_INTERFACE(Rpc_enable, Rpc_disable, Rpc_clock_rate); + GENODE_RPC_INTERFACE(Rpc_enable, Rpc_disable, Rpc_clock_rate, + Rpc_revision); }; } diff --git a/os/src/drivers/framebuffer/imx53/driver.h b/os/src/drivers/framebuffer/imx53/driver.h index 1fdd46972..9a724d6bd 100644 --- a/os/src/drivers/framebuffer/imx53/driver.h +++ b/os/src/drivers/framebuffer/imx53/driver.h @@ -14,6 +14,7 @@ /* local includes */ #include +#include namespace Framebuffer { @@ -26,48 +27,68 @@ class Framebuffer::Driver { private: - Platform::Connection _platform; - Attached_io_mem_dataspace _ipu_mmio; /* Image processing unit memory */ - Ipu _ipu; - Gpio::Connection _gpio; + Platform::Connection _platform; + Attached_io_mem_dataspace _ipu_mmio; + Ipu _ipu; + Attached_io_mem_dataspace _pwm_mmio; + Pwm _pwm; + Gpio::Connection _gpio; + Platform::Session::Board_revision _board; + size_t _width; + size_t _height; public: - enum { - REFRESH = 60, - WIDTH = 800, - HEIGHT = 480, - PIX_CLK = 29850, - ROUND_PIX_CLK = 38000, - LEFT_MARGIN = 89, - RIGHT_MARGIN = 104, - UPPER_MARGIN = 10, - LOWER_MARGIN = 10, - VSYNC_LEN = 10, - HSYNC_LEN = 10, + enum Resolutions { + QSB_WIDTH = 800, + QSB_HEIGHT = 480, + SMD_WIDTH = 1024, + SMD_HEIGHT = 768, BYTES_PER_PIXEL = 2, - FRAMEBUFFER_SIZE = WIDTH * HEIGHT * BYTES_PER_PIXEL, + }; + enum Gpio_pins { LCD_BL_GPIO = 88, LCD_CONT_GPIO = 1, }; - Driver() : _ipu_mmio(Board_base::IPU_BASE, Board_base::IPU_SIZE), - _ipu((addr_t)_ipu_mmio.local_addr()) { } + _ipu((addr_t)_ipu_mmio.local_addr()), + _pwm_mmio(Board_base::PWM2_BASE, Board_base::PWM2_SIZE), + _pwm((addr_t)_pwm_mmio.local_addr()), + _board(_platform.revision()), + _width(_board == Platform::Session::QSB ? QSB_WIDTH : SMD_WIDTH), + _height(_board == Platform::Session::QSB ? QSB_HEIGHT : SMD_HEIGHT) { } bool init(addr_t phys_base) { /* enable IPU via platform driver */ _platform.enable(Platform::Session::IPU); - _ipu.init(WIDTH, HEIGHT, WIDTH * BYTES_PER_PIXEL, phys_base); + switch (_board) { + case Platform::Session::QSB: + _ipu.init(_width, _height, _width * BYTES_PER_PIXEL, + phys_base, true); - /* Turn on lcd power */ - _gpio.direction_output(LCD_BL_GPIO, true); - _gpio.direction_output(LCD_CONT_GPIO, true); + /* Turn display */ + _gpio.direction_output(LCD_BL_GPIO, true); + _gpio.direction_output(LCD_CONT_GPIO, true); + break; + case Platform::Session::SMD: + _ipu.init(_width, _height, _width * BYTES_PER_PIXEL, + phys_base, false); + _pwm.enable_display(); + break; + default: + PERR("Unknown board revision!"); + return false; + } return true; } -}; + Mode mode() { return Mode(_width, _height, Mode::RGB565); } + size_t size() { return BYTES_PER_PIXEL * _width * _height; } + + Ipu &ipu() { return _ipu; } +}; diff --git a/os/src/drivers/framebuffer/imx53/ipu.h b/os/src/drivers/framebuffer/imx53/ipu.h index 9904d7b63..de93d1386 100644 --- a/os/src/drivers/framebuffer/imx53/ipu.h +++ b/os/src/drivers/framebuffer/imx53/ipu.h @@ -1,6 +1,7 @@ /* * \brief Image Processing Unit registers - * \author Nikolay Golikov + * \author Nikolay Golikov + * \author Stefan Kalkowski * \date 2012-11-10 */ @@ -14,311 +15,533 @@ #include -using namespace Genode; - - -struct Ipu : Genode::Mmio +class Ipu : Genode::Mmio { - enum { - REGS_OFF = 0x06000000, - CPMEM_OFF = 0x01000000, - IDMAC_CHAN = 23, - }; + private: + + enum { REGS_OFF = 0x6000000 }; + + struct Conf : Register<0x0, 32> { }; + + template + struct Int_ctrl : Register<0x3c+(NR*4), 32> { }; + + struct Srm_pri2 : Register<0xa4, 32> + { + struct Dp_m_srm : Bitfield<3,2> { enum { UPDATE_NOW = 1 }; }; + }; + struct Disp_gen : Register<0xc4, 32> { }; + struct Mem_rst : Register<0xdc, 32> { }; + struct Pm : Register<0xe0, 32> { }; + struct Gpr : Register<0xe4, 32> { }; + struct Ch_db_mode_sel0 : Register<0x150, 32> { }; + struct Alt_ch_trb_mode_sel0 : Register<0x178, 32> { }; + struct Cur_buf_0 : Register<0x23c, 32> { }; + struct Triple_cur_buf_1 : Register<0x25c, 32> { }; + struct Ch_buf0_rdy0 : Register<0x268, 32> { }; + struct Ch_buf1_rdy0 : Register<0x270, 32> { }; - struct Conf : Register<0x0, 32> { }; - struct Cur_buf_0 : Register<0x23c, 32> { }; - struct Int_ctrl_5 : Register<0x4c, 32> { }; - struct Int_ctrl_6 : Register<0x50, 32> { }; - struct Int_ctrl_9 : Register<0x5c, 32> { }; - struct Int_ctrl_10 : Register<0x60, 32> { }; - struct Srm_pri2 : Register<0xa4, 32> { }; - struct Disp_gen : Register<0xc4, 32> { }; - struct Mem_rst : Register<0xdc, 32> { }; - struct Ch_db_mode_sel0 : Register<0x150, 32> { }; + /************************************** + ** Image DMA controller registers ** + **************************************/ - /** - * IDMAC cannel enable register - */ - struct Idmac_ch_en : Register_array<0x8004, 32, 32, 1> - { - struct Ch : Bitfield<0, 1> { }; - }; + enum Idmac_channels { + CHAN_DP_PRIMARY_MAIN = 23, + CHAN_DP_PRIMARY_AUXI = 27, + CHAN_DC_SYNC_FLOW = 28 + }; - struct Idmac_ch_pri_1 : Register<0x8014, 32> { }; - struct Dp_com_conf : Register<0x18000, 32> { }; - struct Gr_wnd_ctl_sync : Register<0x18004, 32> { }; - struct Di0_general : Register<0x40000, 32> { }; - struct Di0_bs_clkgen0 : Register<0x40004, 32> { }; - struct Di0_bs_clkgen1 : Register<0x40008, 32> { }; - struct Di0_sw_gen0_1 : Register<0x4000c, 32> { }; - struct Di0_sw_gen0_2 : Register<0x40010, 32> { }; - struct Di0_sw_gen0_3 : Register<0x40014, 32> { }; - struct Di0_sw_gen0_4 : Register<0x40018, 32> { }; - struct Di0_sw_gen0_5 : Register<0x4001c, 32> { }; - struct Di0_sw_gen0_6 : Register<0x40020, 32> { }; - struct Di0_sw_gen0_7 : Register<0x40024, 32> { }; - struct Di0_sw_gen0_8 : Register<0x40028, 32> { }; - struct Di0_sw_gen0_9 : Register<0x4002c, 32> { }; - struct Di0_sw_gen1_1 : Register<0x40030, 32> { }; - struct Di0_sw_gen1_2 : Register<0x40034, 32> { }; - struct Di0_sw_gen1_3 : Register<0x40038, 32> { }; - struct Di0_sw_gen1_4 : Register<0x4003c, 32> { }; - struct Di0_sw_gen1_5 : Register<0x40040, 32> { }; - struct Di0_sw_gen1_6 : Register<0x40044, 32> { }; - struct Di0_sw_gen1_7 : Register<0x40048, 32> { }; - struct Di0_sw_gen1_8 : Register<0x4004c, 32> { }; - struct Di0_sw_gen1_9 : Register<0x40050, 32> { }; - struct Di0_sync_as_gen : Register<0x40054, 32> { }; - struct Di0_dw_gen_1 : Register<0x40058, 32> { }; - struct Di0_dw_set3_1 : Register<0x40118, 32> { }; - struct Di0_stp_rep_1 : Register<0x40148, 32> { }; - struct Di0_stp_rep_3 : Register<0x4014c, 32> { }; - struct Di0_stp_rep_5 : Register<0x40150, 32> { }; - struct Di0_stp_rep_7 : Register<0x40154, 32> { }; - struct Di0_stp_rep_9 : Register<0x40158, 32> { }; - struct Di0_pol : Register<0x40164, 32> { }; - struct Di0_scr_conf : Register<0x40170, 32> { }; - struct Dc_wr_ch_conf_1 : Register<0x5801c, 32> { }; - struct Dc_wr_ch_conf_5 : Register<0x5805c, 32> { }; - struct Dc_wr_ch_addr_5 : Register<0x58060, 32> { }; - struct Dc_rl0_ch_5 : Register<0x58064, 32> { }; - struct Dc_rl1_ch_5 : Register<0x58068, 32> { }; - struct Dc_rl2_ch_5 : Register<0x5806c, 32> { }; - struct Dc_rl3_ch_5 : Register<0x58070, 32> { }; - struct Dc_rl4_ch_5 : Register<0x58074, 32> { }; - struct Dc_gen : Register<0x580d4, 32> { }; - struct Dc_disp_conf2_0 : Register<0x580e8, 32> { }; - struct Dc_map_conf_0 : Register<0x58108, 32> { }; - struct Dc_map_conf_1 : Register<0x5810c, 32> { }; - struct Dc_map_conf_2 : Register<0x58110, 32> { }; - struct Dc_map_conf_15 : Register<0x58144, 32> { }; - struct Dc_map_conf_16 : Register<0x58148, 32> { }; - struct Dc_map_conf_17 : Register<0x5814c, 32> { }; - struct Dc_map_conf_18 : Register<0x58150, 32> { }; - struct Dc_map_conf_19 : Register<0x58154, 32> { }; - struct Dc_map_conf_20 : Register<0x58158, 32> { }; - struct Dc_map_conf_21 : Register<0x5815c, 32> { }; - struct Dc_map_conf_22 : Register<0x58160, 32> { }; - struct Dmfc_wr_chan : Register<0x60004, 32> { }; - struct Dmfc_wr_chan_def : Register<0x60008, 32> { }; - struct Dmfc_dp_chan : Register<0x6000c, 32> { }; - struct Dmfc_dp_chan_def : Register<0x60010, 32> { }; - struct Dmfc_general_1 : Register<0x60014, 32> { }; - struct Dmfc_ic_ctrl : Register<0x6001c, 32> { }; - struct Dc_tmpl_low10 : Register<0x1080028, 32> { }; - struct Dc_tmpl_high10 : Register<0x108002c, 32> { }; - struct Dc_tmpl_low11 : Register<0x1080030, 32> { }; - struct Dc_tmpl_high11 : Register<0x1080034, 32> { }; - struct Dc_tmpl_low12 : Register<0x1080038, 32> { }; - struct Dc_tmpl_high12 : Register<0x108003c, 32> { }; + struct Idmac_ch_en : Register_array<0x8004, 32, 32, 1> + { + struct Ch : Bitfield<0, 1> { }; + }; + + struct Idmac_ch_pri_1 : Register<0x8014, 32> { }; + + struct Idmac_wm_en : Register_array<0x801c, 32, 32, 1> + { + struct Ch : Bitfield<0, 1> { }; + }; + + struct Idmac_ch_lock_en_1 : Register<0x8024, 32> { }; - /** - * IDMAC channel parametrs memory structure - */ - struct Cp_mem - { - Genode::uint32_t Data[5]; - Genode::uint32_t Resetrved[3]; - } _ch_cpmem[2]; + /*********************************** + ** Display processor registers ** + ***********************************/ - void cpmem_set_field(Genode::uint8_t word, Genode::uint8_t bit, - Genode::uint8_t size, Genode::uint32_t value) - { - int i = (bit) / 32; - int off = (bit) % 32; - _ch_cpmem[word].Data[i] |= (value) << off; - if (((bit) + (size) - 1) / 32 > i) { - _ch_cpmem[word].Data[i + 1] |= (value) >> (off ? (32 - off) : 0); + struct Dp_com_conf : Register<0x1040000, 32> { }; + struct Dp_fg_pos_sync : Register<0x1040008, 32> { }; + struct Gr_wnd_ctl_sync : Register<0x1040004, 32> { }; + + + /*********************************** + ** Display interface registers ** + ***********************************/ + + template + struct Di + { + struct General : Register { }; + struct Bs_clkgen0 : Register { }; + struct Bs_clkgen1 : Register { }; + template + struct Sync_wave_gen0 : Register<0xc+OFF+(NR*4), 32> { }; + template + struct Sync_wave_gen1 : Register<0x30+OFF+(NR*4), 32> { }; + + struct Sync_as_gen : Register { }; + + template + struct Dw_gen : Register<0x58 + OFF + (NR*4), 32> { }; + template + struct Dw_set3 : Register<0x118 + OFF + (NR*4), 32> { }; + template + struct Step_repeat : Register<0x148 + OFF + (NR*4), 32> { }; + + struct Polarity : Register { }; + struct Scr_conf : Register { }; + }; + + typedef Di<0x40000> Di0; + typedef Di<0x48000> Di1; + + + /************************************ + ** Display controller registers ** + ************************************/ + + struct Dc_wr_ch_conf_5 : Register<0x5805c, 32> { }; + struct Dc_wr_ch_addr_5 : Register<0x58060, 32> { }; + template + struct Dc_rl_ch_5 : Register<0x58064+(NR*4), 32> { }; + struct Dc_gen : Register<0x580d4, 32> { }; + struct Dc_disp_conf2_0 : Register<0x580e8, 32> { }; + struct Dc_disp_conf2_1 : Register<0x580ec, 32> { }; + template + struct Dc_map_conf : Register<0x58108+(NR*4), 32> { }; + template + struct Dc_template : Register<0x1080000+(NR*4), 32> { }; + + + /*********************************************** + ** Display multi FIFO controller registers ** + ***********************************************/ + + struct Dmfc_wr_chan : Register<0x60004, 32> { }; + struct Dmfc_wr_chan_def : Register<0x60008, 32> { }; + struct Dmfc_dp_chan : Register<0x6000c, 32> { }; + struct Dmfc_dp_chan_def : Register<0x60010, 32> { }; + struct Dmfc_general_1 : Register<0x60014, 32> { }; + struct Dmfc_ic_ctrl : Register<0x6001c, 32> { }; + + + class Cp_mem + { + public: + + enum { OFFSET = 0x1000000 }; + + unsigned xv : 10; /* XV Virtual Coordinate */ + unsigned yv : 9; /* YV Virtual Coordinate */ + unsigned xb : 13; /* XB inner Block Coordinate */ + unsigned yb : 12; /* YB inner Block Coordinate */ + unsigned nsb_b : 1; /* New Sub Block */ + unsigned cf : 1; /* Current Field */ + unsigned sx : 12; /* Scroll X counter */ + unsigned sy : 11; /* Scroll Y counter */ + unsigned ns : 10; /* Number of Scroll */ + unsigned sdx : 7; /* Scroll Delta X */ + unsigned sm : 10; /* Scroll Max */ + unsigned scc : 1; /* Scrolling Configuration */ + unsigned sce : 1; /* Scrolling Enable */ + unsigned sdy : 7; /* Scroll Delta Y */ + unsigned sdrx : 1; /* Scroll Horizontal Direction */ + unsigned sdry : 1; /* Scroll Vertical Direction */ + unsigned bpp : 3; /* Bits per Pixel */ + unsigned dec_sel : 2; /* Decode Address Select */ + unsigned dim : 1; /* Access Dimension */ + unsigned so : 1; /* Scan Order */ + unsigned bndm : 3; /* Band Mode */ + unsigned bm : 2; /* Block Mode */ + unsigned rot : 1; /* Rotation */ + unsigned hf : 1; /* Horizontal Flip */ + unsigned vf : 1; /* Vertical Flip */ + unsigned the : 1; /* Threshold Enable */ + unsigned cap : 1; /* Conditional Access Polarity */ + unsigned cae : 1; /* Conditional Access Enable */ + unsigned fw : 13; /* Frame Width */ + unsigned fh : 12; /* Frame Height */ + unsigned res0 : 10; /* reserved */ + Genode::uint32_t res1[3]; + + unsigned eba0 : 29; /* Ext Mem Buffer 0 Address */ + unsigned eba1 : 29; /* Ext Mem Buffer 1 Address */ + unsigned ilo : 20; /* Interlace Offset */ + unsigned npb : 7; /* Number of Pixels in Whole Burst Access */ + unsigned pfs : 4; /* Pixel Format Select */ + unsigned alu : 1; /* Alpha Used */ + unsigned albm : 3; /* Alpha Channel Mapping */ + unsigned id : 2; /* AXI ID */ + unsigned th : 7; /* Threshold */ + unsigned sly : 14; /* Stride Line */ + unsigned wid0 : 3; /* Width0 */ + unsigned wid1 : 3; /* Width1 */ + unsigned wid2 : 3; /* Width2 */ + unsigned wid3 : 3; /* Width3 */ + unsigned off0 : 5; /* Offset0 */ + unsigned off1 : 5; /* Offset1 */ + unsigned off2 : 5; /* Offset2 */ + unsigned off3 : 5; /* Offset3 */ + unsigned sxys : 1; /* Select SX SY Set */ + unsigned cre : 1; /* Conditional Read Enable */ + unsigned dec_sel2 : 1; /* Decode Address Select bit[2] */ + unsigned res2 : 9; /* reserved */ + Genode::uint32_t res3[3]; + + Cp_mem() { Genode::memset(this, 0, sizeof(Cp_mem)); } + + void * operator new(Genode::size_t size, void* addr) { return addr; } + } __attribute__((packed)); + + + void _init_dma_channel(unsigned channel, + Genode::uint16_t width, Genode::uint16_t height, + Genode::uint32_t stride, Genode::addr_t phys_base) + { + void *dst =(void*)(base + Cp_mem::OFFSET + channel*sizeof(Cp_mem)); + Cp_mem cpmem; + + cpmem.fw = width - 1; + cpmem.fh = height - 1; + cpmem.sly = stride - 1; + cpmem.eba0 = phys_base >> 3; + cpmem.eba1 = phys_base >> 3; + cpmem.bpp = 3; /* corresponds to 16BPP */ + cpmem.pfs = 7; /* corresponds to RGB */ + cpmem.npb = 31; /* 32 pixel per burst access */ + + /* red */ + cpmem.wid0 = 4; + cpmem.off0 = 0; + + /* green */ + cpmem.wid1 = 5; + cpmem.off1 = 5; + + /* blue */ + cpmem.wid2 = 4; cpmem.off2 = 11; + + /* alpha */ + cpmem.wid3 = 7; + cpmem.off3 = 16; + + Genode::memcpy(dst, (void*)&cpmem, sizeof(Cp_mem)); } - } - /** - * IPU initialization - */ - void init(Genode::uint16_t width, Genode::uint16_t height, - Genode::uint32_t stride, - Genode::addr_t phys_base) - { - /* Reset ipu memory */ - write(0x807fffff); - while (read() & 0x80000000) - ; + + void _init_di0(Genode::uint16_t width, Genode::uint16_t height, + Genode::uint32_t stride, Genode::addr_t phys_base) + { + /* set MCU_T to divide MCU access window into 2 */ + write(0x1600000); // ?= 0x600000 + + /* link display controller events */ + write >(0x5030000); + write >(0x602); + write >(0x701); + write >(0x5030000); + write >(0x0); + write >(0x0); + write >(0x602); + write >(0x0); + write >(0x0); + + write(0x2); + write(0x0); + + write(0x84); + + + /************************* + ** Display interface ** + *************************/ + + /* clear DI */ + write(0x200000); + + /* initialize display interface 0 */ + write(0x38); + write(0x30000); + write >(0x2020300); + write >(0x60000); + write >(0x21310000); + write >(0x10000000); + write >(0x21310001); + write >(0x30141000); + write >(0x0); + write >(0x10520000); + write >(0x30142000); + write(0x20a); + write >(0x3010b); + write >(0x8000000); + write >(0x1e00000); + write >(0x10319); + write >(0xa000000); + write >(0x0); + write >(0x0); + write >(0x0); + write >(0x0); + write >(0x0); + write >(0x0); + write >(0x0); + write >(0x0); + write >(0x320); + write >(0x0); + write >(0x0); + + /* write display connection microcode */ + write >(0x8885); + write >(0x380); + write >(0x8845); + write >(0x380); + write >(0x8805); + write >(0x380); + + write(0x220000); + write(0x2002); + write(0x200000); + write(0x4002); + + write(0x10); + write(0x320); + + /* init IDMAC channels */ + _init_dma_channel(CHAN_DP_PRIMARY_MAIN, width, height, stride, phys_base); + _init_dma_channel(CHAN_DP_PRIMARY_AUXI, width, height, stride, phys_base); + + /* round robin for simultaneous synchronous flows from DC & DP */ + write(0x3); + + /* enable DP, DI0, DC, DMFC */ + write(0x660); + + /* use double buffer for main DMA channel */ + write(1 << CHAN_DP_PRIMARY_MAIN | + 1 << CHAN_DP_PRIMARY_AUXI); + + /* buffer used by DMA channel is buffer 1 */ + write(1 << CHAN_DP_PRIMARY_MAIN); + + write(0x82); + + /* Enable IDMAC channels */ + write(1, CHAN_DP_PRIMARY_MAIN); + write(1, CHAN_DP_PRIMARY_AUXI); + } + + void _init_di1(Genode::uint16_t width, Genode::uint16_t height, + Genode::uint32_t stride, Genode::addr_t phys_base) + { + write(0x600000); //write(0x2400000); + + write(0); + write(Srm_pri2::Dp_m_srm::UPDATE_NOW); + + write >(0x2030000); + write >(0); + write >(0x302); + write >(0); + write >(0x401); + write(0xe); + write(0x0); + write(0x84); + + write(0); + + write(0x200000); + write(0x300000); + + write(0x10); + write(0x10000); + + write(0x10101010); + + write >(0x300); + write >(0x20000); + write >(0x29f90000); + write >(0x10000000); + write >(0x0); + write >(0x29f90001); + write >(0x30781000); + write >(0x0); + write >(0x192a0000); + write >(0x30142000); + write >(0x3000000); + write(0x325); + write >(0x300fb); + write >(0x8000000); + write >(0x3000000); + write >(0x108c1); + write >(0xa000000); + write >(0x400); + write >(0x29f90091); + write >(0x30781000); + write >(0x0); + write >(0x192a000a); + write >(0x30142000); + write >(0x0); + write >(0x0); + write >(0x0); + write >(0x0); + write >(0x0); + write >(0x0); + write >(0x400); + + write >(0x90011); + write >(0x4000000); + write >(0x28a0400); + + write >(0x10885); + write >(0x380); + write >(0x845); + write >(0x280); + write >(0x10805); + write >(0x380); + + write(0x6300000); + write(0x4000); + + write(0x10); + write(0x400); + + _init_dma_channel(CHAN_DP_PRIMARY_MAIN, width, height, stride, phys_base); + _init_dma_channel(CHAN_DP_PRIMARY_AUXI, width, height, stride, phys_base); + + /* use double buffer for main DMA channel */ + write(1 << CHAN_DP_PRIMARY_MAIN | + 1 << CHAN_DP_PRIMARY_AUXI); + + /* buffer used by DMA channel is buffer 1 */ + write(1 << CHAN_DP_PRIMARY_MAIN); + + write(0x6a0); + + /* Enable IDMAC channels */ + write(1, CHAN_DP_PRIMARY_MAIN); + write(1, CHAN_DP_PRIMARY_AUXI); + + write(1 << CHAN_DP_PRIMARY_MAIN | + 1 << CHAN_DP_PRIMARY_AUXI); + + write(0x8e); + + write(0x2600000); + } + + public: /** - * Init display controller mappings + * IPU initialization */ - write(0x14830820); - write(0x2d4920e6); - write(0x39ac); - write(0xfff07ff); - write(0x5fc17ff); - write(0x11fc0bfc); - write(0x17ff0fff); - write(0x4f807ff); - write(0xff80afc); - write(0xdfc05fc); - write(0x15fc); + void init(Genode::uint16_t width, Genode::uint16_t height, + Genode::uint32_t stride, Genode::addr_t phys_base, + bool di0) + { + /* stop pixel clocks */ + write(0); + write(0); + + /* reset IPU memory buffers */ + write(0x807fffff); + while (read() & 0x80000000) ; + + /* initialize pixel format mappings for display controller */ + write >(0x14830820); + write >(0x2d4920e6); + write >(0x39ac); + write >(0xfff07ff); + write >(0x5fc17ff); + write >(0x11fc0bfc); + write >(0x17ff0fff); + write >(0x4f807ff); + write >(0xff80afc); + write >(0xdfc05fc); + write >(0x15fc); + + /* clear interrupt control registers */ + write >(0); + write >(0); + write >(0); + write >(0); + + /* disable DMFC channel from image converter */ + write(0x2); + + /* set DMFC FIFO for idma channels */ + write(0x90); /* channel CHAN_DC_SYNC_FLOW */ + write(0x202020f6); + write(0x968a); /* channels CHAN_DP_PRIMARY_XXX */ + write(0x2020f6f6); + write(0x3); + + /* set idma channels 23, 27, 28 as high priority */ + write(1 << CHAN_DP_PRIMARY_MAIN | + 1 << CHAN_DP_PRIMARY_AUXI | + 1 << CHAN_DC_SYNC_FLOW); + + /* + * generate 8 AXI bursts upon the assertion of DMA request + * for our channels + */ + write(0x3f0000); + + if (di0) + _init_di0(width, height, stride, phys_base); + else + _init_di1(width, height, stride, phys_base); + + + /************************ + ** overlay settings ** + ************************/ + + write(1 << 0); + write(Srm_pri2::Dp_m_srm::UPDATE_NOW); + + write(16); + write(Srm_pri2::Dp_m_srm::UPDATE_NOW); + + write(1 << 0 | 1 << 2); + write(Srm_pri2::Dp_m_srm::UPDATE_NOW); + + write(0xff000000); + write(Srm_pri2::Dp_m_srm::UPDATE_NOW); + } + + + void overlay(Genode::addr_t phys_base, int x, int y, int alpha) + { + volatile Genode::uint32_t *ptr = (volatile Genode::uint32_t*) + (base + Cp_mem::OFFSET + CHAN_DP_PRIMARY_AUXI*sizeof(Cp_mem)); + ptr[8] = (((phys_base >> 3) & 0b111) << 29) | (phys_base >> 3); + ptr[9] = (phys_base >> 6); + + write(x << 16 | y); + write(Srm_pri2::Dp_m_srm::UPDATE_NOW); + + write(alpha << 24); + write(Srm_pri2::Dp_m_srm::UPDATE_NOW); + } + /** - * Clear interrupt control registers + * Constructor + * + * \param mmio_base base address of IPU */ - write(0x0); - write(0x0); - write(0x0); - write(0x0); - - /** - * Init DMFC - */ - write(0x2); - write(0x90); - write(0x202020f6); - write(0x9694); - write(0x2020f6f6); - - write(0x18800000); - write(0x80000000); - write(0x605080b); - write(0x4); - write(0x605080b); - - /** - * Link display controller events - */ - write(0x5030000); - write(0x602); - write(0x701); - write(0x5030000); - write(0x0); - write(0x0); - write(0x602); - write(0x0); - write(0x0); - - /** - * Init display controller - */ - write(0x2); - write(0x0); - write(0x84); - - write(0x660); - - /** - * Init display interface - */ - write(0x38); - write(0x30000); - write(0x2020300); - write(0x60000); - write(0x21310000); - write(0x10000000); - write(0x21310001); - write(0x30141000); - write(0x0); - write(0x10520000); - write(0x30142000); - write(0x20a); - write(0x3010b); - write(0x8000000); - write(0x1e00000); - write(0x10319); - write(0xa000000); - write(0x0); - write(0x0); - write(0x0); - write(0x0); - write(0x0); - write(0x0); - write(0x0); - write(0x0); - write(0x320); - write(0x0); - write(0x0); - - /** - * Write display connection templates - */ - write(0x8885); - write(0x380); - write(0x8845); - write(0x380); - write(0x8805); - write(0x380); - - - write(0x220000); - write(0x2002); - write(0x200000); - write(0x4002); - - write(0x10); - write(0x320); - write(0x3); - write(0x800000); - write(0x800000); - - write(0x4); - write(0x82); - write(0x1600000); - - /** - * Init IDMAC channel - */ - cpmem_set_field(0, 125, 13, width - 1); - cpmem_set_field(0, 138, 12, height - 1); - cpmem_set_field(1, 102, 14, stride - 1 ); - cpmem_set_field(1, 0, 29, 0); - cpmem_set_field(1, 29, 29, phys_base >> 3); - - /* bits/pixel */ - cpmem_set_field(0, 107, 3, 3); - - /* pixel format RGB565 */ - cpmem_set_field(1, 85, 4, 7); - - /* burst size */ - cpmem_set_field(1, 78, 7, 15); - - - /******************* - ** set packing ** - *******************/ - - /* red */ - cpmem_set_field(1, 116, 3, 4); - cpmem_set_field(1, 128, 5, 0); - - /* green */ - cpmem_set_field(1, 119, 3, 5); - cpmem_set_field(1, 133, 5, 5); - - /* blue */ - cpmem_set_field(1, 122, 3, 4); - cpmem_set_field(1, 138, 5, 11); - - /* alpha */ - cpmem_set_field(1, 125, 3, 7); - cpmem_set_field(1, 143, 5, 16); - - cpmem_set_field(0, 46, 22, 0); - cpmem_set_field(0, 68, 22, 0); - - Genode::memcpy((void *)(base + CPMEM_OFF + sizeof(_ch_cpmem) * IDMAC_CHAN), - (void *)&_ch_cpmem, sizeof(_ch_cpmem)); - - write(1, IDMAC_CHAN); -} - - /** - * Constructor - * - * \param mmio_base base address of IPU - */ - Ipu(Genode::addr_t mmio_base) - : Genode::Mmio(mmio_base + REGS_OFF) { } + Ipu(Genode::addr_t mmio_base) : Genode::Mmio(mmio_base + REGS_OFF) { } }; #endif /* _IPU_H_ */ diff --git a/os/src/drivers/framebuffer/imx53/main.cc b/os/src/drivers/framebuffer/imx53/main.cc index 64ceacf94..418a4488b 100644 --- a/os/src/drivers/framebuffer/imx53/main.cc +++ b/os/src/drivers/framebuffer/imx53/main.cc @@ -5,7 +5,7 @@ */ /* Genode includes */ -#include +#include #include #include #include @@ -22,21 +22,25 @@ namespace Framebuffer { class Framebuffer::Session_component : - public Genode::Rpc_object + public Genode::Rpc_object { private: size_t _size; Dataspace_capability _ds; addr_t _phys_base; + Mode _mode; + Ipu &_ipu; public: Session_component(Driver &driver) - : _size(Driver::FRAMEBUFFER_SIZE), + : _size(driver.size()), _ds(env()->ram_session()->alloc(_size, false)), - _phys_base(Dataspace_client(_ds).phys_addr()) + _phys_base(Dataspace_client(_ds).phys_addr()), + _mode(driver.mode()), + _ipu(driver.ipu()) { if (!driver.init(_phys_base)) { PERR("Could not initialize display"); @@ -50,12 +54,14 @@ class Framebuffer::Session_component : ** Framebuffer::session interface ** **************************************/ - Dataspace_capability dataspace() { return _ds; } - void release() { } - Mode mode() const { - return Mode(Driver::WIDTH, Driver::HEIGHT, Mode::RGB565); } + Dataspace_capability dataspace() { return _ds; } + void release() { } + Mode mode() const { return _mode; } void mode_sigh(Genode::Signal_context_capability) { } - void refresh(int, int, int, int) { } + void refresh(int, int, int, int) { } + + void overlay(Genode::addr_t phys_base, int x, int y, int alpha) { + _ipu.overlay(phys_base, x, y, alpha); } }; int main(int, char **) diff --git a/os/src/drivers/framebuffer/imx53/pwm.h b/os/src/drivers/framebuffer/imx53/pwm.h new file mode 100644 index 000000000..cb8c2e5d6 --- /dev/null +++ b/os/src/drivers/framebuffer/imx53/pwm.h @@ -0,0 +1,36 @@ +/* + * \brief Pulse width modulation + * \author Stefan Kalkowski + * \date 2013-03-05 + */ + +/* + * Copyright (C) 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. + */ + +#ifndef _PWM_H_ +#define _PWM_H_ + +/* Genode includes */ +#include + +struct Pwm : Genode::Mmio +{ + struct Control : Register<0x0, 32> {}; + struct Sample : Register<0xc, 32> {}; + struct Period : Register<0x10,32> {}; + + Pwm(Genode::addr_t const mmio_base) : Genode::Mmio(mmio_base) { } + + void enable_display() + { + write(0x64); + write(0x64); + write(0x3c20001); + } +}; + +#endif /* _PWM_H_ */ diff --git a/os/src/drivers/platform/imx53/ccm.h b/os/src/drivers/platform/imx53/ccm.h index 8e175fe15..d8b6ee53f 100644 --- a/os/src/drivers/platform/imx53/ccm.h +++ b/os/src/drivers/platform/imx53/ccm.h @@ -33,6 +33,16 @@ class Ccm : public Genode::Attached_io_mem_dataspace, struct Ipu_hs_mask : Bitfield <21, 1> { }; }; + /** + * Serial Clock Multiplexer Register 2 + */ + struct Cscmr2 : Register<0x20, 32> {}; + + /** + * D1 Clock Divider Register + */ + struct Cdcdr : Register<0x30, 32> {}; + /** * Low power control register */ @@ -41,7 +51,7 @@ class Ccm : public Genode::Attached_io_mem_dataspace, struct Bypass_ipu_hs : Bitfield<18, 1> { }; }; - struct Cccr5 : Register<0x7c, 32> + struct Ccgr5 : Register<0x7c, 32> { struct Ipu_clk_en : Bitfield<10, 2> { }; }; @@ -55,14 +65,16 @@ class Ccm : public Genode::Attached_io_mem_dataspace, void ipu_clk_enable(void) { - write(3); + write(3); write(0); write(0); + write(0xa2b32f0b); + write(0x14370092); } void ipu_clk_disable(void) { - write(0); + write(0); write(1); write(1); } diff --git a/os/src/drivers/platform/imx53/iim.h b/os/src/drivers/platform/imx53/iim.h new file mode 100644 index 000000000..2a67ad557 --- /dev/null +++ b/os/src/drivers/platform/imx53/iim.h @@ -0,0 +1,39 @@ +/* + * \brief IC identification module register description + * \author Stefan Kalkowski + * \date 2013-04-29 + */ + +/* + * Copyright (C) 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. + */ + +#ifndef _DRIVERS__PLATFORM__IMX53__IIM_H_ +#define _DRIVERS__PLATFORM__IMX53__IIM_H_ + +/* Genode includes */ +#include +#include +#include + +class Iim : public Genode::Attached_io_mem_dataspace, + Genode::Mmio +{ + private: + + struct Fuse_bank0_gp6 : Register<0x878, 32> {}; + + public: + + Iim() + : Genode::Attached_io_mem_dataspace(Genode::Board_base::IIM_BASE, + Genode::Board_base::IIM_SIZE), + Genode::Mmio((Genode::addr_t)local_addr()) {} + + unsigned long revision() { return read() & 0xf; } +}; + +#endif /* _DRIVERS__PLATFORM__IMX53__IIM_H_ */ diff --git a/os/src/drivers/platform/imx53/iomux.h b/os/src/drivers/platform/imx53/iomux.h index 4f26be879..27e96b4fd 100644 --- a/os/src/drivers/platform/imx53/iomux.h +++ b/os/src/drivers/platform/imx53/iomux.h @@ -22,12 +22,35 @@ class Iomux : public Genode::Attached_io_mem_dataspace, Genode::Mmio { + private: + + struct Gpr2 : Register<0x8,32> + { + struct Ch1_mode : Bitfield<2, 2> { + enum { ROUTED_TO_DI1 = 0x3 }; }; + struct Data_width_ch1 : Bitfield<7, 1> { + enum { PX_18_BITS, PX_24_BITS }; }; + struct Bit_mapping_ch1 : Bitfield<8, 1> { + enum { SPWG, JEIDA }; }; + struct Di1_vs_polarity : Bitfield<10,1> { }; + }; + public: Iomux() : Genode::Attached_io_mem_dataspace(Genode::Board_base::IOMUXC_BASE, Genode::Board_base::IOMUXC_SIZE), - Genode::Mmio((Genode::addr_t)local_addr()) {} + Genode::Mmio((Genode::addr_t)local_addr()) + { + } + + void enable_di1() + { + write(1); + write(Gpr2::Data_width_ch1::PX_18_BITS); + write(Gpr2::Bit_mapping_ch1::SPWG); + write(Gpr2::Ch1_mode::ROUTED_TO_DI1); + } }; #endif /* _DRIVERS__PLATFORM__IMX53__IOMUX_H_ */ diff --git a/os/src/drivers/platform/imx53/main.cc b/os/src/drivers/platform/imx53/main.cc index 217ded3ff..c44f6cd47 100644 --- a/os/src/drivers/platform/imx53/main.cc +++ b/os/src/drivers/platform/imx53/main.cc @@ -18,8 +18,9 @@ #include #include -#include #include +#include +#include #include @@ -33,17 +34,18 @@ class Platform::Session_component : public Genode::Rpc_object { private: - Iomux &_iomux; /* I/O multiplexer device */ - Ccm &_ccm; /* clock control module */ - Src &_src; /* system reset controller */ + Iim &_iim; /* IC identification module */ + Iomux &_iomux; /* I/O multiplexer device */ + Ccm &_ccm; /* clock control module */ + Src &_src; /* system reset controller */ public: /** * Constructor */ - Session_component(Iomux &iomux, Ccm &ccm, Src &src) - : _iomux(iomux), _ccm(ccm), _src(src) {} + Session_component(Iim &iim, Iomux &iomux, Ccm &ccm, Src &src) + : _iim(iim), _iomux(iomux), _ccm(ccm), _src(src) {} /********************************** @@ -56,6 +58,7 @@ class Platform::Session_component : public Genode::Rpc_object case Session::IPU: _src.reset_ipu(); _ccm.ipu_clk_enable(); + _iomux.enable_di1(); break; default: PWRN("Invalid device"); @@ -80,6 +83,15 @@ class Platform::Session_component : public Genode::Rpc_object PWRN("Invalid device"); }; } + + Board_revision revision() + { + switch (_iim.revision()) { + case QSB: return QSB; + case SMD: return SMD; + }; + return UNKNOWN; + } }; @@ -87,6 +99,7 @@ class Platform::Root : public Genode::Root_component