Implement i.MX53 framebuffer driver

This commit is contained in:
Nikolay Golikov 2013-05-03 17:20:45 +02:00 committed by Norman Feske
parent a5d236475a
commit d2f5deaf33
8 changed files with 611 additions and 1 deletions
base
include/platform/imx53/drivers
mk
os/src/drivers/framebuffer/imx53

View File

@ -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,
};
};

View File

@ -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

View File

@ -0,0 +1,67 @@
/*
* \brief Clock control module
* \author Nikolay Golikov <nik@ksyslabs.org>
* \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 <util/mmio.h>
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<Cccr5::Ipu_clk_en>(3);
write<Ccdr::Ipu_hs_mask>(0);
write<Clpcr::Bypass_ipu_hs>(0);
}
void ipu_clk_disable(void)
{
write<Cccr5::Ipu_clk_en>(0);
write<Ccdr::Ipu_hs_mask>(1);
write<Clpcr::Bypass_ipu_hs>(1);
}
Ccm(Genode::addr_t const mmio_base) : Genode::Mmio(mmio_base) { }
};
#endif /* _CCM_H_ */

View File

@ -0,0 +1,90 @@
/*
* \brief Frame-buffer driver for Freescale's i.MX53
* \author Nikolay Golikov <nik@ksyslabs.org>
* \date 2012-06-21
*/
/* Genode includes */
#include <drivers/board_base.h>
#include <os/attached_io_mem_dataspace.h>
#include <io_mem_session/connection.h>
#include <gpio_session/connection.h>
#include <util/mmio.h>
/* local includes */
#include <ipu.h>
#include <src.h>
#include <ccm.h>
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<void>()),
_src_mmio(Board_base::SRC_BASE, Board_base::SRC_SIZE),
_src((addr_t)_src_mmio.local_addr<void>()),
_ipu_mmio(Board_base::IPU_BASE, Board_base::IPU_SIZE),
_ipu((addr_t)_ipu_mmio.local_addr<void>()) { }
bool init(addr_t phys_base)
{
/* reset ipu over src */
_src.write<Src::Ctrl_reg::Ipu_rst>(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;
}
};

View File

