oleavr-rgl-a500-mini-linux-.../drivers/char/sunxi_tr/sun50iw1_transform.c
Ole André Vadla Ravnås 169c65d57e Initial commit
2022-05-07 01:01:45 +02:00

405 lines
10 KiB
C
Executable file

/*
* linux-3.10/drivers/char/sunxi_tr/sun50iw1_transform.c
*
* Copyright (c) 2007-2017 Allwinnertech Co., Ltd.
*
* 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.
*
*/
//*********************************************************************************************************************
// All Winner Tech, All Right Reserved. 2014-2015 Copyright (c)
//
// File name : de_tr.c
//
// Description : display engine 2.0 transform processing base functions implement
//
// History : 2014/04/08 iptang v0.1 Initial version
//
//*********************************************************************************************************************
#include "transform.h"
#define TR_OFFSET 0x00020000
#define TR_CTL (0x000)
#define TR_IRQ (0x004)
#define TR_IN_FMT (0x020)
#define TR_IN_SIZE (0x024)
#define TR_IN_PITCH0 (0x030)
#define TR_IN_PITCH1 (0x034)
#define TR_IN_PITCH2 (0x038)
#define TR_IN_LADDR0 (0x040)
#define TR_IN_LADDR1 (0x048)
#define TR_IN_LADDR2 (0x050)
#define TR_IN_HADDR0 (0x044)
#define TR_IN_HADDR1 (0x04c)
#define TR_IN_HADDR2 (0x054)
#define TR_OUT_FMT (0x080)
#define TR_OUT_SIZE (0x084)
#define TR_OUT_PITCH0 (0x090)
#define TR_OUT_PITCH1 (0x094)
#define TR_OUT_PITCH2 (0x098)
#define TR_OUT_LADDR0 (0x0a0)
#define TR_OUT_LADDR1 (0x0a8)
#define TR_OUT_LADDR2 (0x0b0)
#define TR_OUT_HADDR0 (0x0a4)
#define TR_OUT_HADDR1 (0x0ac)
#define TR_OUT_HADDR2 (0x0b4)
static uintptr_t tr_base;
#define tr_writel(val, addr) writel(val, (void __iomem *)(addr))
#define tr_readl(addr) readl((void __iomem *)(addr))
int de_tr_set_base(uintptr_t reg_base)
{
tr_base = reg_base + TR_OFFSET;
return 0;
}
int de_tr_irq_enable(void)
{
tr_writel(1<<16, tr_base + TR_IRQ);
return 0;
}
int de_tr_irq_disable(void)
{
tr_writel(0, tr_base + TR_IRQ);
return 0;
}
/* */
int de_tr_irq_query(void)
{
unsigned int irq_flag;
unsigned reg_val = 0;
reg_val = tr_readl(tr_base + TR_IRQ);
irq_flag = reg_val&0x1;
if(0x1 == irq_flag) {
tr_writel(reg_val, tr_base + TR_IRQ);
return 0;
}
return -1;
}
static int de_tr_clk_enable(void)
{
uintptr_t base = tr_base - TR_OFFSET;
unsigned int reg_val = 0;
unsigned int offset = 3;//bit 3
/* clk div */
reg_val = tr_readl(base + 0xc);
reg_val &= ~(0xf << 12);
reg_val |= (0x0 << 12);
tr_writel(reg_val, base + 0xc);
/* reset */
reg_val = tr_readl(base + 0x8);
reg_val |= (1<<offset);
tr_writel(reg_val, base + 0x8);
/* bus */
reg_val = tr_readl(base + 0x4);
reg_val |= (1<<offset);
tr_writel(reg_val, base + 0x4);
/* module */
reg_val = tr_readl(base + 0x0);
reg_val |= (1<<offset);
tr_writel(reg_val, base + 0x0);
return 0;
}
static int de_tr_clk_disable(void)
{
uintptr_t base = tr_base - TR_OFFSET;
unsigned int reg_val = 0;
unsigned int offset = 3;//bit 3
/* module */
reg_val = tr_readl(base + 0x0);
reg_val &= ~(1<<offset);
tr_writel(reg_val, base + 0x0);
/* bus */
reg_val = tr_readl(base + 0x4);
reg_val &= ~(1<<offset);
tr_writel(reg_val, base + 0x4);
/* reset */
reg_val = tr_readl(base + 0x8);
reg_val &= ~(1<<offset);
tr_writel(reg_val, base + 0x8);
return 0;
}
static int de_tr_set_enable(void)
{
unsigned int tmp;
tmp = tr_readl(tr_base + TR_CTL);
tr_writel((1<<31)|tmp,tr_base + TR_CTL);
return 0;
}
static int de_tr_set_disable(void)
{
//when rst need read de top register
tr_readl(tr_base - TR_OFFSET);
de_tr_irq_disable();
return 0;
}
int de_tr_init(void)
{
return de_tr_clk_enable();
}
int de_tr_exit(void)
{
de_tr_set_disable();
de_tr_clk_disable();
return 0;
}
int de_tr_reset(void)
{
uintptr_t base = tr_base - TR_OFFSET;
unsigned int reg_val = 0;
unsigned int offset = 3;//bit 3
tr_readl(tr_base - TR_OFFSET);
reg_val = tr_readl(tr_base + TR_CTL);
reg_val |= 0x1;//enable bit
tr_writel(reg_val,tr_base + TR_CTL);
/* assert */
reg_val = tr_readl(base + 0x8);
reg_val &= ~(1<<offset);
tr_writel(reg_val, base + 0x8);
udelay(10);//wait for reset finish
/* de-assert */
reg_val = tr_readl(base + 0x8);
reg_val |= (1<<offset);
tr_writel(reg_val, base + 0x8);
return 0;
}
int de_tr_exception(void)
{
mdelay(100);//wait to finish
return 0;
}
int de_tr_set_cfg(tr_info *info)
{
int x0,x1,y0,y1;
unsigned char haddr[3],degree,hflip_en,vflip_en,burst;
unsigned int w,h,fmt,ycnt = 4,ucnt = 0,tmp,pitch[3];
long long addr[3];
de_tr_reset();
//global
burst = 0x7;
degree = hflip_en = vflip_en = 0x0;
if (info->mode<=TR_ROT_270)
{
degree = info->mode;
}
else if ((info->mode == TR_HFLIP) || (info->mode == TR_HFLIP_ROT_90))
{
hflip_en = 0x1;
}
else if ((info->mode == TR_VFLIP) || (info->mode == TR_VFLIP_ROT_90))
{
vflip_en = 0x1;
}
if ((info->mode == TR_HFLIP_ROT_90) || (info->mode == TR_VFLIP_ROT_90))
{
degree = 0x1;
}
if((info->mode == TR_ROT_0) || (info->mode == TR_ROT_180) || (info->mode == TR_HFLIP) || (info->mode == TR_VFLIP))
{
burst = 0x3f;
}
tmp = (burst<<16)|(hflip_en<<7)|(vflip_en<<6)|(degree<<4)|(1<<0);
tr_writel(tmp,tr_base + TR_CTL);
x0 = x1 = info->src_rect.x;
y0 = y1 = info->src_rect.y;
w = info->src_rect.w;
h = info->src_rect.h;
fmt = info->src_frame.fmt;
if (fmt<=TR_FORMAT_BGRX_8888) {ycnt = 4;}
else if (fmt<=TR_FORMAT_BGR_888) {ycnt = 3;}
else if (fmt<=TR_FORMAT_BGRA_5551) {ycnt = 2;}
else if (fmt<=TR_FORMAT_YUV422_I_VYUY) {ycnt = 2;ucnt=0;}
else if (fmt==TR_FORMAT_YUV422_P) {ycnt = 1;ucnt=1; x1=x0/2;y1=y0;} //YUV422
else if (fmt==TR_FORMAT_YUV420_P) {ycnt = 1;ucnt=1; x1=x0/2;y1=y0/2;}//YUV420
else if (fmt==TR_FORMAT_YUV411_P) {ycnt = 1;ucnt=1; x1=x0/4;y1=y0;} //YUV411
else if (fmt<=TR_FORMAT_YUV422_SP_VUVU){ycnt = 1;ucnt=2; x1=x0/2;y1=y0;}
else if (fmt<=TR_FORMAT_YUV420_SP_VUVU){ycnt = 1;ucnt=2; x1=x0/2;y1=y0/2;}
else if (fmt<=TR_FORMAT_YUV411_SP_VUVU){ycnt = 1;ucnt=2; x1=x0/4;y1=y0;}
else {ycnt = 4;}
pitch[0] = info->src_frame.pitch[0] * ycnt;
pitch[1] = info->src_frame.pitch[1] * ucnt;
pitch[2] = info->src_frame.pitch[2] * ucnt;
if((0 != x0) ||(0 != y0)){
pr_warn("In buffer coordinate is not original point[%d,%d].\n", x0, y0);
return -1;
}
if((pitch[0]&0xf) ||(pitch[1]&0xf)||(pitch[2]&0xf)){
pr_warn("In buffer pitch is not 16 byte align[%x,%x,%x].\n",
pitch[0],pitch[1],pitch[2]);
return -1;
}
addr[0] = info->src_frame.laddr[0]+pitch[0]*y0+x0*ycnt;//Y/ARGB
addr[1] = info->src_frame.laddr[1]+pitch[1]*y1+x1*ucnt;//UV/U
addr[2] = info->src_frame.laddr[2]+pitch[2]*y1+x1*ucnt;//V
haddr[0] = ((addr[0]>>32)&0xff) + info->src_frame.haddr[0];
haddr[1] = ((addr[1]>>32)&0xff) + info->src_frame.haddr[1];
haddr[2] = ((addr[2]>>32)&0xff) + info->src_frame.haddr[2];
if(fmt >= TR_FORMAT_YUV444_I_AYUV) {
if((addr[0]&0xf) ||(addr[1]&0xf)||(addr[2]&0xf)){
pr_warn("Input address is not 16 byte align.\n");
return -1;
}
}
w = w==0?0:w-1;
h = h==0?0:h-1;
tr_writel((h<<16)|w,tr_base + TR_IN_SIZE);
tr_writel(pitch[0],tr_base + TR_IN_PITCH0);
tr_writel(pitch[1],tr_base + TR_IN_PITCH1);
tr_writel(pitch[2],tr_base + TR_IN_PITCH2);
tr_writel(addr[0]&0xffffffff,tr_base + TR_IN_LADDR0);
tr_writel(addr[1]&0xffffffff,tr_base + TR_IN_LADDR1);
tr_writel(addr[2]&0xffffffff,tr_base + TR_IN_LADDR2);
tr_writel(haddr[0],tr_base + TR_IN_HADDR0);
tr_writel(haddr[1],tr_base + TR_IN_HADDR1);
tr_writel(haddr[2],tr_base + TR_IN_HADDR2);
//dst
x0 = info->dst_rect.x;
y0 = info->dst_rect.y;
w = info->dst_rect.w;
h = info->dst_rect.h;
//for ycbcr format output only support yv12
if(fmt >= TR_FORMAT_YUV444_I_AYUV) {
ycnt = 1;ucnt=1; x1=x0/2;y1=y0/2;
}
pitch[0] = info->dst_frame.pitch[0] * ycnt;
pitch[1] = info->dst_frame.pitch[1] * ucnt;
pitch[2] = info->dst_frame.pitch[2] * ucnt;
if(fmt >= TR_FORMAT_YUV444_I_AYUV) {
if((pitch[0]&0xf) ||(pitch[1]&0xf)||(pitch[2]&0xf)){
pr_warn("Out buffer pitch is not 16 byte align[%x,%x,%x].\n",
pitch[0],pitch[1],pitch[2]);
return -1;
}
}
if((0 != x0) ||(0 != y0)){
pr_warn("Out buffer coordinate is not original point[%d,%d].\n", x0, y0);
return -1;
}
addr[0] = info->dst_frame.laddr[0]+pitch[0]*y0+x0*ycnt;//Y/ARGB
addr[1] = info->dst_frame.laddr[1]+pitch[1]*y1+x1*ucnt;//UV/U
addr[2] = info->dst_frame.laddr[2]+pitch[2]*y1+x1*ucnt;//V
haddr[0] = ((addr[0]>>32)&0xff) + info->dst_frame.haddr[0];
haddr[1] = ((addr[1]>>32)&0xff) + info->dst_frame.haddr[1];
haddr[2] = ((addr[2]>>32)&0xff) + info->dst_frame.haddr[2];
if(fmt >= TR_FORMAT_YUV444_I_AYUV) {
if((addr[0]&0x1f) ||(addr[1]&0x1f)||(addr[2]&0x1f)){
pr_warn("Output address is not 32 byte align.\n");
return -1;
}
}
w = w==0?0:w-1;
h = h==0?0:h-1;
tr_writel((h<<16)|w,tr_base + TR_OUT_SIZE);
tr_writel(pitch[0],tr_base + TR_OUT_PITCH0);
tr_writel(pitch[1],tr_base + TR_OUT_PITCH1);
tr_writel(pitch[2],tr_base + TR_OUT_PITCH2);
tr_writel(addr[0]&0xffffffff,tr_base + TR_OUT_LADDR0);
tr_writel(addr[1]&0xffffffff,tr_base + TR_OUT_LADDR1);
tr_writel(addr[2]&0xffffffff,tr_base + TR_OUT_LADDR2);
tr_writel(haddr[0],tr_base + TR_OUT_HADDR0);
tr_writel(haddr[1],tr_base + TR_OUT_HADDR1);
tr_writel(haddr[2],tr_base + TR_OUT_HADDR2);
//src
if (TR_FORMAT_YUV422_I_VYUY == info->src_frame.fmt){fmt = 0x20;}
else if (TR_FORMAT_YUV422_I_YVYU == info->src_frame.fmt){fmt = 0x21;}
else if (TR_FORMAT_YUV422_I_UYVY == info->src_frame.fmt){fmt = 0x22;}
else if (TR_FORMAT_YUV422_I_YUYV == info->src_frame.fmt){fmt = 0x23;}
else if (TR_FORMAT_YUV422_SP_UVUV == info->src_frame.fmt){fmt = 0x24;}
else if (TR_FORMAT_YUV422_SP_VUVU == info->src_frame.fmt){fmt = 0x25;}
else if (TR_FORMAT_YUV422_P == info->src_frame.fmt){fmt = 0x26;}
else if (TR_FORMAT_YUV420_SP_UVUV == info->src_frame.fmt){fmt = 0x28;}
else if (TR_FORMAT_YUV420_SP_VUVU == info->src_frame.fmt){fmt = 0x29;}
else if (TR_FORMAT_YUV420_P == info->src_frame.fmt){fmt = 0x2a;}
else if (TR_FORMAT_YUV411_SP_UVUV == info->src_frame.fmt){fmt = 0x2c;}
else if (TR_FORMAT_YUV411_SP_VUVU == info->src_frame.fmt){fmt = 0x2d;}
else if (TR_FORMAT_YUV411_P == info->src_frame.fmt){fmt = 0x2e;}
else {fmt = info->src_frame.fmt;}
// else {fmt = 0x0;}
tr_writel(fmt,tr_base + TR_IN_FMT);
de_tr_irq_enable();
de_tr_set_enable();
return 0;
}