From d2f5deaf33c048ac395177b445f1855577ddbec1 Mon Sep 17 00:00:00 2001 From: Nikolay Golikov Date: Fri, 3 May 2013 17:20:45 +0200 Subject: [PATCH] Implement i.MX53 framebuffer driver --- .../platform/imx53/drivers/board_base.h | 11 + base/mk/spec-platform_imx53.mk | 2 +- os/src/drivers/framebuffer/imx53/ccm.h | 67 ++++ os/src/drivers/framebuffer/imx53/driver.h | 90 +++++ os/src/drivers/framebuffer/imx53/ipu.h | 324 ++++++++++++++++++ os/src/drivers/framebuffer/imx53/main.cc | 80 +++++ os/src/drivers/framebuffer/imx53/src.h | 31 ++ os/src/drivers/framebuffer/imx53/target.mk | 7 + 8 files changed, 611 insertions(+), 1 deletion(-) create mode 100644 os/src/drivers/framebuffer/imx53/ccm.h create mode 100644 os/src/drivers/framebuffer/imx53/driver.h create mode 100644 os/src/drivers/framebuffer/imx53/ipu.h create mode 100644 os/src/drivers/framebuffer/imx53/main.cc create mode 100644 os/src/drivers/framebuffer/imx53/src.h create mode 100644 os/src/drivers/framebuffer/imx53/target.mk diff --git a/base/include/platform/imx53/drivers/board_base.h b/base/include/platform/imx53/drivers/board_base.h index ed96a4bda3..4505c21035 100644 --- a/base/include/platform/imx53/drivers/board_base.h +++ b/base/include/platform/imx53/drivers/board_base.h @@ -46,6 +46,17 @@ namespace Genode AIPS_1_MMIO_BASE = 0x53f00000, AIPS_2_MMIO_BASE = 0x63f00000, + IPU_ERR_IRQ = 10, + IPU_SYNC_IRQ = 11, + IPU_BASE = 0x18000000, + IPU_SIZE = 0x08000000, + + SRC_BASE = 0x53fd0000, + SRC_SIZE = 0x00004000, + + CCM_BASE = 0x53FD4000, + CCM_SIZE = 0x00004000, + SECURITY_EXTENSION = 1, }; }; diff --git a/base/mk/spec-platform_imx53.mk b/base/mk/spec-platform_imx53.mk index 876355eca8..01cc3a0ec0 100644 --- a/base/mk/spec-platform_imx53.mk +++ b/base/mk/spec-platform_imx53.mk @@ -5,7 +5,7 @@ # # denote wich specs are also fullfilled by this spec -SPECS += cortex_a8 imx53 imx gpio +SPECS += cortex_a8 imx53 imx gpio framebuffer # add repository relative include paths REP_INC_DIR += include/platform/imx53 diff --git a/os/src/drivers/framebuffer/imx53/ccm.h b/os/src/drivers/framebuffer/imx53/ccm.h new file mode 100644 index 0000000000..5946795259 --- /dev/null +++ b/os/src/drivers/framebuffer/imx53/ccm.h @@ -0,0 +1,67 @@ +/* + * \brief Clock control module + * \author Nikolay Golikov + * \date 2012-10-09 + */ + +/* + * Copyright (C) 2012 Ksys Labs LLC + * 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. + */ + +#ifndef _CCM_H_ +#define _CCM_H_ + +/* Genode includes */ +#include + +struct Ccm : Genode::Mmio +{ + enum { IPU_CLK = 133000000 }; + + /** + * Control divider register + */ + struct Ccdr : Register<0x4, 32> + { + struct Ipu_hs_mask : Bitfield <21, 1> { }; + }; + + /** + * Low power control register + */ + struct Clpcr : Register<0x54, 32> + { + struct Bypass_ipu_hs : Bitfield<18, 1> { }; + }; + + /** + * + */ + struct Cccr5 : Register<0x7c, 32> + { + struct Ipu_clk_en : Bitfield<10, 2> { }; + }; + + void ipu_clk_enable(void) + { + write(3); + write(0); + write(0); + } + + void ipu_clk_disable(void) + { + write(0); + write(1); + write(1); + } + + Ccm(Genode::addr_t const mmio_base) : Genode::Mmio(mmio_base) { } + +}; + +#endif /* _CCM_H_ */ diff --git a/os/src/drivers/framebuffer/imx53/driver.h b/os/src/drivers/framebuffer/imx53/driver.h new file mode 100644 index 0000000000..dcd7cb146a --- /dev/null +++ b/os/src/drivers/framebuffer/imx53/driver.h @@ -0,0 +1,90 @@ +/* + * \brief Frame-buffer driver for Freescale's i.MX53 + * \author Nikolay Golikov + * \date 2012-06-21 + */ + +/* Genode includes */ +#include +#include +#include +#include +#include + +/* local includes */ +#include +#include +#include + + +namespace Framebuffer { + using namespace Genode; + class Driver; +}; + + +class Framebuffer::Driver +{ + private: + + /* Clocks control module */ + Attached_io_mem_dataspace _ccm_mmio; + Ccm _ccm; + + /* System reset controller registers */ + Attached_io_mem_dataspace _src_mmio; + Src _src; + + /* Image processing unit memory */ + Attached_io_mem_dataspace _ipu_mmio; + Ipu _ipu; + + Gpio::Connection _gpio; + + 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, + BYTES_PER_PIXEL = 2, + FRAMEBUFFER_SIZE = WIDTH * HEIGHT * BYTES_PER_PIXEL, + + LCD_BL_GPIO = 88, + LCD_CONT_GPIO = 1, + }; + + + Driver() + : _ccm_mmio(Board_base::CCM_BASE, Board_base::CCM_SIZE), + _ccm((addr_t)_ccm_mmio.local_addr()), + _src_mmio(Board_base::SRC_BASE, Board_base::SRC_SIZE), + _src((addr_t)_src_mmio.local_addr()), + _ipu_mmio(Board_base::IPU_BASE, Board_base::IPU_SIZE), + _ipu((addr_t)_ipu_mmio.local_addr()) { } + + bool init(addr_t phys_base) + { + /* reset ipu over src */ + _src.write(1); + + _ccm.ipu_clk_enable(); + + _ipu.init(WIDTH, HEIGHT, WIDTH * BYTES_PER_PIXEL, phys_base); + + /* Turn on lcd power */ + _gpio.direction_output(LCD_BL_GPIO, true); + _gpio.direction_output(LCD_CONT_GPIO, true); + return true; + } + +}; + diff --git a/os/src/drivers/framebuffer/imx53/ipu.h b/os/src/drivers/framebuffer/imx53/ipu.h new file mode 100644 index 0000000000..9904d7b634 --- /dev/null +++ b/os/src/drivers/framebuffer/imx53/ipu.h @@ -0,0 +1,324 @@ +/* + * \brief Image Processing Unit registers + * \author Nikolay Golikov + * \date 2012-11-10 + */ + +#ifndef _IPU_H_ +#define _IPU_H_ + +/* Genode includes */ +#include +#include +#include +#include + + +using namespace Genode; + + +struct Ipu : Genode::Mmio +{ + enum { + REGS_OFF = 0x06000000, + CPMEM_OFF = 0x01000000, + IDMAC_CHAN = 23, + }; + + + 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> { }; + + /** + * IDMAC cannel enable register + */ + struct Idmac_ch_en : Register_array<0x8004, 32, 32, 1> + { + struct Ch : Bitfield<0, 1> { }; + }; + + 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> { }; + + + /** + * IDMAC channel parametrs memory structure + */ + struct Cp_mem + { + Genode::uint32_t Data[5]; + Genode::uint32_t Resetrved[3]; + } _ch_cpmem[2]; + + 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); + } + } + + /** + * 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) + ; + + /** + * Init display controller mappings + */ + 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(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) { } +}; + +#endif /* _IPU_H_ */ diff --git a/os/src/drivers/framebuffer/imx53/main.cc b/os/src/drivers/framebuffer/imx53/main.cc new file mode 100644 index 0000000000..64ceacf94b --- /dev/null +++ b/os/src/drivers/framebuffer/imx53/main.cc @@ -0,0 +1,80 @@ +/* + * \brief Frame-buffer driver for the i.MX53 + * \author Nikolay Golikov + * \date 2012-06-21 + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include + +/* local includes */ +#include + +namespace Framebuffer { + using namespace Genode; + class Session_component; +}; + + +class Framebuffer::Session_component : + public Genode::Rpc_object +{ + private: + + size_t _size; + Dataspace_capability _ds; + addr_t _phys_base; + + + public: + + Session_component(Driver &driver) + : _size(Driver::FRAMEBUFFER_SIZE), + _ds(env()->ram_session()->alloc(_size, false)), + _phys_base(Dataspace_client(_ds).phys_addr()) + { + if (!driver.init(_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, Driver::HEIGHT, Mode::RGB565); } + void mode_sigh(Genode::Signal_context_capability) { } + void refresh(int, int, int, int) { } +}; + +int main(int, char **) +{ + Genode::printf("Starting i.MX53 framebuffer driver\n"); + + using namespace Framebuffer; + + static Driver driver; + + enum { STACK_SIZE = 4096 }; + static Cap_connection cap; + static Rpc_entrypoint ep(&cap, STACK_SIZE, "fb_ep"); + + static Session_component fb_session(driver); + static Static_root fb_root(ep.manage(&fb_session)); + + env()->parent()->announce(ep.manage(&fb_root)); + + sleep_forever(); + return 0; +} diff --git a/os/src/drivers/framebuffer/imx53/src.h b/os/src/drivers/framebuffer/imx53/src.h new file mode 100644 index 0000000000..e0f5b57f52 --- /dev/null +++ b/os/src/drivers/framebuffer/imx53/src.h @@ -0,0 +1,31 @@ +/* + * \brief System reset controller registers + * \author Nikolay Golikov + * \date 2012-11-06 + */ + +/* + * Copyright (C) 2012 Ksys Labs LLC + * 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. + */ + +#ifndef _SRC_H_ +#define _SRC_H_ + +/* Genode includes */ +#include + +struct Src : Genode::Mmio +{ + Src(Genode::addr_t const mmio_base) : Genode::Mmio(mmio_base) { } + + struct Ctrl_reg : Register<0x0, 32> + { + struct Ipu_rst : Bitfield<3, 1> { }; + }; +}; + +#endif /* _SRC_H_ */ diff --git a/os/src/drivers/framebuffer/imx53/target.mk b/os/src/drivers/framebuffer/imx53/target.mk new file mode 100644 index 0000000000..b387f4298f --- /dev/null +++ b/os/src/drivers/framebuffer/imx53/target.mk @@ -0,0 +1,7 @@ +TARGET = fb_drv +REQUIRES = imx53 +SRC_CC = main.cc +LIBS = base +INC_DIR += $(PRG_DIR) + +vpath main.cc $(PRG_DIR)