@ -0,0 +1,324 @@
/*
* \brief Image Processing Unit registers
* \author Nikolay Golikov <nik@ksyslabs.org>
* \date 2012-11-10
*/
#ifndef _IPU_H_
#define _IPU_H_
/* Genode includes */
#include <util/mmio.h>
#include <util/string.h>
#include <drivers/board_base.h>
#include <os/attached_io_mem_dataspace.h>
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<Mem_rst>(0x807fffff);
while (read<Mem_rst>() & 0x80000000)
;
/**
* Init display controller mappings
*/
write<Dc_map_conf_0>(0x14830820);
write<Dc_map_conf_1>(0x2d4920e6);
write<Dc_map_conf_2>(0x39ac);
write<Dc_map_conf_15>(0xfff07ff);
write<Dc_map_conf_16>(0x5fc17ff);
write<Dc_map_conf_17>(0x11fc0bfc);
write<Dc_map_conf_18>(0x17ff0fff);
write<Dc_map_conf_19>(0x4f807ff);
write<Dc_map_conf_20>(0xff80afc);
write<Dc_map_conf_21>(0xdfc05fc);
write<Dc_map_conf_22>(0x15fc);
/**
* Clear interrupt control registers
*/
write<Int_ctrl_5>(0x0);
write<Int_ctrl_6>(0x0);
write<Int_ctrl_9>(0x0);
write<Int_ctrl_10>(0x0);
/**
* Init DMFC
*/
write<Dmfc_ic_ctrl>(0x2);
write<Dmfc_wr_chan>(0x90);
write<Dmfc_wr_chan_def>(0x202020f6);
write<Dmfc_dp_chan>(0x9694);
write<Dmfc_dp_chan_def>(0x2020f6f6);
write<Idmac_ch_pri_1>(0x18800000);
write<Gr_wnd_ctl_sync>(0x80000000);
write<Srm_pri2>(0x605080b);
write<Dp_com_conf>(0x4);
write<Srm_pri2>(0x605080b);
/**
* Link display controller events
*/
write<Dc_rl0_ch_5>(0x5030000);
write<Dc_rl2_ch_5>(0x602);
write<Dc_rl4_ch_5>(0x701);
write<Dc_rl0_ch_5>(0x5030000);
write<Dc_rl1_ch_5>(0x0);
write<Dc_rl1_ch_5>(0x0);
write<Dc_rl2_ch_5>(0x602);
write<Dc_rl3_ch_5>(0x0);
write<Dc_rl3_ch_5>(0x0);
/**
* Init display controller
*/
write<Dc_wr_ch_conf_5>(0x2);
write<Dc_wr_ch_addr_5>(0x0);
write<Dc_gen>(0x84);
write<Conf>(0x660);
/**
* Init display interface
*/
write<Di0_bs_clkgen0>(0x38);
write<Di0_bs_clkgen1>(0x30000);
write<Di0_dw_gen_1>(0x2020300);
write<Di0_dw_set3_1>(0x60000);
write<Di0_sw_gen0_1>(0x21310000);
write<Di0_sw_gen1_1>(0x10000000);
write<Di0_sw_gen0_2>(0x21310001);
write<Di0_sw_gen1_2>(0x30141000);
write<Di0_stp_rep_1>(0x0);
write<Di0_sw_gen0_3>(0x10520000);
write<Di0_sw_gen1_3>(0x30142000);
write<Di0_scr_conf>(0x20a);
write<Di0_sw_gen0_4>(0x3010b);
write<Di0_sw_gen1_4>(0x8000000);
write<Di0_stp_rep_3>(0x1e00000);
write<Di0_sw_gen0_5>(0x10319);
write<Di0_sw_gen1_5>(0xa000000);
write<Di0_sw_gen0_6>(0x0);
write<Di0_sw_gen1_6>(0x0);
write<Di0_sw_gen0_7>(0x0);
write<Di0_sw_gen1_7>(0x0);
write<Di0_sw_gen0_8>(0x0);
write<Di0_sw_gen1_8>(0x0);
write<Di0_sw_gen0_9>(0x0);
write<Di0_sw_gen1_9>(0x0);
write<Di0_stp_rep_5>(0x320);
write<Di0_stp_rep_7>(0x0);
write<Di0_stp_rep_9>(0x0);
/**
* Write display connection templates
*/
write<Dc_tmpl_low10>(0x8885);
write<Dc_tmpl_high10>(0x380);
write<Dc_tmpl_low11>(0x8845);
write<Dc_tmpl_high11>(0x380);
write<Dc_tmpl_low12>(0x8805);
write<Dc_tmpl_high12>(0x380);
write<Di0_general>(0x220000);
write<Di0_sync_as_gen>(0x2002);
write<Di0_general>(0x200000);
write<Di0_sync_as_gen>(0x4002);
write<Di0_pol>(0x10);
write<Dc_disp_conf2_0>(0x320);
write<Dmfc_general_1>(0x3);
write<Ch_db_mode_sel0>(0x800000);
write<Cur_buf_0>(0x800000);
write<Dc_wr_ch_conf_1>(0x4);
write<Dc_wr_ch_conf_5>(0x82);
write<Disp_gen>(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<Idmac_ch_en::Ch>(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_ */

View File

@ -0,0 +1,80 @@
/*
* \brief Frame-buffer driver for the i.MX53
* \author Nikolay Golikov <nik@ksyslabs.org>
* \date 2012-06-21
*/
/* Genode includes */
#include <framebuffer_session/framebuffer_session.h>
#include <cap_session/connection.h>
#include <dataspace/client.h>
#include <base/printf.h>
#include <base/sleep.h>
#include <os/static_root.h>
/* local includes */
#include <driver.h>
namespace Framebuffer {
using namespace Genode;
class Session_component;
};
class Framebuffer::Session_component :
public Genode::Rpc_object<Framebuffer::Session>
{
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<Framebuffer::Session> fb_root(ep.manage(&fb_session));
env()->parent()->announce(ep.manage(&fb_root));
sleep_forever();
return 0;
}

View File

@ -0,0 +1,31 @@
/*
* \brief System reset controller registers
* \author Nikolay Golikov <nik@ksyslabs.org>
* \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 <util/mmio.h>
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_ */

View File

@ -0,0 +1,7 @@
TARGET = fb_drv
REQUIRES = imx53
SRC_CC = main.cc
LIBS = base
INC_DIR += $(PRG_DIR)
vpath main.cc $(PRG_DIR)