/* * 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. * */ #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 (irq_flag == 0x1) { 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<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_BGR_888) ycnt = 3; else if (fmt <= TR_FORMAT_BGRA_5551) ycnt = 2; 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_I_VYUY) { ycnt = 2; ucnt = 0; } else if (fmt == TR_FORMAT_YUV422_P) { ycnt = 1; ucnt = 1; x1 = x0/2; y1 = y0; } else if (fmt == TR_FORMAT_YUV420_P) { ycnt = 1; ucnt = 1; x1 = x0/2; y1 = y0/2; } else if (fmt == TR_FORMAT_YUV411_P) { ycnt = 1; ucnt = 1; x1 = x0/4; y1 = y0; } else if (fmt == TR_FORMAT_YUV411_P) { ycnt = 1; ucnt = 1; x1 = x0/4; y1 = y0; } 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_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 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; addr[0] = info->src_frame.laddr[0] + pitch[0] * y0 + x0 * ycnt; if (fmt >= TR_FORMAT_YUV444_P) { pitch[1] = info->src_frame.pitch[1] * ucnt; addr[1] = info->src_frame.laddr[1] + pitch[1] * y1 + x1 * ucnt; } if ((fmt == TR_FORMAT_YUV444_P) || (fmt == TR_FORMAT_YUV422_P) || (fmt == TR_FORMAT_YUV420_P) || (fmt == TR_FORMAT_YUV411_P)) { pitch[2] = info->src_frame.pitch[2] * ucnt; addr[2] = info->src_frame.laddr[2] + pitch[2] * y1 + x1 * ucnt; } if ((x0 != 0) || (y0 != 0)) { 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; } 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 */ fmt = info->dst_frame.fmt; 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; addr[0] = info->dst_frame.laddr[0] + pitch[0] * y0 + x0 * ycnt; if (fmt >= TR_FORMAT_YUV444_P) { pitch[1] = info->dst_frame.pitch[1] * ucnt; addr[1] = info->dst_frame.laddr[1] + pitch[1] * y1 + x1 * ucnt; } if ((fmt == TR_FORMAT_YUV444_P) || (fmt == TR_FORMAT_YUV422_P) || (fmt == TR_FORMAT_YUV420_P) || (fmt == TR_FORMAT_YUV411_P)) { pitch[2] = info->dst_frame.pitch[2] * ucnt; addr[2] = info->dst_frame.laddr[2]+pitch[2]*y1+x1*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 ((x0 != 0) || (y0 != 0)) { pr_warn("Out buffer coordinate is not original point[%d,%d].\n", x0, y0); return -1; } 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 (info->src_frame.fmt == TR_FORMAT_YUV422_I_VYUY) fmt = 0x20; else if (info->src_frame.fmt == TR_FORMAT_YUV422_I_YVYU) fmt = 0x21; else if (info->src_frame.fmt == TR_FORMAT_YUV422_I_YVYU) fmt = 0x21; else if (info->src_frame.fmt == TR_FORMAT_YUV422_I_UYVY) fmt = 0x22; else if (info->src_frame.fmt == TR_FORMAT_YUV422_I_UYVY) fmt = 0x22; else if (info->src_frame.fmt == TR_FORMAT_YUV422_I_YUYV) fmt = 0x23; else if (info->src_frame.fmt == TR_FORMAT_YUV422_I_YUYV) fmt = 0x23; else if (info->src_frame.fmt == TR_FORMAT_YUV422_SP_UVUV) fmt = 0x24; else if (info->src_frame.fmt == TR_FORMAT_YUV422_SP_UVUV) fmt = 0x24; else if (info->src_frame.fmt == TR_FORMAT_YUV422_SP_VUVU) fmt = 0x25; else if (info->src_frame.fmt == TR_FORMAT_YUV422_SP_VUVU) fmt = 0x25; else if (info->src_frame.fmt == TR_FORMAT_YUV422_P) fmt = 0x26; else if (info->src_frame.fmt == TR_FORMAT_YUV422_P) fmt = 0x26; else if (info->src_frame.fmt == TR_FORMAT_YUV420_SP_UVUV) fmt = 0x28; else if (info->src_frame.fmt == TR_FORMAT_YUV420_SP_UVUV) fmt = 0x28; else if (info->src_frame.fmt == TR_FORMAT_YUV420_SP_VUVU) fmt = 0x29; else if (info->src_frame.fmt == TR_FORMAT_YUV420_SP_VUVU) fmt = 0x29; else if (info->src_frame.fmt == TR_FORMAT_YUV420_P) fmt = 0x2a; else if (info->src_frame.fmt == TR_FORMAT_YUV420_P) fmt = 0x2a; else if (info->src_frame.fmt == TR_FORMAT_YUV411_SP_UVUV) fmt = 0x2c; else if (info->src_frame.fmt == TR_FORMAT_YUV411_SP_UVUV) fmt = 0x2c; else if (info->src_frame.fmt == TR_FORMAT_YUV411_SP_VUVU) fmt = 0x2d; else if (info->src_frame.fmt == TR_FORMAT_YUV411_SP_VUVU) fmt = 0x2d; else if (info->src_frame.fmt == TR_FORMAT_YUV411_P) fmt = 0x2e; else if (info->src_frame.fmt == TR_FORMAT_YUV411_P) 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; }