/* * Allwinner SoCs display driver. * * Copyright (C) 2016 Allwinner. * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ /** *All Winner Tech, All Right Reserved. 2014-2015 Copyright (c) * *File name :de_rtmx.c * *Description :display engine 2.0 realtime mixer * processing base functions implement * *History :2014/02/08 iptang v0.1 Initial version * */ #include "de_rtmx.h" #include "de_rtmx_type.h" #include "de_scaler.h" static struct __rtmx_reg_t de200_rtmx[DE_NUM]; static struct de_reg_blocks glb_ctl_block[DE_NUM]; static struct de_reg_blocks vi_attr_block[DE_NUM][VI_CHN_NUM][LAYER_MAX_NUM_PER_CHN]; static struct de_reg_blocks vi_fc_block[DE_NUM][VI_CHN_NUM]; static struct de_reg_blocks vi_haddr_block[DE_NUM][VI_CHN_NUM]; static struct de_reg_blocks vi_size_block[DE_NUM][VI_CHN_NUM]; static struct de_reg_blocks ui_attr_block[DE_NUM][CHN_NUM - VI_CHN_NUM][LAYER_MAX_NUM_PER_CHN]; static struct de_reg_blocks ui_haddr_block[DE_NUM][CHN_NUM - VI_CHN_NUM]; static struct de_reg_blocks ui_size_block[DE_NUM][CHN_NUM - VI_CHN_NUM]; static struct de_reg_blocks bld_attr_block[DE_NUM]; static struct de_reg_blocks bld_ctl_block[DE_NUM]; static struct de_reg_blocks bld_ck_block[DE_NUM]; static struct de_reg_blocks bld_out_block[DE_NUM]; /* static uintptr_t de_base = 0; */ static uintptr_t de_base; int de_rtmx_update_regs(unsigned int sel) { int i, j, ui_chno, vi_chno, layno; vi_chno = de_feat_get_num_vi_chns(sel); ui_chno = de_feat_get_num_ui_chns(sel); layno = LAYER_MAX_NUM_PER_CHN; if (glb_ctl_block[sel].dirty == 0x1) { memcpy((void *)glb_ctl_block[sel].off, glb_ctl_block[sel].val, glb_ctl_block[sel].size); glb_ctl_block[sel].dirty = 0; } for (j = 0; j < vi_chno; j++) { for (i = 0; i < layno; i++) { if (vi_attr_block[sel][j][i].dirty == 0x1) { memcpy((void *)vi_attr_block[sel][j][i].off, vi_attr_block[sel][j][i].val, vi_attr_block[sel][j][i].size); vi_attr_block[sel][j][i].dirty = 0; } } if (vi_fc_block[sel][j].dirty == 0x1) { memcpy((void *)vi_fc_block[sel][j].off, vi_fc_block[sel][j].val, vi_fc_block[sel][j].size); vi_fc_block[sel][j].dirty = 0; } if (vi_haddr_block[sel][j].dirty == 0x1) { memcpy((void *)vi_haddr_block[sel][j].off, vi_haddr_block[sel][j].val, vi_haddr_block[sel][j].size); vi_haddr_block[sel][j].dirty = 0; } if (vi_size_block[sel][j].dirty == 0x1) { memcpy((void *)vi_size_block[sel][j].off, vi_size_block[sel][j].val, vi_size_block[sel][j].size); vi_size_block[sel][j].dirty = 0; } } for (j = 0; j < ui_chno; j++) { for (i = 0; i < layno; i++) { if (ui_attr_block[sel][j][i].dirty == 0x1) { memcpy((void *)ui_attr_block[sel][j][i].off, ui_attr_block[sel][j][i].val, ui_attr_block[sel][j][i].size); ui_attr_block[sel][j][i].dirty = 0; } } if (ui_haddr_block[sel][j].dirty == 0x1) { memcpy((void *)ui_haddr_block[sel][j].off, ui_haddr_block[sel][j].val, ui_haddr_block[sel][j].size); ui_haddr_block[sel][j].dirty = 0; } if (ui_size_block[sel][j].dirty == 0x1) { memcpy((void *)ui_size_block[sel][j].off, ui_size_block[sel][j].val, ui_size_block[sel][j].size); ui_size_block[sel][j].dirty = 0; } } if (bld_attr_block[sel].dirty == 0x1) { memcpy((void *)bld_attr_block[sel].off, bld_attr_block[sel].val, bld_attr_block[sel].size); bld_attr_block[sel].dirty = 0; } if (bld_ctl_block[sel].dirty == 0x1) { memcpy((void *)bld_ctl_block[sel].off, bld_ctl_block[sel].val, bld_ctl_block[sel].size); bld_ctl_block[sel].dirty = 0; } if (bld_ck_block[sel].dirty == 0x1) { memcpy((void *)bld_ck_block[sel].off, bld_ck_block[sel].val, bld_ck_block[sel].size); bld_ck_block[sel].dirty = 0; } if (bld_out_block[sel].dirty == 0x1) { memcpy((void *)bld_out_block[sel].off, bld_out_block[sel].val, bld_out_block[sel].size); bld_out_block[sel].dirty = 0; } return 0; } static int de_rtmx_force_dirty(unsigned int sel) { int i, j, ui_chno, vi_chno, layno; vi_chno = de_feat_get_num_vi_chns(sel); ui_chno = de_feat_get_num_ui_chns(sel); layno = LAYER_MAX_NUM_PER_CHN; glb_ctl_block[sel].dirty = 1; for (j = 0; j < vi_chno; j++) { for (i = 0; i < layno; i++) vi_attr_block[sel][j][i].dirty = 1; vi_fc_block[sel][j].dirty = 1; vi_haddr_block[sel][j].dirty = 1; vi_size_block[sel][j].dirty = 1; } for (j = 0; j < ui_chno; j++) { for (i = 0; i < layno; i++) ui_attr_block[sel][j][i].dirty = 1; ui_haddr_block[sel][j].dirty = 1; ui_size_block[sel][j].dirty = 1; } bld_attr_block[sel].dirty = 1; bld_ctl_block[sel].dirty = 1; bld_ck_block[sel].dirty = 1; bld_out_block[sel].dirty = 1; return 0; } int de_rtmx_init(unsigned int sel, uintptr_t reg_base) { void *memory; int i, j, vi_chno, ui_chno, layno; uintptr_t glb_base, apb_base, ovl_base; int ch_index = 0; de_base = reg_base; if (sel > de_feat_get_num_screens()) __wrn("sel %d out of range\n", sel); vi_chno = de_feat_get_num_vi_chns(sel); ui_chno = de_feat_get_num_ui_chns(sel); layno = LAYER_MAX_NUM_PER_CHN; glb_base = reg_base + 0x00100000; apb_base = reg_base + 0x00101000; ovl_base = reg_base + 0x00102000; if (sel) { glb_base = reg_base + 0x00200000; apb_base = reg_base + 0x00201000; ovl_base = reg_base + 0x00202000; } #if defined(CONFIG_INDEPENDENT_DE) if (sel) { glb_base = glb_base - 0x00100000; apb_base = apb_base - 0x00100000; ovl_base = ovl_base - 0x00100000; } #endif memory = kmalloc(sizeof(struct __glb_reg_t), GFP_KERNEL | __GFP_ZERO); if (memory == NULL) { __wrn("malloc rtmx global memory fail! size=0x%x\n", (unsigned int)sizeof(struct __glb_reg_t)); return -1; } glb_ctl_block[sel].off = glb_base; glb_ctl_block[sel].val = memory; glb_ctl_block[sel].size = 0x10; glb_ctl_block[sel].dirty = 1; de_rtmx_set_gld_reg_base(sel, memory); for (j = 0; j < vi_chno; j++) { memory = kmalloc(sizeof(struct __vi_ovl_reg_t), GFP_KERNEL | __GFP_ZERO); if (memory == NULL) { __wrn("malloc video overlay memory fail! size=0x%x\n", (unsigned int)sizeof(struct __vi_ovl_reg_t)); return -1; } __inf("malloc memory ok(0x%p) for video channel\n", (void *)memory); for (i = 0; i < layno; i++) { vi_attr_block[sel][j][i].off = ovl_base + ch_index * 0x00001000 + i * 0x30; vi_attr_block[sel][j][i].val = (memory + i * 0x30); vi_attr_block[sel][j][i].size = 0x30; vi_attr_block[sel][j][i].dirty = 1; } vi_fc_block[sel][j].off = ovl_base + ch_index * 0x00001000 + 0xc0; vi_fc_block[sel][j].val = (memory + 0xc0); vi_fc_block[sel][j].size = 0x10; vi_fc_block[sel][j].dirty = 1; vi_haddr_block[sel][j].off = ovl_base + ch_index * 0x00001000 + 0xd0; vi_haddr_block[sel][j].val = (memory + 0xd0); vi_haddr_block[sel][j].size = 0x18; vi_haddr_block[sel][j].dirty = 1; vi_size_block[sel][j].off = ovl_base + ch_index * 0x00001000 + 0xe8; vi_size_block[sel][j].val = (memory + 0xe8); vi_size_block[sel][j].size = 0x18; vi_size_block[sel][j].dirty = 1; de_rtmx_set_overlay_reg_base(sel, j, memory); ch_index++; } for (j = 0; j < ui_chno; j++) { memory = kmalloc(sizeof(struct __ui_ovl_reg_t), GFP_KERNEL | __GFP_ZERO); if (memory == NULL) { __wrn("malloc ui overlay memory fail! size=0x%x\n", (unsigned int)sizeof(struct __ui_ovl_reg_t)); return -1; } for (i = 0; i < layno; i++) { ui_attr_block[sel][j][i].off = ovl_base + ch_index * 0x00001000 + i * 0x20; ui_attr_block[sel][j][i].val = (memory + i * 0x20); ui_attr_block[sel][j][i].size = 0x20; ui_attr_block[sel][j][i].dirty = 1; } ui_haddr_block[sel][j].off = ovl_base + ch_index * 0x00001000 + 0x80; ui_haddr_block[sel][j].val = (memory + 0x80); ui_haddr_block[sel][j].size = 0x8; ui_haddr_block[sel][j].dirty = 1; ui_size_block[sel][j].off = ovl_base + ch_index * 0x00001000 + 0x88; ui_size_block[sel][j].val = (memory + 0x88); ui_size_block[sel][j].size = 0x4; ui_size_block[sel][j].dirty = 1; de_rtmx_set_overlay_reg_base(sel, j + vi_chno, memory); ch_index++; } memory = kmalloc(sizeof(struct __bld_reg_t), GFP_KERNEL | __GFP_ZERO); if (memory == NULL) { __wrn("malloc blending memory fail! size=0x%x\n", (unsigned int)sizeof(struct __bld_reg_t)); return -1; } bld_attr_block[sel].off = apb_base; bld_attr_block[sel].val = memory; bld_attr_block[sel].size = 0x44; bld_attr_block[sel].dirty = 1; bld_ctl_block[sel].off = apb_base + 0x80; bld_ctl_block[sel].val = (memory + 0x80); bld_ctl_block[sel].size = 0x20; bld_ctl_block[sel].dirty = 1; bld_ck_block[sel].off = apb_base + 0xb0; bld_ck_block[sel].val = (memory + 0xb0); bld_ck_block[sel].size = 0x4c; bld_ck_block[sel].dirty = 1; bld_out_block[sel].off = apb_base + 0xfc; bld_out_block[sel].val = (memory + 0xfc); bld_out_block[sel].size = 0x4; bld_out_block[sel].dirty = 1; de_rtmx_set_bld_reg_base(sel, memory); return 0; } int de_rtmx_exit(unsigned int sel) { int j, vi_chno, ui_chno; int ch_index = 0; if (sel > de_feat_get_num_screens()) __wrn("sel %d out of range\n", sel); vi_chno = de_feat_get_num_vi_chns(sel); ui_chno = de_feat_get_num_ui_chns(sel); kfree(glb_ctl_block[sel].val); for (j = 0; j < vi_chno; j++) { kfree(vi_attr_block[sel][j][0].val); ch_index++; } for (j = 0; j < ui_chno; j++) { kfree(ui_attr_block[sel][j][0].val); ch_index++; } kfree(bld_attr_block[sel].val); return 0; } /** *function : de_rtmx_set_gld_reg_base(unsigned int sel, unsigned int base) *description : set de reg base *parameters : * sel * base *return : * success */ int de_rtmx_set_gld_reg_base(unsigned int sel, void *base) { __inf("sel=0x%x, addr=0x%p\n", sel, base); de200_rtmx[sel].glb_ctl = (struct __glb_reg_t *)base; return 0; } /** *function : de_rtmx_set_bld_reg_base(unsigned int sel, unsigned int base) *description : set de reg base *parameters : * sel * base *return : * success */ int de_rtmx_set_bld_reg_base(unsigned int sel, void *base) { __inf("sel=%d, base=0x%p\n", sel, base); de200_rtmx[sel].bld_ctl = (struct __bld_reg_t *) base; return 0; } /** *function : de_rtmx_set_overlay_reg_base(unsigned int sel, * unsigned int chno, unsigned int base) *description: set de reg base *parameters : * sel * chno * base *return : * success */ int de_rtmx_set_overlay_reg_base(unsigned int sel, unsigned int chno, void *base) { int vi_chno = de_feat_get_num_vi_chns(sel); __inf("sel=0x%x, overlayer %d, addr=0x%p\n", sel, chno, base); if (chno < vi_chno) { de200_rtmx[sel].vi_ovl[chno] = (struct __vi_ovl_reg_t *) base; } else { de200_rtmx[sel].ui_ovl[chno - vi_chno] = (struct __ui_ovl_reg_t *) base; } return 0; } int de_rtmx_set_display_size(unsigned int sel, unsigned int width, unsigned int height) { de200_rtmx[sel].glb_ctl->glb_size.bits.width = width == 0 ? 0 : width - 1; de200_rtmx[sel].glb_ctl->glb_size.bits.height = height == 0 ? 0 : height - 1; glb_ctl_block[sel].dirty = 1; return 0; } int de_rtmx_set_dbuff_rdy(unsigned int sel) { de200_rtmx[sel].glb_ctl->glb_dbuff.dwval = 0x1; glb_ctl_block[sel].dirty = 1; return 0; } int de_rtmx_set_enable(unsigned int sel, unsigned int en) { /* de200_rtmx[sel].glb_ctl->glb_ctl.bits.finish_irq_en = en&0x1; */ /* 0:write back fetch data after dep; * 1:write back fetch data before dep */ de200_rtmx[sel].glb_ctl->glb_ctl.bits.rtwb_port = 0x1; de200_rtmx[sel].glb_ctl->glb_ctl.bits.rt_en = en & 0x1; /* glb_ctl_block[sel].dirty = 1; */ if (en) de_rtmx_force_dirty(sel); return 0; } int de_rtmx_query_irq(unsigned int sel) { unsigned int irq_flag; uintptr_t base = glb_ctl_block[sel].off; irq_flag = readl((void __iomem *)(base + 0x04)); if (irq_flag & 0x1) { writel(irq_flag, (void __iomem *)(base + 0x04)); return 1; } return 0; } int de_rtmx_enable_irq(unsigned int sel, unsigned int en) { unsigned int irq_flag; uintptr_t base = glb_ctl_block[sel].off; irq_flag = readl((void __iomem *)(base + 0x0)); irq_flag &= (~(0x1 << 4)); irq_flag |= (en & 0x1) << 4; writel(irq_flag, (void __iomem *)(base + 0x0)); return 0; } /** *function : de_rtmx_set_lay_cfg(unsigned int sel, * unsigned int chno, unsigned int layno, struct __lay_para_t *cfg) *description : set de layer config *parameters : * sel * chno * layno * cfg *return : * success */ int de_rtmx_set_lay_cfg(unsigned int sel, unsigned int chno, unsigned int layno, struct __lay_para_t *cfg) { int fmt, ui_sel; int vi_chno = de_feat_get_num_vi_chns(sel); if (chno >= vi_chno) { de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].lay_attr. bits.lay_en = cfg->en; de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].lay_attr. bits.lay_alpmod = cfg->alpha_mode; de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].lay_attr. bits.lay_fcolor_en = cfg->fcolor_en; de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].lay_attr. bits.lay_fmt = cfg->fmt; de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].lay_attr. bits.lay_alpctl = cfg->premul_ctl; de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].lay_attr. bits.lay_top_down = cfg->top_bot_en; de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].lay_attr. bits.lay_alpha = cfg->alpha; de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].lay_size. bits.lay_width = cfg->layer.w == 0 ? 0 : cfg->layer.w - 1; de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].lay_size. bits.lay_height = cfg->layer.h == 0 ? 0 : cfg->layer.h - 1; de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].lay_coor. bits.lay_coorx = cfg->layer.x; de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].lay_coor. bits.lay_coory = cfg->layer.y; ui_attr_block[sel][chno - vi_chno][layno].dirty = 1; } else { if (cfg->fmt == DE_FORMAT_YUV422_I_VYUY) { ui_sel = 0x0; fmt = 0x0; } else if (cfg->fmt == DE_FORMAT_YUV422_I_YVYU) { ui_sel = 0x0; fmt = 0x1; } else if (cfg->fmt == DE_FORMAT_YUV422_I_UYVY) { ui_sel = 0x0; fmt = 0x2; } else if (cfg->fmt == DE_FORMAT_YUV422_I_YUYV) { ui_sel = 0x0; fmt = 0x3; } else if (cfg->fmt == DE_FORMAT_YUV422_SP_VUVU) { ui_sel = 0x0; fmt = 0x5; } else if (cfg->fmt == DE_FORMAT_YUV422_SP_UVUV) { ui_sel = 0x0; fmt = 0x4; } else if (cfg->fmt == DE_FORMAT_YUV422_P) { ui_sel = 0x0; fmt = 0x6; } else if (cfg->fmt == DE_FORMAT_YUV420_SP_VUVU) { ui_sel = 0x0; fmt = 0x9; } else if (cfg->fmt == DE_FORMAT_YUV420_SP_UVUV) { ui_sel = 0x0; fmt = 0x8; } else if (cfg->fmt == DE_FORMAT_YUV420_P) { ui_sel = 0x0; fmt = 0xa; } else if (cfg->fmt == DE_FORMAT_YUV411_SP_VUVU) { ui_sel = 0x0; fmt = 0xd; } else if (cfg->fmt == DE_FORMAT_YUV411_SP_UVUV) { ui_sel = 0x0; fmt = 0xc; } else if (cfg->fmt == DE_FORMAT_YUV411_P) { ui_sel = 0x0; fmt = 0xe; } else { ui_sel = 0x1; fmt = cfg->fmt; } de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.bits. lay_en = cfg->en; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.bits. alpmode = cfg->alpha_mode; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.bits. alpctl = cfg->premul_ctl; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.bits. alpha = cfg->alpha; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.bits. lay_fcolor_en = cfg->fcolor_en; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.bits. lay_fmt = fmt; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.bits. ui_sel = ui_sel; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.bits. lay_top_down = cfg->top_bot_en; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_size.bits. lay_width = cfg->layer.w == 0 ? 0 : cfg->layer.w - 1; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_size.bits. lay_height = cfg->layer.h == 0 ? 0 : cfg->layer.h - 1; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_coor.bits. lay_coorx = cfg->layer.x; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_coor.bits. lay_coory = cfg->layer.y; vi_attr_block[sel][chno][layno].dirty = 1; } return 0; } /* *function : de_rtmx_set_lay_haddr(unsigned int sel, unsigned int chno, * unsigned int layno, unsigned char top_bot_en, * unsigned char *haddr_t, unsigned char *haddr_b) *description : set de high address for layers *parameters : * sel * chno * haddr_t * haddr_b *return : * success */ int de_rtmx_set_lay_haddr(unsigned int sel, unsigned int chno, unsigned int layno, unsigned char top_bot_en, unsigned char *haddr_t, unsigned char *haddr_b) { unsigned int haddr, mask; int vi_chno = de_feat_get_num_vi_chns(sel); switch (layno) { case 0: mask = 0xffffff00; break; case 1: mask = 0xffff00ff; break; case 2: mask = 0xff00ffff; break; default: mask = 0x00ffffff; break; } if (chno >= vi_chno) { haddr = de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_top_haddr.dwval & mask; de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_top_haddr.dwval = haddr + (haddr_t[0] << layno); if (top_bot_en) { haddr = de200_rtmx[sel].ui_ovl[chno - vi_chno] ->ui_lay_bot_haddr.dwval & mask; de200_rtmx[sel].ui_ovl[chno - vi_chno] ->ui_lay_bot_haddr.dwval = haddr + (haddr_b[0] << layno); } ui_haddr_block[sel][chno - vi_chno].dirty = 1; } else { haddr = de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[0].dwval & mask; de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[0].dwval = haddr + (haddr_t[0] << layno); haddr = de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[1].dwval & mask; de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[1].dwval = haddr + (haddr_t[1] << layno); haddr = de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[2].dwval & mask; de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[2].dwval = haddr + (haddr_t[2] << layno); if (top_bot_en) { haddr = de200_rtmx[sel].vi_ovl[chno]->vi_lay_bot_haddr[0]. dwval & mask; de200_rtmx[sel].vi_ovl[chno]->vi_lay_bot_haddr[0].dwval = haddr + (haddr_b[0] << layno); haddr = de200_rtmx[sel].vi_ovl[chno]->vi_lay_bot_haddr[1]. dwval & mask; de200_rtmx[sel].vi_ovl[chno]->vi_lay_bot_haddr[1].dwval = haddr + (haddr_b[1] << layno); haddr = de200_rtmx[sel].vi_ovl[chno]->vi_lay_bot_haddr[2]. dwval & mask; de200_rtmx[sel].vi_ovl[chno]->vi_lay_bot_haddr[2].dwval = haddr + (haddr_b[2] << layno); } vi_haddr_block[sel][chno].dirty = 1; } return 0; } /** *function : de_rtmx_set_lay_laddr(unsigned int sel, unsigned int chno, * unsigned int layno, unsigned char fmt,struct de_rect crop, * unsigned int *size, enum de_3d_in_mode trdinmode, * unsigned int *addr,unsigned char *haddr) *description : set de low address for layer *parameters : * sel * chno * layno * fmt *return : * success */ int de_rtmx_set_lay_laddr(unsigned int sel, unsigned int chno, unsigned int layno, unsigned char fmt, struct de_rect crop, unsigned int *size, unsigned int *align, enum de_3d_in_mode trdinmode, unsigned int *addr, unsigned char *haddr) { long long addr_off[3]; unsigned int pitch[3]; unsigned int x0, x1, y0, y1, ycnt, ucnt; int vi_chno = de_feat_get_num_vi_chns(sel); x0 = crop.x; y0 = crop.y; x1 = y1 = 0; ycnt = ucnt = 0; if (fmt <= DE_FORMAT_BGRX_8888) { ycnt = 4; } else if (fmt <= DE_FORMAT_BGR_888) { ycnt = 3; } else if (fmt <= DE_FORMAT_BGRA_5551) { ycnt = 2; } else if (fmt <= DE_FORMAT_YUV422_I_VYUY) { ycnt = 2; ucnt = 0; } else if (fmt == DE_FORMAT_YUV422_P) { ycnt = 1; ucnt = 1; x1 = x0 / 2; y1 = y0; } /* YUV422 */ else if (fmt == DE_FORMAT_YUV420_P) { ycnt = 1; ucnt = 1; x1 = x0 / 2; y1 = y0 / 2; } /* YUV420 */ else if (fmt == DE_FORMAT_YUV411_P) { ycnt = 1; ucnt = 1; x1 = x0 / 4; y1 = y0; } /* YUV411 */ else if (fmt <= DE_FORMAT_YUV422_SP_VUVU) { ycnt = 1; ucnt = 2; x1 = x0 / 2; y1 = y0; } else if (fmt <= DE_FORMAT_YUV420_SP_VUVU) { ycnt = 1; ucnt = 2; x1 = x0 / 2; y1 = y0 / 2; } else if (fmt <= DE_FORMAT_YUV411_SP_VUVU) { ycnt = 1; ucnt = 2; x1 = x0 / 4; y1 = y0; } else { ycnt = 4; } pitch[0] = DISPALIGN(size[0] * ycnt, align[0]); pitch[1] = DISPALIGN(size[1] * ucnt, align[1]); pitch[2] = DISPALIGN(size[2] * ucnt, align[2]); if (trdinmode == DE_3D_SRC_MODE_LI) addr_off[0] = addr[0] + de_rtmx_get_li_addr_offset(size[0], align[0], x0, y0, ycnt); else addr_off[0] = addr[0] + pitch[0] * y0 + x0 * ycnt; /* Y/ARGB */ haddr[0] = (addr_off[0] >> 32) & 0xff; if (chno >= vi_chno) { de200_rtmx[sel].ui_ovl[chno - vi_chno] ->ui_lay_cfg[layno].lay_pitch.dwval = pitch[0]; de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno]. lay_top_laddr.dwval = (addr_off[0] & 0xffffffff); de200_rtmx[sel].ui_ovl[chno - vi_chno]-> ui_lay_cfg[layno].lay_bot_laddr.dwval = 0x0; ui_attr_block[sel][chno - vi_chno][layno].dirty = 1; } else { if (trdinmode == DE_3D_SRC_MODE_LI) { addr_off[1] = addr[1] + de_rtmx_get_li_addr_offset(size[1], align[1], x1, y1, ucnt); addr_off[2] = addr[2] + de_rtmx_get_li_addr_offset(size[2], align[2], x1, y1, ucnt); } else { addr_off[1] = addr[1] + pitch[1] * y1 + x1 * ucnt; /* UV/U */ addr_off[2] = addr[2] + pitch[2] * y1 + x1 * ucnt; /* V */ } haddr[1] = (addr_off[1] >> 32) & 0xff; haddr[2] = (addr_off[2] >> 32) & 0xff; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_pitch[0]. dwval = pitch[0]; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_pitch[1]. dwval = pitch[1]; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_pitch[2]. dwval = pitch[2]; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno]. lay_top_laddr[0].dwval = (addr_off[0] & 0xffffffff); de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno]. lay_top_laddr[1].dwval = (addr_off[1] & 0xffffffff); de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno]. lay_top_laddr[2].dwval = (addr_off[2] & 0xffffffff); de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno]. lay_bot_laddr[0].dwval = 0x0; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno]. lay_bot_laddr[1].dwval = 0x0; de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno]. lay_bot_laddr[2].dwval = 0x0; vi_attr_block[sel][chno][layno].dirty = 1; } return 0; } int de_rtmx_get_3d_in_single_size(enum de_3d_in_mode inmode, struct de_rect64 *size) { switch (inmode) { case DE_3D_SRC_MODE_TB: /*size->w = size->w;*/ size->h = size->h >> 1; /*size->x = size->x; size->y = size->y;*/ break; case DE_3D_SRC_MODE_SSF: case DE_3D_SRC_MODE_SSH: size->w = size->w >> 1; /*size->h = size->h; size->x = size->x; size->y = size->y;*/ break; case DE_3D_SRC_MODE_LI: /*size->w = size->w;*/ size->h = size->h >> 1; /*size->x = size->x;*/ size->y = size->y >> 1; break; case DE_3D_SRC_MODE_FP: /*size->w = size->w; size->h = size->h; size->x = size->x; size->y = size->y;*/ break; default: /* undefine input mode */ break; } return 0; } int de_rtmx_get_3d_in(unsigned char fmt, struct de_rect crop, struct de_fb *size, unsigned int *align, enum de_3d_in_mode trdinmode, unsigned int *addr, unsigned int *trd_addr, unsigned int *pitch, unsigned int *pitchr, unsigned int *lay_laddr) { unsigned int ycnt, ucnt, data_type; unsigned int image_w0, image_w1, image_w2, image_h0, image_h1, image_h2; ycnt = ucnt = 0; if (trdinmode == DE_3D_SRC_NORMAL) return -1; if (fmt <= DE_FORMAT_BGRX_8888) { ycnt = 4; data_type = 0x0; } else if (fmt <= DE_FORMAT_BGR_888) { ycnt = 3; data_type = 0x0; } else if (fmt <= DE_FORMAT_BGRA_5551) { ycnt = 2; data_type = 0x0; } else if (fmt <= DE_FORMAT_YUV422_I_VYUY) { ycnt = 2; data_type = 0x0; ucnt = 0; } else if (fmt == DE_FORMAT_YUV422_P) { ycnt = 1; data_type = 0x2; ucnt = 1; } /* YUV422 */ else if (fmt == DE_FORMAT_YUV420_P) { ycnt = 1; data_type = 0x2; ucnt = 1; } /* YUV420 */ else if (fmt == DE_FORMAT_YUV411_P) { ycnt = 1; data_type = 0x2; ucnt = 1; } /* YUV411 */ else if (fmt <= DE_FORMAT_YUV422_SP_VUVU) { ycnt = 1; data_type = 0x1; ucnt = 2; } else if (fmt <= DE_FORMAT_YUV420_SP_VUVU) { ycnt = 1; data_type = 0x1; ucnt = 2; } else if (fmt <= DE_FORMAT_YUV411_SP_VUVU) { ycnt = 1; data_type = 0x1; ucnt = 2; } else { ycnt = 4; data_type = 0x0; } switch (fmt) { case DE_FORMAT_YUV420_P: case DE_FORMAT_YUV420_SP_VUVU: case DE_FORMAT_YUV420_SP_UVUV: image_w0 = crop.w; image_w2 = image_w1 = crop.w >> 1; image_h0 = crop.h; image_h2 = image_h1 = crop.h >> 1; break; case DE_FORMAT_YUV422_P: case DE_FORMAT_YUV422_SP_VUVU: case DE_FORMAT_YUV422_SP_UVUV: image_w0 = crop.w; image_w2 = image_w1 = crop.w >> 1; image_h0 = crop.h; image_h2 = image_h1 = image_h0; break; case DE_FORMAT_YUV411_P: case DE_FORMAT_YUV411_SP_VUVU: case DE_FORMAT_YUV411_SP_UVUV: image_w0 = crop.w; image_w2 = image_w1 = crop.w >> 2; image_h0 = crop.h; image_h2 = image_h1 = image_h0; break; default: image_w0 = crop.w; image_w2 = image_w1 = image_w0; image_h0 = crop.h; image_h2 = image_h1 = image_h0; break; } /* planar */ if (data_type == 0x2) { if (trdinmode == DE_3D_SRC_MODE_TB) { pitchr[0] = pitch[0] = DISPALIGN(size[0].w, align[0]); pitchr[1] = pitch[1] = DISPALIGN(size[1].w, align[1]); pitchr[2] = pitch[2] = DISPALIGN(size[2].w, align[2]); lay_laddr[0] = pitch[0] * image_h0 + addr[0]; lay_laddr[1] = pitch[1] * image_h1 + addr[1]; lay_laddr[2] = pitch[2] * image_h2 + addr[2]; } else if (trdinmode == DE_3D_SRC_MODE_FP) { pitchr[0] = pitch[0] = DISPALIGN(size[0].w, align[0]); pitchr[1] = pitch[1] = DISPALIGN(size[1].w, align[1]); pitchr[2] = pitch[2] = DISPALIGN(size[2].w, align[2]); lay_laddr[0] = trd_addr[0]; lay_laddr[1] = trd_addr[1]; lay_laddr[2] = trd_addr[2]; } else if ((trdinmode == DE_3D_SRC_MODE_SSF) || (trdinmode == DE_3D_SRC_MODE_SSH)) { pitchr[0] = pitch[0] = DISPALIGN(size[0].w, align[0]); pitchr[1] = pitch[1] = DISPALIGN(size[1].w, align[1]); pitchr[2] = pitch[2] = DISPALIGN(size[2].w, align[2]); lay_laddr[0] = image_w0 + addr[0]; lay_laddr[1] = image_w1 + addr[1]; lay_laddr[2] = image_w2 + addr[2]; } else if (trdinmode == DE_3D_SRC_MODE_LI) { pitchr[0] = pitch[0] = (DISPALIGN(size[0].w, align[0])) << 1; pitchr[1] = pitch[1] = (DISPALIGN(size[1].w, align[1])) << 1; pitchr[2] = pitch[2] = (DISPALIGN(size[2].w, align[2])) << 1; lay_laddr[0] = DISPALIGN(size[0].w, align[0]) + addr[0]; lay_laddr[1] = DISPALIGN(size[1].w, align[1]) + addr[1]; lay_laddr[2] = DISPALIGN(size[2].w, align[2]) + addr[2]; } } else if (data_type == 0x0) /* interleaved */ { if (trdinmode == DE_3D_SRC_MODE_FP) { pitchr[0] = pitch[0] = DISPALIGN(size[0].w * ycnt, align[0]) / ycnt; pitchr[1] = pitch[1] = 0; pitchr[2] = pitch[2] = 0; lay_laddr[0] = trd_addr[0]; lay_laddr[1] = 0; lay_laddr[2] = 0; } else if (trdinmode == DE_3D_SRC_MODE_TB) { pitchr[0] = pitch[0] = DISPALIGN(size[0].w * ycnt, align[0]) / ycnt; pitchr[1] = pitch[1] = 0; pitchr[2] = pitch[2] = 0; lay_laddr[0] = pitch[0] * image_h0 * ycnt + addr[0]; lay_laddr[1] = 0; lay_laddr[2] = 0; } else if ((trdinmode == DE_3D_SRC_MODE_SSF) || (trdinmode == DE_3D_SRC_MODE_SSH)) { pitchr[0] = pitch[0] = DISPALIGN(size[0].w * ycnt, align[0]) / ycnt; pitchr[1] = pitch[1] = 0; pitchr[2] = pitch[2] = 0; lay_laddr[0] = image_w0 * ycnt + addr[0]; lay_laddr[1] = 0; lay_laddr[2] = 0; } else if (trdinmode == DE_3D_SRC_MODE_LI) { pitchr[0] = pitch[0] = (DISPALIGN(size[0].w, align[0])) << 1; pitchr[1] = pitch[1] = 0; pitchr[2] = pitch[2] = 0; lay_laddr[0] = (DISPALIGN(size[0].w, align[0])) * ycnt + addr[0]; lay_laddr[1] = 0; lay_laddr[2] = 0; } } else if (data_type == 0x1) /* semi-planar */ { if ((trdinmode == DE_3D_SRC_MODE_SSF) || (trdinmode == DE_3D_SRC_MODE_SSH)) { pitchr[0] = pitch[0] = DISPALIGN(size[0].w, align[0]); pitchr[1] = pitch[1] = DISPALIGN(size[1].w, align[1]); pitchr[2] = pitch[2] = 0; lay_laddr[0] = image_w0 + addr[0]; lay_laddr[1] = (image_w1 * ucnt) + addr[1]; lay_laddr[2] = 0; } else if (trdinmode == DE_3D_SRC_MODE_TB) { pitchr[0] = pitch[0] = DISPALIGN(size[0].w, align[0]); pitchr[1] = pitch[1] = DISPALIGN(size[1].w, align[1]); pitchr[2] = pitch[2] = 0; lay_laddr[0] = pitch[0] * image_h0 + addr[0]; lay_laddr[1] = pitch[1] * image_h1 * ucnt + addr[1]; lay_laddr[2] = 0; } else if (trdinmode == DE_3D_SRC_MODE_FP) { pitchr[0] = pitch[0] = DISPALIGN(size[0].w, align[0]); pitchr[1] = pitch[1] = DISPALIGN(size[1].w, align[1]); pitchr[2] = pitch[2] = 0; lay_laddr[0] = trd_addr[0]; lay_laddr[1] = trd_addr[1]; lay_laddr[2] = 0; } else if (trdinmode == DE_3D_SRC_MODE_LI) { pitchr[0] = pitch[0] = (DISPALIGN(size[0].w, align[0])) << 1; pitchr[1] = pitch[1] = (DISPALIGN(size[1].w, align[1])) << 1; pitchr[2] = pitch[2] = 0; lay_laddr[0] = addr[0] + DISPALIGN(size[1].w, align[1]); lay_laddr[1] = addr[1] + (DISPALIGN(size[1].w, align[1])) * ucnt; lay_laddr[2] = 0; } } return 0; } int de_rtmx_get_li_addr_offset(unsigned int size, unsigned int align, unsigned int x, unsigned int y, unsigned int cnt) { unsigned int offset; offset = DISPALIGN(size, align) * (y >> 1) + x * cnt; return offset; } int de_rtmx_get_3d_out(struct de_rect frame0, unsigned int scn_w, unsigned int scn_h, enum de_3d_out_mode trdoutmode, struct de_rect *frame1) { switch (trdoutmode) { case DE_3D_OUT_MODE_CI_1: case DE_3D_OUT_MODE_CI_2: case DE_3D_OUT_MODE_CI_3: case DE_3D_OUT_MODE_CI_4: case DE_3D_OUT_MODE_SSF: case DE_3D_OUT_MODE_SSH: { frame1->x = frame0.x + scn_w; frame1->y = frame0.y; frame1->w = frame0.w; frame1->h = frame0.h; break; } case DE_3D_OUT_MODE_TB: case DE_3D_OUT_MODE_FP: { frame1->x = frame0.x; frame1->y = frame0.y + (scn_h >> 1); frame1->w = frame0.w; frame1->h = frame0.h; break; } case DE_3D_OUT_MODE_LI: /* enable remapping */ { frame1->x = frame0.x + scn_w; frame1->y = frame0.y; frame1->w = frame0.w; frame1->h = frame0.h; break; } case DE_3D_OUT_MODE_LIRGB: /* enable remapp */ { frame1->x = frame0.x; frame1->y = frame0.y + scn_h; frame1->w = frame0.w; frame1->h = frame0.h; break; } default: break; } __inf("frame0=<%d,%d,%d,%d>\n", frame0.x, frame0.y, frame0.w, frame0.h); __inf("frame1=<%d,%d,%d,%d>\n", frame1->x, frame1->y, frame1->w, frame1->h); return 0; } int de_rtmx_set_lay_fcolor(unsigned int sel, unsigned int chno, unsigned int layno, unsigned char en, unsigned char fmt, unsigned int color) { unsigned int Y, U, V; int vi_chno = de_feat_get_num_vi_chns(sel); if (chno >= vi_chno) { de200_rtmx[sel].ui_ovl[chno - vi_chno] ->ui_lay_cfg[layno].lay_fcolor.dwval = en ? color : 0; ui_attr_block[sel][chno - vi_chno][layno].dirty = 1; } else { Y = color & 0xff0000; switch (fmt) { case DE_FORMAT_YUV422_I_UYVY: case DE_FORMAT_YUV422_I_YUYV: case DE_FORMAT_YUV422_SP_UVUV: case DE_FORMAT_YUV420_SP_UVUV: case DE_FORMAT_YUV411_SP_UVUV: U = (color & 0xff) << 8; V = (color & 0xff00) >> 8; break; default: U = (color & 0xff00); V = (color & 0xff); break; } de200_rtmx[sel].vi_ovl[chno]->vi_lay_fcolor[layno].dwval = en ? ((0xFF << 24) | Y | U | V) : 0; vi_fc_block[sel][chno].dirty = 1; } return 0; } int de_rtmx_set_overlay_size(unsigned int sel, unsigned int chno, unsigned int w, unsigned int h) { int vi_chno = de_feat_get_num_vi_chns(sel); if (chno >= vi_chno) { de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_ovl_size.bits.ovl_width = w == 0 ? 0 : w - 1; de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_ovl_size.bits.ovl_height = h == 0 ? 0 : h - 1; ui_size_block[sel][chno - vi_chno].dirty = 1; } else { de200_rtmx[sel].vi_ovl[chno]->vi_ovl_size[0].bits.ovl_width = w == 0 ? 0 : w - 1; de200_rtmx[sel].vi_ovl[chno]->vi_ovl_size[0].bits.ovl_height = h == 0 ? 0 : h - 1; vi_size_block[sel][chno].dirty = 1; } return 0; } static int de_rtmx_get_coarse_fac(unsigned int sel, unsigned int ovl_w, unsigned int ovl_h, unsigned int vsu_outw, unsigned int vsu_outh, unsigned int fmt, unsigned int lcd_fps, unsigned int lcd_height, unsigned int de_freq_mhz, unsigned int *yhm, unsigned int *yhn, unsigned int *yvm, unsigned int *yvn, unsigned int *chm, unsigned int *chn, unsigned int *cvm, unsigned int *cvn, unsigned int *midyw, unsigned int *midyh, unsigned int *midcw, unsigned int *midch) { unsigned int format, wshift, hshift, status; unsigned int tmpyhm, tmpyhn, tmpyvm, tmpyvn; unsigned int tmp, required_speed_ability; unsigned long long update_speed_ability; unsigned int linebuf = 2048; /* 0-422, 1-420, 2-411, 3-no mean */ switch (fmt) { case DE_FORMAT_YUV422_I_YVYU: case DE_FORMAT_YUV422_I_YUYV: case DE_FORMAT_YUV422_I_UYVY: case DE_FORMAT_YUV422_I_VYUY: case DE_FORMAT_YUV422_P: case DE_FORMAT_YUV422_SP_UVUV: case DE_FORMAT_YUV422_SP_VUVU: format = 0; break; case DE_FORMAT_YUV420_P: case DE_FORMAT_YUV420_SP_UVUV: case DE_FORMAT_YUV420_SP_VUVU: format = 1; break; case DE_FORMAT_YUV411_P: case DE_FORMAT_YUV411_SP_UVUV: case DE_FORMAT_YUV411_SP_VUVU: format = 2; break; default: format = 3; break; } if (format == 0) { wshift = 1; hshift = 0; } else if (format == 1) { wshift = 1; hshift = 1; } else if (format == 2) { wshift = 2; hshift = 0; } else { wshift = 0; hshift = 0; } /* floor Y channel size */ ovl_w = ovl_w & (~((1 << wshift) - 1)); ovl_h = ovl_h & (~((1 << hshift) - 1)); status = 0x0; *yhm = 0; *yhn = 0; *chm = 0; *chn = 0; *midyw = ovl_w; *midcw = ovl_w >> wshift; /* add for UI size not scaler */ if ((format > 2) && (ovl_w == vsu_outw) && (ovl_h == vsu_outh)) { *yvm = 0; *yvn = 0; *cvm = 0; *cvn = 0; *midyh = ovl_h; *midch = ovl_h >> hshift; return status; } linebuf = de_feat_get_scale_linebuf(sel); if ((ovl_w > linebuf) && (ovl_w > 8 * vsu_outw)) { tmpyhn = (linebuf < (8 * vsu_outw)) ? linebuf : (8 * vsu_outw); status = 0x1; /* horizontal Y channel */ } else if (ovl_w > linebuf) { tmpyhn = linebuf; status = 0x1; } else if (ovl_w > 8 * vsu_outw) { tmpyhn = 8 * vsu_outw; status = 0x1; } if (status == 0x1) { tmpyhn = tmpyhn & (~((1 << wshift) - 1)); tmpyhm = ovl_w; *yhm = tmpyhm; *yhn = tmpyhn; *chm = *yhm; *chn = *yhn; /* actually fetch horizontal pixel Y channel */ *midyw = tmpyhn; /* actually fetch horizontal pixel C channel */ *midcw = tmpyhn >> wshift; } /*lcd_freq_MHz = lcd_width*lcd_height*lcd_fps/1000000; * *how many overlay line can be fetched during scanning * one lcd line(consider 80% dram efficiency) *update_speed_ability = lcd_width*de_freq_mhz*125/(ovl_w*lcd_freq_MHz); */ /* how many overlay line can be fetched * during scanning one lcd line(consider 80% dram efficiency) */ tmp = lcd_height * lcd_fps * (ovl_w > vsu_outw ? ovl_w : vsu_outw); if (tmp != 0) { update_speed_ability = ((unsigned long long)de_freq_mhz * 80000000); do_div(update_speed_ability, tmp); } else update_speed_ability = 0; /* how many overlay line need to fetch during scanning one lcd line */ required_speed_ability = vsu_outh == 0 ? 0 : ovl_h * 100 / vsu_outh; __inf("%d,%d,%d,%d\n", de_freq_mhz, tmp, vsu_outh, ovl_h); __inf("%lld,%d\n", update_speed_ability, required_speed_ability); /* vertical Y channel */ if (update_speed_ability < required_speed_ability) { /* if ability < required, use coarse scale */ unsigned long long tmp2 = update_speed_ability * vsu_outh; do_div(tmp2, 100); tmpyvn = tmp == 0 ? 0 : (unsigned int)tmp2; tmpyvn = tmpyvn & (~((1 << hshift) - 1)); tmpyvm = ovl_h; *yvm = tmpyvm; *yvn = tmpyvn; *cvm = *yvm; *cvn = *yvn; /* actually fetch vertical pixel Y channel */ *midyh = tmpyvn; /* actually fetch vertical pixel C channel */ *midch = tmpyvn >> hshift; status |= (0x1 << 1); } else if (ovl_h > 4 * vsu_outh) { /* to save dram bandwidth when scale down factor more than 4. */ tmpyvn = 4 * vsu_outh; tmpyvn = tmpyvn & (~((1 << hshift) - 1)); tmpyvm = ovl_h; *yvm = tmpyvm; *yvn = tmpyvn; *cvm = *yvm; *cvn = *yvn; /* actually fetch vertical pixel Y channel */ *midyh = tmpyvn; /* actually fetch vertical pixel C channel */ *midch = tmpyvn >> hshift; status |= (0x1 << 1); } else { *yvm = 0; *yvn = 0; *cvm = 0; *cvn = 0; *midyh = ovl_h; *midch = ovl_h >> hshift; } return status; } /** *function : de_rtmx_set_coarse_fac(unsigned int sel, unsigned int fmt, * unsigned int ovl_w, unsigned int ovl_h,unsigned int vsu_outw, * unsigned int vsu_outh, unsigned int *midyw, unsigned int *midyh, * unsigned int *midcw, unsigned int *midch) *description: set de reg base *parameters : * sel * fmt * ovl_w,ovl_h * vsu_outw,vsu_outh * *midyw,*midyh * *midcw,*midch *return : * success */ int de_rtmx_set_coarse_fac(unsigned int sel, unsigned char chno, unsigned int fmt, unsigned int lcd_fps, unsigned int lcd_height, unsigned int de_freq_mhz, unsigned int ovl_w, unsigned int ovl_h, unsigned int vsu_outw, unsigned int vsu_outh, unsigned int *midyw, unsigned int *midyh, unsigned int *midcw, unsigned int *midch) { unsigned int yhm, yhn, yvm, yvn, chm, chn, cvm, cvn; int status; status = de_rtmx_get_coarse_fac(sel, ovl_w, ovl_h, vsu_outw, vsu_outh, fmt, lcd_fps, lcd_height, de_freq_mhz, &yhm, &yhn, &yvm, &yvn, &chm, &chn, &cvm, &cvn, midyw, midyh, midcw, midch); de200_rtmx[sel].vi_ovl[chno]->vi_hori_ds[0].bits.m = yhm; de200_rtmx[sel].vi_ovl[chno]->vi_hori_ds[0].bits.n = yhn; de200_rtmx[sel].vi_ovl[chno]->vi_hori_ds[1].bits.m = chm; de200_rtmx[sel].vi_ovl[chno]->vi_hori_ds[1].bits.n = chn; de200_rtmx[sel].vi_ovl[chno]->vi_vert_ds[0].bits.m = yvm; de200_rtmx[sel].vi_ovl[chno]->vi_vert_ds[0].bits.n = yvn; de200_rtmx[sel].vi_ovl[chno]->vi_vert_ds[1].bits.m = cvm; de200_rtmx[sel].vi_ovl[chno]->vi_vert_ds[1].bits.n = cvn; vi_size_block[sel][chno].dirty = 1; return status; } int de_rtmx_set_pf_en(unsigned int sel, unsigned char *pen) { unsigned char fen[4] = { 1, 0, 0, 0 }; de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p0_en = pen[0]; de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p1_en = pen[1]; de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p2_en = pen[2]; de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p3_en = pen[3]; de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p0_fcolor_en = fen[0]; de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p1_fcolor_en = fen[1]; de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p2_fcolor_en = fen[2]; de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p3_fcolor_en = fen[3]; bld_attr_block[sel].dirty = 1; return 0; } int de_rtmx_set_pipe_cfg(unsigned int sel, unsigned char pno, unsigned int color, struct de_rect bldrc) { /* fix the pipe fill color to 0xff000000(alpha=1) * actually, we just want to fix the fill color of the bottom pipe * so only the fill color function of the bottom pipe is enabled * cause: * co = cs + cb * (1 - as), * ao = as + ab * (1 - as), * Co(result) = co / ao * when ab = 0, the result is ( Cs ); * when 1, the result is ( Cs * as ), this is what we want. */ de200_rtmx[sel].bld_ctl->bld_pipe_attr[pno].fcolor.dwval = 0xff000000 | color; de200_rtmx[sel].bld_ctl->bld_pipe_attr[pno].insize.bits.width = bldrc.w == 0 ? 0 : bldrc.w - 1; de200_rtmx[sel].bld_ctl->bld_pipe_attr[pno].insize.bits.height = bldrc.h == 0 ? 0 : bldrc.h - 1; de200_rtmx[sel].bld_ctl->bld_pipe_attr[pno].offset.bits.coorx = bldrc.x; de200_rtmx[sel].bld_ctl->bld_pipe_attr[pno].offset.bits.coory = bldrc.y; bld_attr_block[sel].dirty = 1; return 0; } int de_rtmx_set_route(unsigned int sel, unsigned char pno, unsigned int zoder) { unsigned int route; route = de200_rtmx[sel].bld_ctl->bld_route_ctl.dwval & (~(0xf << (pno << 2))); __inf("sel%d, pno%d, zorder%d, route:0x%x\n", sel, pno, zoder, route); de200_rtmx[sel].bld_ctl->bld_route_ctl.dwval = route | (zoder << (pno << 2)); __inf("addr=0x%p, reg=0x%x\n", &de200_rtmx[sel].bld_ctl->bld_route_ctl, de200_rtmx[sel].bld_ctl->bld_route_ctl.dwval); bld_ctl_block[sel].dirty = 1; return 0; } int de_rtmx_set_premul(unsigned int sel, unsigned char pno, unsigned int pre_mul) { unsigned int pre_mode; pre_mode = de200_rtmx[sel].bld_ctl->bld_premultiply_ctl.dwval & (~(0x1 << pno)); de200_rtmx[sel].bld_ctl->bld_premultiply_ctl.dwval = pre_mode | (pre_mul << pno); bld_ctl_block[sel].dirty = 1; return 0; } int de_rtmx_set_background_color(unsigned int sel, unsigned int color) { de200_rtmx[sel].bld_ctl->bld_bkcolor.dwval = (0xff << 24) | (color & 0xffffff); bld_ctl_block[sel].dirty = 1; return 0; } int de_rtmx_set_blend_size(unsigned int sel, unsigned int w, unsigned int h) { de200_rtmx[sel].bld_ctl->bld_output_size.bits.width = w == 0 ? 0 : w - 1; de200_rtmx[sel].bld_ctl->bld_output_size.bits.height = h == 0 ? 0 : h - 1; bld_ctl_block[sel].dirty = 1; return 0; } int de_rtmx_set_blend_mode(unsigned int sel, unsigned int bldno, unsigned char mode) { unsigned int bld_mode; if (mode == DE_BLD_CLEAR) bld_mode = 0x00000000; else if (mode == DE_BLD_SRC) bld_mode = 0x00010001; else if (mode == DE_BLD_DST) bld_mode = 0x01000100; else if (mode == DE_BLD_SRCOVER) bld_mode = 0x03010301; else if (mode == DE_BLD_DSTOVER) bld_mode = 0x01030103; else if (mode == DE_BLD_SRCIN) bld_mode = 0x00020002; else if (mode == DE_BLD_DSTIN) bld_mode = 0x02000200; else if (mode == DE_BLD_SRCOUT) bld_mode = 0x00030003; else if (mode == DE_BLD_DSTOUT) bld_mode = 0x03000300; else if (mode == DE_BLD_SRCATOP) bld_mode = 0x03020302; else if (mode == DE_BLD_DSTATOP) bld_mode = 0x02030203; else if (mode == DE_BLD_XOR) bld_mode = 0x03030303; else bld_mode = 0x03010301; de200_rtmx[sel].bld_ctl->bld_mode[bldno].dwval = bld_mode; bld_ctl_block[sel].dirty = 1; return 0; } int de_rtmx_set_blend_color(unsigned int sel, unsigned int bldno, unsigned int color) { de200_rtmx[sel].bld_ctl->bld_pipe_attr[bldno].fcolor.dwval = (0xff << 24) | (color & 0xffffff); bld_attr_block[sel].dirty = 1; return 0; } int de_rtmx_set_outitl(unsigned int sel, unsigned char interlace_en) { de200_rtmx[sel].bld_ctl->bld_out_ctl.bits.interlace_en = interlace_en & 0x1; de200_rtmx[sel].bld_ctl->bld_out_ctl.bits.premultiply_en = 0x0; bld_out_block[sel].dirty = 1; return 0; } int de_rtmx_set_colorkey(unsigned int sel, unsigned char ck_no, unsigned char ck_mode, unsigned char ck_red_match, unsigned char ck_green_match, unsigned char ck_blue_match, unsigned int ck_max, unsigned int ck_min) { unsigned int tmp, ck_match; tmp = de200_rtmx[sel].bld_ctl->bld_ck_ctl. dwval & (~(0x6 << (0x2 << ck_no))); de200_rtmx[sel].bld_ctl->bld_ck_ctl.dwval = tmp | (ck_mode << (0x2 << (ck_no + 0x1))); ck_match = (ck_red_match << 2) | (ck_green_match << 1) | ck_blue_match; tmp = de200_rtmx[sel].bld_ctl->bld_ck_cfg. dwval & (~(0x7 << (ck_no << 8))); de200_rtmx[sel].bld_ctl->bld_ck_ctl.dwval = tmp | (ck_match << (ck_no << 8)); de200_rtmx[sel].bld_ctl->bld_ck_max[ck_no].dwval = ck_max & 0xffffff; de200_rtmx[sel].bld_ctl->bld_ck_min[ck_no].dwval = ck_min & 0xffffff; bld_ck_block[sel].dirty = 1; return 0; } struct de_rect de_rtmx_extend_rect(struct de_rect rc1, struct de_rect rc2) { struct de_rect rc; int xmax, ymax; if ((rc1.w == 0) || (rc1.h == 0)) return rc2; rc.x = min2(rc1.x, rc2.x); rc.y = min2(rc1.y, rc2.y); xmax = max2(rc1.x + rc1.w, rc2.x + rc2.w); ymax = max2(rc1.y + rc1.h, rc2.y + rc2.h); rc.w = xmax - rc.x; rc.h = ymax - rc.y; return rc; } int de_rtmx_calc_chnrect(unsigned char *lay_en, int laynum, struct de_rect *frame, struct de_rect *crop, int gsu_sel, struct scaler_para *step, struct de_rect *layer, struct de_rect *bld_rect, unsigned int *ovlw, unsigned int *ovlh) { unsigned int i, minx, miny, pipe_en; struct de_rect RCOVL = { 0, 0, 0, 0 }; struct de_rect RCBLD = { 0, 0, 0, 0 }; minx = 0xffffffff; miny = 0xffffffff; /* find min cord */ for (i = 0; i < laynum; i++) { if (lay_en[i]) { minx = min2(frame[i].x, minx); miny = min2(frame[i].y, miny); } } /* recall the layer cord by sub */ for (i = 0; i < laynum; i++) { if (lay_en[i]) { layer[i].x = de_calc_ovl_coord(frame[i].x - minx, step[i].hstep, gsu_sel); layer[i].y = de_calc_ovl_coord(frame[i].y - miny, step[i].vstep, gsu_sel); layer[i].w = crop[i].w; layer[i].h = crop[i].h; __inf("layernum=%d, i=%d\n", laynum, i); __inf("crop=<%d,%d,%d,%d>\n", crop[i].x, crop[i].y, crop[i].w, crop[i].h); __inf("layer=<%d,%d,%d,%d>\n", layer[i].x, layer[i].y, layer[i].w, layer[i].h); } } for (i = 0; i < laynum; i++) { if (lay_en[i]) { RCOVL = de_rtmx_extend_rect(RCOVL, layer[i]); RCBLD = de_rtmx_extend_rect(RCBLD, frame[i]); __inf("ovl_rect=<%d,%d,%d,%d>\n", RCOVL.x, RCOVL.y, RCOVL.w, RCOVL.h); __inf("bld_rect=<%d,%d,%d,%d>\n", RCBLD.x, RCBLD.y, RCBLD.w, RCBLD.h); } } *ovlw = RCOVL.w; *ovlh = RCOVL.h; bld_rect->x = RCBLD.x; bld_rect->y = RCBLD.y; bld_rect->w = RCBLD.w; bld_rect->h = RCBLD.h; pipe_en = 1; if ((RCBLD.w == 0) || (RCBLD.h == 0)) pipe_en = 0; return pipe_en; } /* ycbcr odd/even */ int de_rtmx_trimcoord(struct de_rect *frame, struct de_rect *crop, unsigned int outw, unsigned int outh, int xratio, int yratio) { int left, right, up, down; int cut_up, cut_down, cut_left, cut_right; int hstep, vstep, hphase, vphase; if ((frame->w == 0) || (frame->h == 0)) { hstep = vstep = 0; hphase = vphase = 0; xratio = hstep; yratio = vstep; return 0; } /* calculate scaler step size */ hstep = (crop->w << 18) / frame->w; vstep = (crop->h << 18) / frame->h; /* calculate scaling ratio */ xratio = hstep; yratio = vstep; /* assume only frame coordinate has negative value */ left = up = 0; cut_left = cut_right = cut_up = cut_down = 0; if (((frame->x + (int)frame->w) < 0) || ((frame->x - outw) > 0)) { /* out of screen */ frame->w = frame->x = 0; } else if (frame->x < 0) { /* cut left */ left = (((-frame->x) * crop->w) << 18) / frame->w; cut_left = (int)(left >> 18); frame->w += frame->x; frame->x = 0; } else if ((frame->x + frame->w) > outw) { /* cut right */ right = (((frame->x + frame->w - outw) * crop->h) << 18) / frame->h; cut_right = (int)(right >> 18); frame->w = outw - frame->x; } crop->x += cut_left; crop->w -= (cut_left + cut_right); hphase = (int)(left & 0x3ffff); if (((frame->y + (int)frame->h) < 0) || ((frame->y - outh) > 0)) { /* out of screen */ frame->h = frame->y = 0; } else if (frame->y < 0) { /* cut up */ up = (((-frame->y) * crop->h) << 18) / frame->h; cut_up = (int)(up >> 18); frame->h += frame->y; frame->y = 0; } else if ((frame->y + frame->h) > outh) { /* cut down */ down = (((frame->y + frame->h - outh) * crop->h) << 18) / frame->h; cut_down = (int)(down >> 18); frame->h = outh - frame->y; } crop->y += cut_up; crop->h -= (cut_up + cut_down); vphase = (int)(up & 0x3ffff); return 0; } int de_rtmx_get_premul_ctl(int laynum, unsigned char *premul) { int i, same, pipe_mode; same = 0; pipe_mode = 1; for (i = 0; i < laynum; i++) same += premul[i]; for (i = 0; i < laynum; i++) { if (premul[i]) { premul[i] = 2; } else if (same == 0) /* all zero */ { pipe_mode = 0; premul[i] = 0; } else { premul[i] = 1; } } return pipe_mode; } int de_rtmx_mux(unsigned int sel, unsigned int tcon_index) { u32 reg_val; if (sel == tcon_index) { reg_val = readl((void __iomem *)(de_base + 0x10)); reg_val &= ~0x1; writel(reg_val, (void __iomem *)(de_base + 0x10)); } else { reg_val = readl((void __iomem *)(de_base + 0x10)); reg_val |= 0x1; writel(reg_val, (void __iomem *)(de_base + 0x10)); } return 0; } int de_rtmx_get_mux(unsigned int sel) { u32 reg_val; reg_val = readl((void __iomem *)(de_base + 0x10)); reg_val &= 0x1; return (reg_val == 0) ? (sel) : (1 - sel); } int de_rtmx_sync_hw(unsigned int sel) { int i, j, ui_chno, vi_chno, layno; vi_chno = de_feat_get_num_vi_chns(sel); ui_chno = de_feat_get_num_ui_chns(sel); layno = LAYER_MAX_NUM_PER_CHN; memcpy(glb_ctl_block[sel].val, (void *)glb_ctl_block[sel].off, glb_ctl_block[sel].size); for (j = 0; j < vi_chno; j++) { for (i = 0; i < layno; i++) { memcpy(vi_attr_block[sel][j][i].val, (void *)vi_attr_block[sel][j][i].off, vi_attr_block[sel][j][i].size); } memcpy(vi_fc_block[sel][j].val, (void *)vi_fc_block[sel][j].off, vi_fc_block[sel][j].size); memcpy(vi_haddr_block[sel][j].val, (void *)vi_haddr_block[sel][j].off, vi_haddr_block[sel][j].size); memcpy(vi_size_block[sel][j].val, (void *)vi_size_block[sel][j].off, vi_size_block[sel][j].size); } for (j = 0; j < ui_chno; j++) { for (i = 0; i < layno; i++) { memcpy(ui_attr_block[sel][j][i].val, (void *)ui_attr_block[sel][j][i].off, ui_attr_block[sel][j][i].size); } memcpy(ui_haddr_block[sel][j].val, (void *)ui_haddr_block[sel][j].off, ui_haddr_block[sel][j].size); memcpy(ui_size_block[sel][j].val, (void *)ui_size_block[sel][j].off, ui_size_block[sel][j].size); } memcpy(bld_attr_block[sel].val, (void *)bld_attr_block[sel].off, bld_attr_block[sel].size); memcpy(bld_ctl_block[sel].val, (void *)bld_ctl_block[sel].off, bld_ctl_block[sel].size); memcpy(bld_ck_block[sel].val, (void *)bld_ck_block[sel].off, bld_ck_block[sel].size); memcpy(bld_out_block[sel].val, (void *)bld_out_block[sel].off, bld_out_block[sel].size); return 0; } int de_rtmx_get_lay_enabled(unsigned int sel, unsigned int chno, unsigned int layno) { int vi_chno = de_feat_get_num_vi_chns(sel); int ret = 0; if (chno >= vi_chno) { ret = de200_rtmx[sel].ui_ovl[chno - vi_chno] ->ui_lay_cfg[layno].lay_attr.bits.lay_en; } else { ret = de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno] .lay_attr.bits.lay_en; } return ret; } int de_rtmx_get_lay_address(unsigned int sel, unsigned int chno, unsigned int layno, unsigned long long *addr) { int vi_chno = de_feat_get_num_vi_chns(sel); int ret = 0; unsigned long long tmp; if (chno >= vi_chno) { addr[0] = de200_rtmx[sel].ui_ovl[chno - vi_chno]-> ui_lay_cfg[layno].lay_top_laddr.dwval; /* low address */ tmp = de200_rtmx[sel].ui_ovl[chno - vi_chno] ->ui_lay_top_haddr.dwval & (0xff << layno); /* high address */ addr[0] |= tmp << 32; addr[1] = 0; addr[2] = 0; } else { addr[0] = de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno]. lay_top_laddr[0].dwval; addr[1] = de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno]. lay_top_laddr[1].dwval; addr[2] = de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno]. lay_top_laddr[2].dwval; tmp = de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[0].dwval & (0xff << layno); /* high address */ addr[0] |= tmp << 32; tmp = de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[1].dwval & (0xff << layno); addr[1] |= tmp << 32; tmp = de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[2].dwval & (0xff << layno); addr[2] |= tmp << 32; } return ret; } int de_rtmx_get_lay_size(unsigned int sel, unsigned int chno, unsigned int layno, struct disp_rectsz *size) { int vi_chno = de_feat_get_num_vi_chns(sel); int ret = 0; int fmt, ycnt = 4, ucnt = 2; if (chno >= vi_chno) { fmt = de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].lay_attr. bits.lay_fmt; if (fmt <= DE_FORMAT_BGRX_8888) ycnt = 4; else if (fmt <= DE_FORMAT_BGR_888) ycnt = 3; else if (fmt <= DE_FORMAT_BGRA_5551) ycnt = 2; else ycnt = 4; size[0].width = de200_rtmx[sel].ui_ovl[chno - vi_chno]-> ui_lay_cfg[layno].lay_pitch.dwval / ycnt; /* fixme,according to format */ size[0].height = de200_rtmx[sel].ui_ovl[chno - vi_chno] ->ui_lay_cfg[layno].lay_size.bits.lay_height; } else { fmt = de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr. bits.lay_fmt; if (fmt <= DE_FORMAT_BGRX_8888) { ycnt = 4; } else if (fmt <= DE_FORMAT_BGR_888) { ycnt = 3; } else if (fmt <= DE_FORMAT_BGRA_5551) { ycnt = 2; } else if (fmt <= DE_FORMAT_YUV422_I_VYUY) { ycnt = 2; } else if (fmt == DE_FORMAT_YUV422_P) { ycnt = 1; ucnt = 1; } /* YUV422 */ else if (fmt == DE_FORMAT_YUV420_P) { ycnt = 1; ucnt = 1; } /* YUV420 */ else if (fmt == DE_FORMAT_YUV411_P) { ycnt = 1; ucnt = 1; } /* YUV411 */ else if (fmt <= DE_FORMAT_YUV422_SP_VUVU) { ycnt = 1; ucnt = 2; } else if (fmt <= DE_FORMAT_YUV420_SP_VUVU) { ycnt = 1; ucnt = 2; } else if (fmt <= DE_FORMAT_YUV411_SP_VUVU) { ycnt = 1; ucnt = 2; } else { ycnt = 4; } size[0].width = de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno]. lay_pitch[0].dwval / ycnt; size[1].width = de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno]. lay_pitch[1].dwval / ucnt; size[2].width = de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno]. lay_pitch[2].dwval / ucnt; size[0].height = de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_size. bits.lay_height; size[2].height = size[1].height = size[0].height; } return ret; } int de_rtmx_get_lay_win(unsigned int sel, unsigned int chno, unsigned int layno, struct disp_rect *win) { int vi_chno = de_feat_get_num_vi_chns(sel); int ret = 0; if (chno >= vi_chno) { win->width = de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno]. lay_size.bits.lay_width + 1; win->height = de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno]. lay_size.bits.lay_height + 1; } else { win->width = de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_size. bits.lay_width + 1; win->height = de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_size. bits.lay_height + 1; } return ret; } int de_rtmx_get_display_size(unsigned int sel, unsigned int *width, unsigned int *height) { *width = de200_rtmx[sel].glb_ctl->glb_size.bits.width + 1; *height = de200_rtmx[sel].glb_ctl->glb_size.bits.height + 1; return 0; } int de_rtmx_get_lay_format(unsigned int sel, unsigned int chno, unsigned int layno) { int vi_chno = de_feat_get_num_vi_chns(sel); int fmt = 0; if (chno >= vi_chno) { fmt = de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno]. lay_attr.bits.lay_fmt; } else { fmt = de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr. bits.lay_fmt; if (fmt == 0) fmt = DE_FORMAT_YUV422_I_VYUY; else if (fmt == 1) fmt = DE_FORMAT_YUV422_I_YVYU; else if (fmt == 2) fmt = DE_FORMAT_YUV422_I_UYVY; else if (fmt == 3) fmt = DE_FORMAT_YUV422_I_YUYV; else if (fmt == 4) fmt = DE_FORMAT_YUV422_SP_UVUV; else if (fmt == 5) fmt = DE_FORMAT_YUV422_SP_VUVU; else if (fmt == 6) fmt = DE_FORMAT_YUV422_P; else if (fmt == 8) fmt = DE_FORMAT_YUV420_SP_UVUV; else if (fmt == 9) fmt = DE_FORMAT_YUV420_SP_VUVU; else if (fmt == 0xa) fmt = DE_FORMAT_YUV420_P; else if (fmt == 0xc) fmt = DE_FORMAT_YUV411_SP_UVUV; else if (fmt == 0xd) fmt = DE_FORMAT_YUV411_SP_VUVU; else if (fmt == 0xe) fmt = DE_FORMAT_YUV411_P; } return fmt; }