/*
|
* drivers/video/sunxi/disp2/disp/de/lowlevel_v2x/de_gsu.c
|
*
|
* Copyright (c) 2007-2019 Allwinnertech Co., Ltd.
|
* Author: zhengxiaobin <zhengxiaobin@allwinnertech.com>
|
*
|
* This software is licensed under the terms of the GNU General Public
|
* License version 2, as published by the Free Software Foundation, and
|
* may be copied, distributed, and modified under those terms.
|
*
|
* This program is distributed in the hope that it will be useful,
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* GNU General Public License for more details.
|
*
|
*/
|
#include "de_feat.h"
|
#include "de_gsu_type.h"
|
#include "de_scaler.h"
|
#include "de_scaler_table.h"
|
|
static struct __gsu_reg_t *gsu_dev[DE_NUM][UI_CHN_NUM];
|
static struct de_reg_blocks gsu_glb_block[DE_NUM][UI_CHN_NUM];
|
static struct de_reg_blocks gsu_out_block[DE_NUM][UI_CHN_NUM];
|
static struct de_reg_blocks gsu_scale_block[DE_NUM][UI_CHN_NUM];
|
static struct de_reg_blocks gsu_coeff_block[DE_NUM][UI_CHN_NUM];
|
|
int de_gsu_init(unsigned int sel, uintptr_t reg_base)
|
{
|
int j, chno;
|
uintptr_t gsu_base;
|
void *memory;
|
int vi_chno;
|
int gsu_offset;
|
|
chno = de_feat_is_support_scale(sel);
|
vi_chno = de_feat_get_num_vi_chns(sel);
|
chno = chno - vi_chno;
|
|
gsu_offset = VSU_OFST + vi_chno * 0x20000;
|
|
for (j = 0; j < chno; j++) {
|
gsu_base = reg_base + (sel + 1) * 0x00100000 + gsu_offset
|
+ j * 0x10000;
|
#if defined(CONFIG_INDEPENDENT_DE)
|
if (sel)
|
gsu_base = gsu_base - 0x00100000;
|
#endif
|
|
memory = kmalloc(sizeof(struct __gsu_reg_t),
|
GFP_KERNEL | __GFP_ZERO);
|
if (NULL == memory) {
|
__wrn("malloc uscaler[%d][%d] memory fail! size=0x%x\n",
|
sel,
|
j,
|
(unsigned int)sizeof(struct __gsu_reg_t));
|
return -1;
|
}
|
|
gsu_glb_block[sel][j].off = gsu_base;
|
gsu_glb_block[sel][j].val = memory;
|
gsu_glb_block[sel][j].size = 0x14;
|
gsu_glb_block[sel][j].dirty = 0;
|
|
gsu_out_block[sel][j].off = gsu_base + 0x40;
|
gsu_out_block[sel][j].val = memory + 0x40;
|
gsu_out_block[sel][j].size = 0x4;
|
gsu_out_block[sel][j].dirty = 0;
|
|
gsu_scale_block[sel][j].off = gsu_base + 0x80;
|
gsu_scale_block[sel][j].val = memory + 0x80;
|
gsu_scale_block[sel][j].size = 0x20;
|
gsu_scale_block[sel][j].dirty = 0;
|
|
gsu_coeff_block[sel][j].off = gsu_base + 0x200;
|
gsu_coeff_block[sel][j].val = memory + 0x200;
|
gsu_coeff_block[sel][j].size = 0x40;
|
gsu_coeff_block[sel][j].dirty = 0;
|
|
de_gsu_set_reg_base(sel, j, memory);
|
}
|
|
return 0;
|
}
|
|
int de_gsu_update_regs(unsigned int sel)
|
{
|
int i, chno;
|
|
chno = de_feat_is_support_scale(sel);
|
chno = chno - de_feat_get_num_vi_chns(sel);
|
|
for (i = 0; i < chno; i++) {
|
if (gsu_glb_block[sel][i].dirty == 0x1) {
|
memcpy((void *)gsu_glb_block[sel][i].off,
|
gsu_glb_block[sel][i].val,
|
gsu_glb_block[sel][i].size);
|
gsu_glb_block[sel][i].dirty = 0x0;
|
}
|
if (gsu_out_block[sel][i].dirty == 0x1) {
|
memcpy((void *)gsu_out_block[sel][i].off,
|
gsu_out_block[sel][i].val,
|
gsu_out_block[sel][i].size);
|
gsu_out_block[sel][i].dirty = 0x0;
|
}
|
if (gsu_scale_block[sel][i].dirty == 0x1) {
|
memcpy((void *)gsu_scale_block[sel][i].off,
|
gsu_scale_block[sel][i].val,
|
gsu_scale_block[sel][i].size);
|
gsu_scale_block[sel][i].dirty = 0x0;
|
}
|
if (gsu_coeff_block[sel][i].dirty == 0x1) {
|
memcpy((void *)gsu_coeff_block[sel][i].off,
|
gsu_coeff_block[sel][i].val,
|
gsu_coeff_block[sel][i].size);
|
gsu_coeff_block[sel][i].dirty = 0x0;
|
}
|
|
}
|
|
return 0;
|
}
|
|
/**
|
* function : de_gsu_set_reg_base(unsigned int sel,
|
* unsigned int chno,
|
* void *base)
|
* description : set gsu reg base
|
* parameters :
|
* sel <rtmx select>
|
* chno <overlay select>
|
* base <reg base>
|
* return :
|
* success
|
*/
|
int de_gsu_set_reg_base(unsigned int sel, unsigned int chno, void *base)
|
{
|
__inf("sel=%d, chno=%d, base=0x%p\n", sel, chno, base);
|
gsu_dev[sel][chno] = (struct __gsu_reg_t *) base;
|
|
return 0;
|
}
|
|
/**
|
* function : de_gsu_enable(unsigned int sel,
|
* unsigned int chno, unsigned int en)
|
* description : enable/disable gsu
|
* parameters :
|
* sel <rtmx select>
|
* chno <overlay select>
|
* en <enable: 0-diable; 1-enable>
|
* return :
|
* success
|
*/
|
int de_gsu_enable(unsigned int sel, unsigned int chno, unsigned int en)
|
{
|
gsu_dev[sel][chno - VI_CHN_NUM]->ctrl.bits.en = en;
|
gsu_glb_block[sel][chno - VI_CHN_NUM].dirty = 1;
|
|
return 0;
|
}
|
|
/**
|
* function : de_gsu_set_fir_coef(unsigned int sel,
|
* unsigned int chno,
|
* unsigned int *coef)
|
* description : set fir coefficients
|
* parameters :
|
* sel <rtmx select>
|
* chno <overlay select>
|
* *coef <coefficients pointer>
|
* return :
|
* success
|
*/
|
/*static int de_gsu_set_fir_coef(unsigned int sel, unsigned int chno,
|
* unsigned int *coef)
|
*{
|
* memcpy(&gsu_dev[sel][chno-VI_CHN_NUM]->hcoeff, coef,
|
* sizeof(unsigned int)*GSU_PHASE_NUM);
|
*
|
* return 0;
|
*}
|
*/
|
|
/*
|
* function : de_gsu_calc_fir_coef(unsigned int step)
|
* description : set fir coefficients
|
* parameters :
|
* step <horizontal scale ratio of gsu>
|
* return :
|
* offset (in word) of coefficient table
|
*/
|
static unsigned int de_gsu_calc_fir_coef(unsigned int step)
|
{
|
unsigned int pt_coef;
|
unsigned int scale_ratio, int_part, float_part, fir_coef_ofst;
|
|
scale_ratio = step >> (GSU_PHASE_FRAC_BITWIDTH - 3);
|
int_part = scale_ratio >> 3;
|
float_part = scale_ratio & 0x7;
|
fir_coef_ofst = (int_part == 0) ? GSU_ZOOM0_SIZE :
|
(int_part == 1) ? GSU_ZOOM0_SIZE + float_part :
|
(int_part == 2) ? GSU_ZOOM0_SIZE + GSU_ZOOM1_SIZE
|
+ (float_part >> 1) :
|
(int_part == 3) ? GSU_ZOOM0_SIZE + GSU_ZOOM1_SIZE
|
+ GSU_ZOOM2_SIZE :
|
(int_part == 4) ? GSU_ZOOM0_SIZE + GSU_ZOOM1_SIZE
|
+ GSU_ZOOM2_SIZE + GSU_ZOOM3_SIZE :
|
GSU_ZOOM0_SIZE + GSU_ZOOM1_SIZE + GSU_ZOOM2_SIZE
|
+ GSU_ZOOM3_SIZE + GSU_ZOOM4_SIZE;
|
|
pt_coef = fir_coef_ofst * GSU_PHASE_NUM;
|
|
return pt_coef;
|
}
|
|
/**
|
* function : de_gsu_set_para(unsigned int sel, unsigned int chno,
|
* unsigned int *coef)
|
* description : set fir coefficients
|
* parameters :
|
* sel <rtmx select>
|
* chno <overlay select>
|
* *coef <coefficients pointer>
|
* return :
|
* success
|
*/
|
int de_gsu_set_para(unsigned int sel, unsigned int chno, unsigned int enable,
|
unsigned int in_w, unsigned int in_h,
|
unsigned int out_w, unsigned int out_h,
|
struct scaler_para *para)
|
{
|
unsigned int pt_coef;
|
unsigned int chno_t;
|
unsigned int vi_chno;
|
|
vi_chno = de_feat_get_num_vi_chns(sel);
|
|
chno_t = chno - vi_chno;
|
|
gsu_dev[sel][chno_t]->ctrl.bits.en = enable;
|
|
if (0 == enable) {
|
gsu_glb_block[sel][chno_t].dirty = 1;
|
return 0;
|
}
|
/* basic parameter */
|
gsu_dev[sel][chno_t]->outsize.dwval = ((out_h - 1) << 16) | (out_w - 1);
|
gsu_dev[sel][chno_t]->insize.dwval = ((in_h - 1) << 16) | (in_w - 1);
|
gsu_dev[sel][chno_t]->hstep.dwval
|
= para->hstep << GSU_PHASE_FRAC_REG_SHIFT;
|
gsu_dev[sel][chno_t]->vstep.dwval
|
= para->vstep << GSU_PHASE_FRAC_REG_SHIFT;
|
gsu_dev[sel][chno_t]->hphase.dwval
|
= para->hphase << GSU_PHASE_FRAC_REG_SHIFT;
|
gsu_dev[sel][chno_t]->vphase0.dwval
|
= para->vphase << GSU_PHASE_FRAC_REG_SHIFT;
|
|
/* fir coefficient */
|
pt_coef = de_gsu_calc_fir_coef(para->vstep);
|
memcpy(&gsu_dev[sel][chno_t]->hcoeff, lan2coefftab16 + pt_coef,
|
sizeof(unsigned int) * GSU_PHASE_NUM);
|
gsu_dev[sel][chno_t]->ctrl.bits.coef_switch_rdy = 1;
|
gsu_glb_block[sel][chno_t].dirty = 1;
|
gsu_out_block[sel][chno_t].dirty = 1;
|
gsu_scale_block[sel][chno_t].dirty = 1;
|
gsu_coeff_block[sel][chno_t].dirty = 1;
|
|
return 0;
|
}
|
|
/*****************************************************************************
|
* function : de_gsu_calc_scaler_para(struct de_rect64 crop,
|
* struct de_rect frame,
|
* struct de_rect *crop_fix,
|
* struct scaler_para *para)
|
* description : calculate scaler parameters
|
* parameters :
|
* crop.w <frame buffer crop width with 32bit fraction part>
|
* crop.h <frame buffer crop height with 32bit fraction part>
|
* crop.x <frame buffer coordinate x with 32bit fraction part>
|
* crop.y <frame buffer coordinate y with 32bit fraction part>
|
* frame.w <frame width in integer>
|
* frame.h <frame height in integer>
|
* crop_fix->w <framebuffer crop_fix width after fixed>
|
* crop_fix->h <framebuffer crop_fix height after fixed>
|
* crop_fix->x <framebuffer crop_fix coordinate x after fixed>
|
* crop_fix->y <framebuffer crop_fix coordinate y after fixed>
|
* hstep <horizon scale ratio>
|
* vstep <vertical scale ratio>
|
* hphase <horizon initial phase>
|
* vphase <vertical initial phase>
|
* return :
|
* success
|
*/
|
int de_gsu_calc_scaler_para(struct de_rect64 crop, struct de_rect frame,
|
struct de_rect *crop_fix, struct scaler_para *para)
|
{
|
unsigned long long tmp = 0;
|
|
tmp = (N2_POWER(crop.w, GSU_PHASE_FRAC_BITWIDTH));
|
if (frame.w)
|
do_div(tmp, frame.w);
|
else
|
tmp = 0;
|
para->hstep = (unsigned int)(tmp >> GSU_FB_FRAC_BITWIDTH);
|
|
tmp = (N2_POWER(crop.h, GSU_PHASE_FRAC_BITWIDTH));
|
if (frame.h)
|
do_div(tmp, frame.h);
|
else
|
tmp = 0;
|
para->vstep = (unsigned int)(tmp >> GSU_FB_FRAC_BITWIDTH);
|
|
para->hphase
|
= ((crop.x & 0xffffffff) >> (32 - GSU_PHASE_FRAC_BITWIDTH));
|
para->vphase
|
= ((crop.y & 0xffffffff) >> (32 - GSU_PHASE_FRAC_BITWIDTH));
|
|
crop_fix->w
|
= (unsigned int)(
|
((crop.w & 0xffffffff) + (crop.x & 0xffffffff)) >=
|
N2_POWER(1, GSU_FB_FRAC_BITWIDTH) ?
|
((crop.w >> GSU_FB_FRAC_BITWIDTH) + 1)
|
: (crop.w >> GSU_FB_FRAC_BITWIDTH));
|
|
crop_fix->h
|
= (unsigned int)(
|
((crop.h & 0xffffffff) + (crop.y & 0xffffffff)) >=
|
N2_POWER(1, GSU_FB_FRAC_BITWIDTH) ?
|
((crop.h >> GSU_FB_FRAC_BITWIDTH) + 1)
|
: (crop.h >> GSU_FB_FRAC_BITWIDTH));
|
|
crop_fix->x = (int)(crop.x >> GSU_FB_FRAC_BITWIDTH);
|
crop_fix->y = (int)(crop.y >> GSU_FB_FRAC_BITWIDTH);
|
|
return 0;
|
}
|
|
/**
|
* function : de_calc_ovl_coord(unsigned int frame_coord,
|
* unsigned int scale_step,
|
* int gsu_sel)
|
* description : calculate overlay coordinate
|
* parameters :
|
* frame_coord <frame buffer coordinate>
|
* scale_step <vsu/gsu horizontal/vertical scale step>
|
* gsu_sel <is gsu or not: 0-is vsu, others-is gsu>
|
* return :
|
* layer_coord <layer coordinate>
|
*/
|
int de_calc_ovl_coord(unsigned int frame_coord, unsigned int scale_step,
|
int gsu_sel)
|
{
|
int shift, half, layer_coord;
|
|
shift = (gsu_sel == 0) ?
|
VSU_PHASE_FRAC_BITWIDTH : GSU_PHASE_FRAC_BITWIDTH;
|
half = (1 << (shift - 1));
|
layer_coord = (frame_coord * scale_step + half) >> shift;
|
__inf("half_shift_xy=<%x,%d,%d>\n", half, shift, layer_coord);
|
|
return layer_coord;
|
}
|
|
/**
|
* function : de_gsu_sel_ovl_scaler_para(unsigned char *en,
|
* struct scaler_para *layer_scale_para[],
|
* struct scaler_para *ovl_scale_para)
|
* description : calculate ui overlay scaler parameters
|
* parameters :
|
* en <pointer of layer enable>
|
* layer_scale_para <pointer array of ui layer scaler parameter>
|
* ovl_scale_para <pointer of ui overlay scaler parameter>
|
* return :
|
* success
|
*/
|
int de_gsu_sel_ovl_scaler_para(unsigned char *en,
|
struct scaler_para *layer_scale_para,
|
struct scaler_para *ovl_scale_para)
|
{
|
int i, j, layer_en_num;
|
int used_layer_idx[LAYER_MAX_NUM_PER_CHN];
|
|
/* get vaild layer number and record layer index */
|
layer_en_num = 0;
|
j = 0;
|
for (i = 0; i < LAYER_MAX_NUM_PER_CHN; i++) {
|
if (*(en + i) == 1) {
|
layer_en_num++;
|
used_layer_idx[j++] = i;
|
}
|
}
|
|
/* only one layer enabled in one overlay */
|
if (layer_en_num == 1) {
|
/* set overlay scale para through this layer */
|
ovl_scale_para->hphase
|
= layer_scale_para[used_layer_idx[0]].hphase;
|
ovl_scale_para->vphase
|
= layer_scale_para[used_layer_idx[0]].vphase;
|
ovl_scale_para->hstep
|
= layer_scale_para[used_layer_idx[0]].hstep;
|
ovl_scale_para->vstep
|
= layer_scale_para[used_layer_idx[0]].vstep;
|
} else if (layer_en_num > 1) {
|
/* two or more layers enabled in one overlay */
|
/* set overlay scale step through first enabled layer */
|
ovl_scale_para->hstep
|
= layer_scale_para[used_layer_idx[0]].hstep;
|
ovl_scale_para->vstep
|
= layer_scale_para[used_layer_idx[0]].vstep;
|
|
/* set overlay phase through 1st enabled non-zero-phase layer */
|
for (i = 0; i < layer_en_num; i++) {
|
if (layer_scale_para[used_layer_idx[i]].hphase != 0) {
|
ovl_scale_para->hphase
|
= layer_scale_para[used_layer_idx[i]].hphase;
|
break;
|
}
|
}
|
|
/* all layer phase equal to zero */
|
if (i == layer_en_num) {
|
ovl_scale_para->hphase
|
= layer_scale_para[used_layer_idx[0]].hphase;
|
}
|
|
/* set overlay phase through 1st enabled non-zero-phase layer */
|
for (i = 0; i < layer_en_num; i++) {
|
if (layer_scale_para[used_layer_idx[i]].vphase != 0) {
|
ovl_scale_para->vphase
|
= layer_scale_para[used_layer_idx[i]].vphase;
|
break;
|
}
|
}
|
|
/* all layer phase equal to zero */
|
if (i == layer_en_num) {
|
ovl_scale_para->vphase
|
= layer_scale_para[used_layer_idx[0]].vphase;
|
}
|
|
} else {
|
ovl_scale_para->hphase = 0;
|
ovl_scale_para->vphase = 0;
|
ovl_scale_para->hstep
|
= (unsigned int)N2_POWER(1, GSU_PHASE_FRAC_BITWIDTH);
|
ovl_scale_para->vstep
|
= (unsigned int)N2_POWER(1, GSU_PHASE_FRAC_BITWIDTH);
|
}
|
|
return 0;
|
}
|