/* * \brief Image Processing Unit registers * \author Nikolay Golikov * \author Stefan Kalkowski * \date 2012-11-10 */ /* * Copyright (C) 2009-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__FRAMEBUFFER__SPEC__IMX53__IPU_H_ #define _DRIVERS__FRAMEBUFFER__SPEC__IMX53__IPU_H_ /* Genode includes */ #include #include #include #include class Ipu : Genode::Mmio { 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> { }; /************************************** ** Image DMA controller registers ** **************************************/ enum Idmac_channels { CHAN_DP_PRIMARY_MAIN = 23, CHAN_DP_PRIMARY_AUXI = 27, CHAN_DC_SYNC_FLOW = 28 }; 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> { }; /*********************************** ** Display processor registers ** ***********************************/ 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)); } } __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)); } 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: /** * IPU initialization */ 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); } /** * Constructor * * \param mmio_base base address of IPU */ Ipu(Genode::addr_t mmio_base) : Genode::Mmio(mmio_base + REGS_OFF) { } }; #endif /* _DRIVERS__FRAMEBUFFER__SPEC__IMX53__IPU_H_ */