1852 lines
63 KiB
C
1852 lines
63 KiB
C
/**
|
|
* @file sdrv_g2dlite_drv.c
|
|
* @brief SemiDrive G2DLite driver file.
|
|
*
|
|
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include <armv7-r/cache.h>
|
|
#include <g2dlite/g2dlite.h>
|
|
#include <g2dlite/g2dlite_core.h>
|
|
#include <g2dlite/g2dlite_log.h>
|
|
#include <g2dlite/g2dlite_reg.h>
|
|
#include <stdlib.h>
|
|
#include <udelay/udelay.h>
|
|
#if CONFIG_OS_FREERTOS
|
|
#include <FreeRTOS.h>
|
|
#include <semphr.h>
|
|
extern SemaphoreHandle_t done_sema;
|
|
#endif
|
|
|
|
#define G2DLITE_CLUT_SADDR 0x5400
|
|
#define G2DLITE_CLUT_EADDR 0x57FF
|
|
|
|
#define G2DLITE_PD_IDX 3
|
|
|
|
static const u8 r_wml_cfgs[8][5] = {
|
|
/*fastcopy*/
|
|
{0x00, 0x00, 0x00, 0x00, 0x40},
|
|
/*GPipe Only(1palne)*/
|
|
{0x30, 0x00, 0x00, 0x00, 0x10},
|
|
/*GPipe Only(2palnes)*/
|
|
{0x18, 0x18, 0x00, 0x00, 0x10},
|
|
/*GPipe Only(3palnes)*/
|
|
{0x18, 0x10, 0x10, 0x00, 0x08},
|
|
/*SPipe Only(1palne)*/
|
|
{0x00, 0x00, 0x00, 0x30, 0x10},
|
|
/*GPipe(1palne) + Spipe*/
|
|
{0x18, 0x00, 0x00, 0x18, 0x10},
|
|
/*GPipe(2palnes) + Spipe*/
|
|
{0x10, 0x10, 0x00, 0x10, 0x10},
|
|
/*GPipe(3palnes) + Spipe*/
|
|
{0x10, 0x08, 0x08, 0x10, 0x10}};
|
|
|
|
static const u8 r_d_depth_cfgs[8][5] = {
|
|
/*fastcopy*/
|
|
{0x00, 0x00, 0x00, 0x00, 0x08},
|
|
/*GPipe Only(1palne)*/
|
|
{0x06, 0x00, 0x00, 0x00, 0x02},
|
|
/*GPipe Only(2palnes)*/
|
|
{0x03, 0x03, 0x00, 0x00, 0x02},
|
|
/*GPipe Only(3palnes)*/
|
|
{0x03, 0x02, 0x02, 0x00, 0x01},
|
|
/*SPipe Only(1palne)*/
|
|
{0x00, 0x00, 0x00, 0x06, 0x02},
|
|
/*GPipe(1palne) + Spipe*/
|
|
{0x03, 0x00, 0x00, 0x03, 0x02},
|
|
/*GPipe(2palnes) + Spipe*/
|
|
{0x02, 0x02, 0x00, 0x03, 0x01},
|
|
/*GPipe(3palnes) + Spipe*/
|
|
{0x02, 0x01, 0x01, 0x03, 0x01}};
|
|
|
|
static const u8 r_c_depth_cfgs[8][5] = {
|
|
/*fastcopy*/
|
|
{0x00, 0x00, 0x00, 0x00, 0x08},
|
|
/*GPipe Only(1palne)*/
|
|
{0x06, 0x00, 0x00, 0x00, 0x02},
|
|
/*GPipe Only(2palnes)*/
|
|
{0x03, 0x03, 0x00, 0x00, 0x02},
|
|
/*GPipe Only(3palnes)*/
|
|
{0x03, 0x02, 0x02, 0x00, 0x01},
|
|
/*SPipe Only(1palne)*/
|
|
{0x00, 0x00, 0x00, 0x06, 0x02},
|
|
/*GPipe(1palne) + Spipe*/
|
|
{0x03, 0x00, 0x00, 0x03, 0x02},
|
|
/*GPipe(2palnes) + Spipe*/
|
|
{0x02, 0x02, 0x00, 0x03, 0x01},
|
|
/*GPipe(3palnes) + Spipe*/
|
|
{0x02, 0x01, 0x01, 0x03, 0x01}};
|
|
|
|
static const u8 w_wml_cfgs[3][3] = {
|
|
/*fastcopy && Wipe(1plane)*/
|
|
{0x40, 0x00, 0x00},
|
|
/*Wipe(2planes)*/
|
|
{0x20, 0x20, 0x00},
|
|
/*Wipe(3planes)*/
|
|
{0x20, 0x10, 0x10}};
|
|
|
|
static const u8 w_d_depth_cfgs[3][3] = {
|
|
/*fastcopy && Wipe(1plane)*/
|
|
{0x08, 0x00, 0x00},
|
|
/*Wipe(2planes)*/
|
|
{0x04, 0x04, 0x00},
|
|
/*Wipe(3planes)*/
|
|
{0x04, 0x02, 0x02}};
|
|
|
|
static const u8 w_c_depth_cfgs[3][3] = {
|
|
/*fastcopy && Wipe(1plane)*/
|
|
{0x08, 0x00, 0x00},
|
|
/*Wipe(2planes)*/
|
|
{0x04, 0x04, 0x00},
|
|
/*Wipe(3planes)*/
|
|
{0x04, 0x02, 0x02}};
|
|
|
|
static const uint32_t csc_param[5][15] = {
|
|
{/*YCbCr to RGB*/
|
|
0x094F, 0x0000, 0x0CC4, 0x094F, 0x3CE0, 0x397F, 0x094F, 0x1024, 0x0000,
|
|
0x0000, 0x0000, 0x0000, 0x0040, 0x0200, 0x0200},
|
|
{/*bt709 YCbCr to RGB(16-235)*/
|
|
0x0800, 0x0000, 0x0C99, 0x0800, 0x3E81, 0x3C42, 0x0800, 0x0ED8, 0x0000,
|
|
0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0200},
|
|
{/*YUV to RGB*/
|
|
0x0800, 0x0000, 0x091E, 0x0800, 0x3CD8, 0x3B5B, 0x0800, 0x1041, 0x0000,
|
|
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
|
|
{/*RGB to YCbCr*/
|
|
0x0264, 0x04B2, 0x00E9, 0x3EA0, 0x3D4A, 0x0416, 0x0416, 0x3C94, 0x3F57,
|
|
0x0000, 0x0200, 0x0200, 0x0000, 0x0000, 0x0000},
|
|
{/*RGB to YUV*/
|
|
0x0000}};
|
|
|
|
static uint32_t G2DLITE_HSCALER[3][2] = {
|
|
{0x2600, 0x29ff}, /**< {HS_0_SADDR, HS_0_EADDR}*/
|
|
{0x3600, 0x39ff}, /**< {HS_1_SADDR, HS_1_EADDR}*/
|
|
{0x4600, 0x49ff} /**< {HS_2_SADDR, HS_2_EADDR}*/
|
|
};
|
|
|
|
static uint32_t G2DLITE_VSCALER[3][2] = {
|
|
{0x2a00, 0x2dff}, /**< {VS_0_SADDR, VS_0_EADDR}*/
|
|
{0x3a00, 0x3dff}, /**< {VS_1_SADDR, VS_1_EADDR}*/
|
|
{0x4a00, 0x4dff} /**< {VS_2_SADDR, VS_2_EADDR}*/
|
|
};
|
|
|
|
static unsigned int get_l_addr(unsigned long addr)
|
|
{
|
|
unsigned int addr_l;
|
|
|
|
addr_l = (unsigned int)(addr & 0x00000000FFFFFFFF);
|
|
return addr_l;
|
|
}
|
|
|
|
static unsigned int get_h_addr(unsigned long addr)
|
|
{
|
|
unsigned int addr_h;
|
|
|
|
addr_h = (unsigned int)(addr & 0xFFFFFFFF00000000);
|
|
return addr_h;
|
|
}
|
|
|
|
static void get_bpp_by_format(unsigned int format, unsigned char *bpp)
|
|
{
|
|
switch (format) {
|
|
case COLOR_MONOTONIC_8BIT:
|
|
bpp[0] = 8;
|
|
bpp[1] = bpp[2] = 0;
|
|
break;
|
|
case COLOR_RGB565:
|
|
case COLOR_BGR565:
|
|
case COLOR_ARGB4444:
|
|
case COLOR_BGRA4444:
|
|
case COLOR_ARGB1555:
|
|
case COLOR_BGRA5551:
|
|
case COLOR_ABGR1555:
|
|
case COLOR_YUYV:
|
|
bpp[0] = 16;
|
|
bpp[1] = bpp[2] = 0;
|
|
break;
|
|
case COLOR_RGB666:
|
|
case COLOR_BGR666:
|
|
bpp[0] = 18;
|
|
bpp[1] = bpp[2] = 0;
|
|
break;
|
|
case COLOR_RGB888:
|
|
case COLOR_BGR888:
|
|
bpp[0] = 24;
|
|
bpp[1] = bpp[2] = 0;
|
|
break;
|
|
case COLOR_ARGB8888:
|
|
case COLOR_BGRA8888:
|
|
case COLOR_ABGR8888:
|
|
case COLOR_ARGB2101010:
|
|
case COLOR_BGRA1010102:
|
|
bpp[0] = 32;
|
|
bpp[1] = bpp[2] = 0;
|
|
break;
|
|
case COLOR_NV21:
|
|
case COLOR_NV12:
|
|
case COLOR_NV61:
|
|
case COLOR_NV16:
|
|
bpp[0] = 8;
|
|
bpp[1] = 8;
|
|
bpp[2] = 0;
|
|
break;
|
|
case COLOR_YUV420P:
|
|
case COLOR_YUV422P:
|
|
case COLOR_YUV444P:
|
|
bpp[0] = 8;
|
|
bpp[1] = 8;
|
|
bpp[2] = 8;
|
|
break;
|
|
default:
|
|
bpp[0] = bpp[1] = bpp[2] = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void g2dlite_com_regs_init(struct g2dlite_device *dev)
|
|
{
|
|
unsigned long base = dev->reg_base;
|
|
|
|
/* G2DLITE_INT_MASK */
|
|
/*g2dlite mask:1-disable irq, 0-enable irq */
|
|
/*bit[6]: G2DLITE_FRM_DONE */
|
|
/*bit[5]: G2DLITE_TASK_DONE */
|
|
/*bit[4]: WDMA */
|
|
/*bit[3]: RLE_1 */
|
|
/*bit[2]: MLC */
|
|
/*bit[1]: RLE_0 */
|
|
/*bit[0]: RDMA */
|
|
g2dlite_write(base, G2D_RA020,
|
|
0x3F); /*set G2DLITE_FRM_DONE enable*/
|
|
}
|
|
|
|
static void g2dlite_rdma_init(struct g2dlite_device *dev)
|
|
{
|
|
int i = 0;
|
|
const unsigned short wml_cfg[] = {0x08, 0x08, 0x08, 0x08, 0x08};
|
|
const unsigned short d_depth_cfg[] = {0x01, 0x01, 0x01, 0x01, 0x01};
|
|
const unsigned short c_depth_cfg[] = {0x01, 0x01, 0x01, 0x01, 0x01};
|
|
const unsigned char sche_cfg[] = {0x04, 0x04, 0x04, 0x04, 0x04};
|
|
const unsigned char p1_cfg[] = {0x30, 0x30, 0x30, 0x30, 0x30};
|
|
const unsigned char p0_cfg[] = {0x10, 0x10, 0x10, 0x10, 0x10};
|
|
const unsigned char burst_mode_cfg[] = {0x00, 0x00, 0x00, 0x00, 0x00};
|
|
const unsigned char burst_len_cfg[] = {0x04, 0x04, 0x04, 0x04, 0x04};
|
|
|
|
unsigned int val;
|
|
unsigned long base = dev->reg_base;
|
|
|
|
for (i = 0; i < CHN_COUNT; i++)
|
|
g2dlite_write(base, G2D_RB000(i), wml_cfg[i]);
|
|
|
|
for (i = 0; i < CHN_COUNT; i++)
|
|
g2dlite_write(base, G2D_RB004(i), d_depth_cfg[i]);
|
|
|
|
for (i = 0; i < CHN_COUNT; i++)
|
|
g2dlite_write(base, G2D_RB008(i), c_depth_cfg[i]);
|
|
|
|
for (i = 0; i < CHN_COUNT; i++) {
|
|
val = reg_value(sche_cfg[i], 0, G2D_SHIFT16_RB00C,
|
|
G2D_MASK16_RB00C);
|
|
val = reg_value(p1_cfg[i], val, G2D_SHIFT08_RB00C,
|
|
G2D_MASK08_RB00C);
|
|
val = reg_value(p0_cfg[i], val, G2D_SHIFT00_RB00C,
|
|
G2D_MASK00_RB00C);
|
|
g2dlite_write(base, G2D_RB00C(i), val);
|
|
}
|
|
|
|
for (i = 0; i < CHN_COUNT; i++) {
|
|
val = reg_value(burst_mode_cfg[i], 0, G2D_SHIFT03_RB010,
|
|
G2D_MASK03_RB010);
|
|
val = reg_value(burst_len_cfg[i], val, G2D_SHIFT00_RB010,
|
|
G2D_MASK00_RB010);
|
|
g2dlite_write(base, G2D_RB010(i), val);
|
|
}
|
|
|
|
g2dlite_write(base, G2D_RB520, 0);
|
|
|
|
val = reg_value(1, 0, G2D_SHIFT01_RB400, G2D_MASK01_RB400);
|
|
val = reg_value(1, val, G2D_SHIFT00_RB400, G2D_MASK00_RB400);
|
|
g2dlite_write(base, G2D_RB400, val);
|
|
}
|
|
|
|
static void g2dlite_gpipe_init(struct g2dlite_device *dev)
|
|
{
|
|
const unsigned char hs_nor_para = 0x09;
|
|
const unsigned char hs_ratio_int = 0x01;
|
|
const unsigned char hs_ratio_fra = 0x00;
|
|
const unsigned char vs_nor_para = 0x06;
|
|
unsigned int val;
|
|
unsigned long base = dev->reg_base;
|
|
|
|
/*YUVUP Bypass*/
|
|
val = reg_value(1, 0, G2D_SHIFT00_RC044,
|
|
G2D_MASK00_RC044);
|
|
g2dlite_write(base, G2D_RC044, val);
|
|
|
|
/*CSC Bypass*/
|
|
val = reg_value(1, 0, G2D_SHIFT00_RC200, G2D_MASK00_RC200);
|
|
g2dlite_write(base, G2D_RC200, val);
|
|
|
|
val = reg_value(csc_param[0][1], 0, G2D_SHIFT16_RC204,
|
|
G2D_MASK16_RC204);
|
|
val = reg_value(csc_param[0][0], val, G2D_SHIFT00_RC204,
|
|
G2D_MASK00_RC204);
|
|
g2dlite_write(base, G2D_RC204, val);
|
|
|
|
val = reg_value(csc_param[0][3], 0, G2D_SHIFT16_RC208,
|
|
G2D_MASK16_RC208);
|
|
val = reg_value(csc_param[0][2], val, G2D_SHIFT00_RC208,
|
|
G2D_MASK00_RC208);
|
|
g2dlite_write(base, G2D_RC208, val);
|
|
|
|
val = reg_value(csc_param[0][5], 0, G2D_SHIFT16_RC20C,
|
|
G2D_MASK16_RC20C);
|
|
val = reg_value(csc_param[0][4], val, G2D_SHIFT00_RC20C,
|
|
G2D_MASK00_RC20C);
|
|
g2dlite_write(base, G2D_RC20C, val);
|
|
|
|
val = reg_value(csc_param[0][7], 0, G2D_SHIFT16_RC210,
|
|
G2D_MASK16_RC210);
|
|
val = reg_value(csc_param[0][6], val, G2D_SHIFT00_RC210,
|
|
G2D_MASK00_RC210);
|
|
g2dlite_write(base, G2D_RC210, val);
|
|
|
|
val = reg_value(csc_param[0][9], 0, G2D_SHIFT16_RC214,
|
|
G2D_MASK16_RC214);
|
|
val = reg_value(csc_param[0][8], val, G2D_SHIFT00_RC214,
|
|
G2D_MASK00_RC214);
|
|
g2dlite_write(base, G2D_RC214, val);
|
|
|
|
val = reg_value(csc_param[0][11], 0, G2D_SHIFT16_RC218,
|
|
G2D_MASK16_RC218);
|
|
val = reg_value(csc_param[0][10], val, G2D_SHIFT00_RC218,
|
|
G2D_MASK00_RC218);
|
|
g2dlite_write(base, G2D_RC218, val);
|
|
|
|
val = reg_value(csc_param[0][13], 0, G2D_SHIFT16_RC21C,
|
|
G2D_MASK16_RC21C);
|
|
val = reg_value(csc_param[0][12], val, G2D_SHIFT00_RC21C,
|
|
G2D_MASK00_RC21C);
|
|
g2dlite_write(base, G2D_RC21C, val);
|
|
|
|
val = reg_value(csc_param[0][14], 0, G2D_SHIFT00_RC220,
|
|
G2D_MASK00_RC220);
|
|
g2dlite_write(base, G2D_RC220, val);
|
|
|
|
/*HSCALER*/
|
|
val = reg_value(hs_nor_para, 0, G2D_SHIFT08_RC300,
|
|
G2D_MASK08_RC300);
|
|
g2dlite_write(base, G2D_RC300, val);
|
|
|
|
g2dlite_write(base, G2D_RC304, 0);
|
|
|
|
val =
|
|
reg_value(hs_ratio_int, 0, G2D_SHIFT19_RC308, G2D_MASK19_RC308);
|
|
val = reg_value(hs_ratio_fra, val, G2D_SHIFT00_RC308,
|
|
G2D_MASK00_RC308);
|
|
g2dlite_write(base, G2D_RC308, val);
|
|
|
|
/*VSCALER*/
|
|
val = reg_value(vs_nor_para, val, G2D_SHIFT04_RC400,
|
|
G2D_MASK04_RC400);
|
|
g2dlite_write(base, G2D_RC400, val);
|
|
|
|
g2dlite_write(base, G2D_RC408, 0);
|
|
|
|
g2dlite_write(base, G2D_RC40C, 0);
|
|
|
|
g2dlite_write(base, G2D_RC410, 0);
|
|
}
|
|
|
|
static void g2dlite_spipe_init(struct g2dlite_device *dev)
|
|
{
|
|
unsigned int val;
|
|
unsigned long base = dev->reg_base;
|
|
|
|
val = g2dlite_read(base, G2D_RD200);
|
|
val = reg_value(1, val, G2D_SHIFT18_RD200, G2D_MASK18_RD200);
|
|
val = reg_value(1, val, G2D_SHIFT16_RD200, G2D_MASK16_RD200);
|
|
g2dlite_write(base, G2D_RD200, val);
|
|
|
|
val = g2dlite_read(base, G2D_RD204);
|
|
val = reg_value(1, val, G2D_SHIFT16_RD204, G2D_MASK16_RD204);
|
|
g2dlite_write(base, G2D_RD204, val);
|
|
|
|
val = g2dlite_read(base, G2D_RD208);
|
|
val = reg_value(1, val, G2D_SHIFT16_RD208, G2D_MASK16_RD208);
|
|
g2dlite_write(base, G2D_RD208, val);
|
|
|
|
val = g2dlite_read(base, G2D_RD20C);
|
|
val = reg_value(1, val, G2D_SHIFT16_RD20C, G2D_MASK16_RD20C);
|
|
g2dlite_write(base, G2D_RD20C, val);
|
|
}
|
|
|
|
static void g2dlite_mlc_init(struct g2dlite_device *dev)
|
|
{
|
|
int i = 0;
|
|
unsigned int val;
|
|
unsigned long base = dev->reg_base;
|
|
const unsigned char prot_val[] = {0x7, 0x7};
|
|
const unsigned char alpha_bld[] = {0xF, 0xF, 0xF};
|
|
const unsigned char pd_out[] = {0x7, 0x7, 0x7};
|
|
const unsigned char pd_des[] = {0x7, 0x7, 0x7};
|
|
const unsigned char pd_src[] = {0x7, 0x7, 0x7};
|
|
const unsigned char layer_out[] = {0xF, 0xF, 0xF};
|
|
|
|
/*LAYER related*/
|
|
for (i = 0; i < MLC_LAYER_COUNT; i++) {
|
|
val = reg_value(prot_val[i], 0, G2D_SHIFT08_RE000,
|
|
G2D_MASK08_RE000);
|
|
val =
|
|
reg_value(1, val, G2D_SHIFT02_RE000, G2D_MASK02_RE000);
|
|
g2dlite_write(base, G2D_RE000(i), val);
|
|
|
|
g2dlite_write(base, G2D_RE018(i), 0xFF);
|
|
}
|
|
|
|
/*PATH related*/
|
|
for (i = 0; i < MLC_PATH_COUNT; i++) {
|
|
val =
|
|
reg_value(alpha_bld[i], 0, G2D_SHIFT16_RE200, G2D_MASK16_RE200);
|
|
val = reg_value(pd_out[i], val, G2D_SHIFT12_RE200, G2D_MASK12_RE200);
|
|
val = reg_value(pd_des[i], val, G2D_SHIFT08_RE200, G2D_MASK08_RE200);
|
|
val = reg_value(pd_src[i], val, G2D_SHIFT04_RE200, G2D_MASK04_RE200);
|
|
val = reg_value(layer_out[i], val, G2D_SHIFT00_RE200,
|
|
G2D_MASK00_RE200);
|
|
g2dlite_write(base, G2D_RE200(i), val);
|
|
}
|
|
|
|
g2dlite_write(base, G2D_RE234, 0xFFFF);
|
|
|
|
g2dlite_write(base, G2D_RE240, 0);
|
|
}
|
|
|
|
static void g2dlite_wdma_init(struct g2dlite_device *dev)
|
|
{
|
|
int i = 0;
|
|
const unsigned short wml_cfg[] = {0x20, 0x10, 0x10};
|
|
const unsigned short d_depth_cfg[] = {0x04, 0x02, 0x02};
|
|
const unsigned short c_depth_cfg[] = {0x04, 0x02, 0x02};
|
|
const unsigned char sche_cfg[] = {0x04, 0x02, 0x02};
|
|
const unsigned char p1_cfg[] = {0x30, 0x30, 0x30};
|
|
const unsigned char p0_cfg[] = {0x10, 0x10, 0x10};
|
|
const unsigned char burst_mode_cfg[] = {0x00, 0x00, 0x00};
|
|
const unsigned char burst_len_cfg[] = {0x04, 0x04, 0x04};
|
|
unsigned int val;
|
|
unsigned long base = dev->reg_base;
|
|
|
|
for (i = 0; i < WCHN_COUNT; i++)
|
|
g2dlite_write(base, G2D_RG000(i), wml_cfg[i]);
|
|
|
|
for (i = 0; i < WCHN_COUNT; i++)
|
|
g2dlite_write(base, G2D_RG004(i), d_depth_cfg[i]);
|
|
|
|
for (i = 0; i < WCHN_COUNT; i++)
|
|
g2dlite_write(base, G2D_RG008(i), c_depth_cfg[i]);
|
|
|
|
for (i = 0; i < WCHN_COUNT; i++) {
|
|
val = reg_value(sche_cfg[i], 0, G2D_SHIFT16_RG00C,
|
|
G2D_MASK16_RG00C);
|
|
val = reg_value(p1_cfg[i], val, G2D_SHIFT08_RG00C,
|
|
G2D_MASK08_RG00C);
|
|
val = reg_value(p0_cfg[i], val, G2D_SHIFT00_RG00C,
|
|
G2D_MASK00_RG00C);
|
|
g2dlite_write(base, G2D_RG00C(i), val);
|
|
}
|
|
|
|
for (i = 0; i < WCHN_COUNT; i++) {
|
|
val = reg_value(burst_mode_cfg[i], 0, G2D_SHIFT03_RG010,
|
|
G2D_MASK03_RG010);
|
|
val = reg_value(burst_len_cfg[i], val, G2D_SHIFT00_RG010,
|
|
G2D_MASK00_RG010);
|
|
g2dlite_write(base, G2D_RG010(i), val);
|
|
}
|
|
|
|
g2dlite_write(base, G2D_RG520, 0);
|
|
}
|
|
|
|
static void g2dlite_wpipe_init(struct g2dlite_device *dev)
|
|
{
|
|
unsigned int val;
|
|
unsigned long base = dev->reg_base;
|
|
|
|
/*YUVDOWN Bypass*/
|
|
val = reg_value(1, 0, G2D_SHIFT08_RH008,
|
|
G2D_MASK08_RH008);
|
|
g2dlite_write(base, G2D_RH008, val);
|
|
|
|
/*CSC Bypass*/
|
|
val = reg_value(1, 0, G2D_SHIFT00_RH040, G2D_MASK00_RH040);
|
|
g2dlite_write(base, G2D_RH040, val);
|
|
|
|
val = reg_value(csc_param[3][1], 0, G2D_SHIFT16_RH044,
|
|
G2D_MASK16_RH044);
|
|
val = reg_value(csc_param[3][0], val, G2D_SHIFT00_RH044,
|
|
G2D_MASK00_RH044);
|
|
g2dlite_write(base, G2D_RH044, val);
|
|
|
|
val = reg_value(csc_param[3][3], 0, G2D_SHIFT16_RH048,
|
|
G2D_MASK16_RH048);
|
|
val = reg_value(csc_param[3][2], val, G2D_SHIFT00_RH048,
|
|
G2D_MASK00_RH048);
|
|
g2dlite_write(base, G2D_RH048, val);
|
|
|
|
val = reg_value(csc_param[3][5], 0, G2D_SHIFT16_RH04C,
|
|
G2D_MASK16_RH04C);
|
|
val = reg_value(csc_param[3][4], val, G2D_SHIFT00_RH04C,
|
|
G2D_MASK00_RH04C);
|
|
g2dlite_write(base, G2D_RH04C, val);
|
|
|
|
val = reg_value(csc_param[3][7], 0, G2D_SHIFT16_RH050,
|
|
G2D_MASK16_RH050);
|
|
val = reg_value(csc_param[3][6], val, G2D_SHIFT00_RH050,
|
|
G2D_MASK00_RH050);
|
|
g2dlite_write(base, G2D_RH050, val);
|
|
|
|
val = reg_value(csc_param[3][9], 0, G2D_SHIFT16_RH054,
|
|
G2D_MASK16_RH054);
|
|
val = reg_value(csc_param[3][8], val, G2D_SHIFT00_RH054,
|
|
G2D_MASK00_RH054);
|
|
g2dlite_write(base, G2D_RH054, val);
|
|
|
|
val = reg_value(csc_param[3][11], 0, G2D_SHIFT16_RH058,
|
|
G2D_MASK16_RH058);
|
|
val = reg_value(csc_param[3][10], val, G2D_SHIFT00_RH058,
|
|
G2D_MASK00_RH058);
|
|
g2dlite_write(base, G2D_RH058, val);
|
|
|
|
val = reg_value(csc_param[3][13], 0, G2D_SHIFT16_RH05C,
|
|
G2D_MASK16_RH05C);
|
|
val = reg_value(csc_param[3][12], val, G2D_SHIFT00_RH05C,
|
|
G2D_MASK00_RH05C);
|
|
g2dlite_write(base, G2D_RH05C, val);
|
|
|
|
val = reg_value(csc_param[3][14], 0, G2D_SHIFT00_RH060,
|
|
G2D_MASK00_RH060);
|
|
g2dlite_write(base, G2D_RH060, val);
|
|
}
|
|
|
|
static u8 get_r_idx(struct g2dlite_input *ins)
|
|
{
|
|
int g_nplanes = 0;
|
|
|
|
switch (ins->layer_num) {
|
|
case 1:
|
|
if (ins->layer[0].layer == G2DLITE_TYPE_GPIPE) {
|
|
g_nplanes = COLOR_GET_PLANE_COUNT(ins->layer[0].fmt);
|
|
return g_nplanes;
|
|
}
|
|
if (ins->layer[0].layer == G2DLITE_TYPE_SPIPE) {
|
|
return 4;
|
|
}
|
|
case 2:
|
|
for (int i = 0; i < 2; i++) {
|
|
if (ins->layer[i].layer == G2DLITE_TYPE_GPIPE) {
|
|
g_nplanes = COLOR_GET_PLANE_COUNT(ins->layer[0].fmt);
|
|
return (g_nplanes + 4);
|
|
}
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static u8 get_w_idx(struct g2dlite_output_cfg *output)
|
|
{
|
|
return COLOR_GET_PLANE_COUNT(output->fmt) - 1;
|
|
}
|
|
|
|
static void g2dlite_rwdma_set(struct g2dlite_device *dev, u8 r_idx, u8 w_idx)
|
|
{
|
|
int i = 0;
|
|
unsigned int val = 0;
|
|
unsigned long base = dev->reg_base;
|
|
|
|
for (i = 0; i < CHN_COUNT; i++)
|
|
g2dlite_write(base, G2D_RB000(i), r_wml_cfgs[r_idx][i]);
|
|
|
|
for (i = 0; i < CHN_COUNT; i++)
|
|
g2dlite_write(base, G2D_RB004(i),
|
|
r_d_depth_cfgs[r_idx][i]);
|
|
|
|
for (i = 0; i < CHN_COUNT; i++)
|
|
g2dlite_write(base, G2D_RB008(i),
|
|
r_c_depth_cfgs[r_idx][i]);
|
|
|
|
val = reg_value(1, 0, G2D_SHIFT01_RB400, G2D_MASK01_RB400);
|
|
val = reg_value(1, val, G2D_SHIFT00_RB400, G2D_MASK00_RB400);
|
|
g2dlite_write(base, G2D_RB400, val);
|
|
|
|
for (i = 0; i < WCHN_COUNT; i++)
|
|
g2dlite_write(base, G2D_RG000(i), w_wml_cfgs[w_idx][i]);
|
|
|
|
for (i = 0; i < WCHN_COUNT; i++)
|
|
g2dlite_write(base, G2D_RG004(i),
|
|
w_d_depth_cfgs[w_idx][i]);
|
|
|
|
for (i = 0; i < WCHN_COUNT; i++)
|
|
g2dlite_write(base, G2D_RG008(i),
|
|
w_c_depth_cfgs[w_idx][i]);
|
|
}
|
|
|
|
static void g2dlite_set_hscaler_coef(struct g2dlite_device *dev)
|
|
{
|
|
const int hscaler_coef[33][5] = {
|
|
{0, 0, 512, 0, 0}, {0, -5, 512, 5, 0},
|
|
{0, -10, 511, 11, 0}, {0, -14, 509, 17, 0},
|
|
{0, -18, 508, 23, -1}, {-1, -22, 507, 29, -1},
|
|
{-1, -25, 503, 36, -1}, {-1, -28, 500, 43, -2},
|
|
{-2, -31, 496, 51, -2}, {-2, -33, 491, 59, -3},
|
|
{-3, -35, 486, 67, -3}, {-3, -37, 481, 75, -4},
|
|
{-3, -39, 475, 84, -5}, {-4, -41, 471, 92, -6},
|
|
{-5, -42, 464, 102, -7}, {-5, -43, 457, 111, -8},
|
|
{-6, -43, 449, 121, -9}, {-6, -44, 442, 130, -10},
|
|
{-7, -44, 435, 140, -12}, {-7, -44, 425, 151, -13},
|
|
{-8, -44, 417, 161, -14}, {-8, -44, 408, 172, -16},
|
|
{-9, -44, 399, 183, -17}, {-9, -43, 390, 193, -19},
|
|
{-9, -42, 379, 204, -20}, {-10, -41, 369, 216, -22},
|
|
{-10, -40, 358, 227, -23}, {-11, -39, 349, 238, -25},
|
|
{-11, -38, 339, 249, -27}, {-11, -37, 327, 261, -28},
|
|
{-11, -36, 317, 272, -30}, {-12, -34, 306, 283, -31},
|
|
{-12, -33, 295, 295, -33},
|
|
};
|
|
unsigned int head, tail;
|
|
unsigned long base = dev->reg_base;
|
|
|
|
for (int i = 0; i < 33; i++) {
|
|
head = ((hscaler_coef[i][0] & 0x7ff) << 12) |
|
|
((hscaler_coef[i][1] & 0x7ff) << 1) |
|
|
((hscaler_coef[i][2] & 0x400) >> 10);
|
|
tail = ((hscaler_coef[i][2] & 0x3ff) << 22) |
|
|
((hscaler_coef[i][3] & 0x7ff) << 11) |
|
|
(hscaler_coef[i][4] & 0x7ff);
|
|
g2dlite_write(base, G2DLITE_HSCALER[0][0] + i * 4, head);
|
|
g2dlite_write(base, G2DLITE_HSCALER[0][0] + 0x100 + i * 4, tail);
|
|
}
|
|
}
|
|
|
|
static void g2dlite_set_vscaler_coef(struct g2dlite_device *dev)
|
|
{
|
|
const int vscaler_coef[33][4] = {
|
|
{0, 64, 0, 0}, {-1, 64, 1, 0}, {-1, 64, 1, 0}, {-2, 64, 2, 0},
|
|
{-2, 63, 3, 0}, {-3, 63, 4, 0}, {-3, 62, 5, 0}, {-3, 62, 5, 0},
|
|
{-4, 62, 6, 0}, {-4, 61, 7, 0}, {-4, 60, 8, 0}, {-5, 61, 9, -1},
|
|
{-5, 60, 10, -1}, {-5, 59, 11, -1}, {-5, 57, 13, -1}, {-5, 56, 14, -1},
|
|
{-5, 55, 15, -1}, {-5, 54, 16, -1}, {-5, 53, 17, -1}, {-5, 52, 19, -2},
|
|
{-5, 51, 20, -2}, {-5, 50, 21, -2}, {-5, 49, 22, -2}, {-5, 47, 24, -2},
|
|
{-5, 46, 25, -2}, {-5, 46, 26, -3}, {-5, 44, 28, -3}, {-5, 43, 29, -3},
|
|
{-5, 41, 31, -3}, {-5, 40, 32, -3}, {-4, 39, 33, -4}, {-4, 37, 35, -4},
|
|
{-4, 36, 36, -4},
|
|
};
|
|
unsigned int value;
|
|
unsigned long base = dev->reg_base;
|
|
|
|
for (uint32_t i = 0; i < 33; i++) {
|
|
value = ((vscaler_coef[i][3] & 0xff) << 24) |
|
|
((vscaler_coef[i][2] & 0xff) << 16) |
|
|
((vscaler_coef[i][1] & 0xff) << 8) |
|
|
((vscaler_coef[i][0] & 0xff));
|
|
g2dlite_write(base, G2DLITE_VSCALER[0][0] + i * 4, value);
|
|
}
|
|
}
|
|
|
|
static int g2dlite_plane_frm_comp_set(struct g2dlite_device *dev,
|
|
struct g2dlite_input_cfg *input)
|
|
{
|
|
unsigned int compval;
|
|
unsigned int frmc_val;
|
|
unsigned char abits, ybits, ubits, vbits;
|
|
unsigned char swap;
|
|
unsigned char comp_swap;
|
|
unsigned char is_yuv;
|
|
unsigned char is_uvswap;
|
|
unsigned char uv_mode;
|
|
unsigned char data_mode;
|
|
unsigned char buf_fmt;
|
|
|
|
abits = COLOR_GET_A_BITS_NUM(input->fmt);
|
|
ybits = COLOR_GET_Y_BITS_NUM(input->fmt);
|
|
ubits = COLOR_GET_U_BITS_NUM(input->fmt);
|
|
vbits = COLOR_GET_V_BITS_NUM(input->fmt);
|
|
compval = reg_value(vbits, 0, G2D_SHIFT24_RC000, G2D_MASK24_RC000);
|
|
compval = reg_value(ubits, compval, G2D_SHIFT16_RC000, G2D_MASK16_RC000);
|
|
compval = reg_value(ybits, compval, G2D_SHIFT08_RC000, G2D_MASK08_RC000);
|
|
compval = reg_value(abits, compval, G2D_SHIFT00_RC000, G2D_MASK00_RC000);
|
|
|
|
swap = COLOR_GET_SWAP(input->fmt);
|
|
comp_swap = COLOR_GET_COMP_SWAP(input->fmt);
|
|
is_yuv = COLOR_GET_IS_YUV(input->fmt);
|
|
is_uvswap = COLOR_GET_IS_UV_SWAP(input->fmt);
|
|
uv_mode = COLOR_GET_UV_MODE(input->fmt);
|
|
data_mode = COLOR_GET_DATA_MODE(input->fmt);
|
|
buf_fmt = COLOR_GET_BUF_FMT(input->fmt);
|
|
|
|
if ((input->layer == G2DLITE_TYPE_SPIPE) && input->rle.en) {
|
|
data_mode = RLE_COMPR_MODE;
|
|
}
|
|
|
|
frmc_val =
|
|
reg_value(swap, 0, G2D_SHIFT16_RC004, G2D_MASK16_RC004);
|
|
frmc_val = reg_value(comp_swap, frmc_val, G2D_SHIFT12_RC004,
|
|
G2D_MASK12_RC004);
|
|
frmc_val =
|
|
reg_value(is_yuv, frmc_val, G2D_SHIFT08_RC004, G2D_MASK08_RC004);
|
|
frmc_val =
|
|
reg_value(is_uvswap, frmc_val, G2D_SHIFT07_RC004, G2D_MASK07_RC004);
|
|
frmc_val =
|
|
reg_value(uv_mode, frmc_val, G2D_SHIFT05_RC004, G2D_MASK05_RC004);
|
|
frmc_val = reg_value(data_mode, frmc_val, G2D_SHIFT02_RC004, G2D_MASK02_RC004);
|
|
frmc_val = reg_value(buf_fmt, frmc_val, G2D_SHIFT00_RC004, G2D_MASK00_RC004);
|
|
|
|
if (input->layer == G2DLITE_TYPE_SPIPE) {
|
|
g2dlite_cwrite(dev, 0, G2D_RD000, compval);
|
|
g2dlite_cwrite(dev, 0, G2D_RD004, frmc_val);
|
|
} else if (input->layer == G2DLITE_TYPE_GPIPE) {
|
|
g2dlite_cwrite(dev, 0, G2D_RC000, compval);
|
|
g2dlite_cwrite(dev, 0, G2D_RC004, frmc_val);
|
|
} else {
|
|
G2DLITE_LOG_ERR("input layer = %d,the number is incorrect",
|
|
input->layer);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_wpipe_pixcomp_set(struct g2dlite_device *dev,
|
|
struct g2dlite_output_cfg *output)
|
|
{
|
|
unsigned int val;
|
|
unsigned char swap;
|
|
unsigned char abits, ybits, ubits, vbits;
|
|
unsigned char uv_mode, buf_fmt, reforce;
|
|
unsigned long base = dev->reg_base;
|
|
|
|
switch (COLOR_GET_PLANE_COUNT(output->fmt)) {
|
|
case 2:
|
|
case 3:
|
|
abits = 0;
|
|
ybits = 8;
|
|
ubits = 8;
|
|
vbits = 8;
|
|
break;
|
|
default:
|
|
abits = COLOR_GET_A_BITS_NUM(output->fmt);
|
|
ybits = COLOR_GET_Y_BITS_NUM(output->fmt);
|
|
ubits = COLOR_GET_U_BITS_NUM(output->fmt);
|
|
vbits = COLOR_GET_V_BITS_NUM(output->fmt);
|
|
break;
|
|
}
|
|
|
|
val = reg_value(vbits, 0, G2D_SHIFT24_RH004, G2D_MASK24_RH004);
|
|
val = reg_value(ubits, val, G2D_SHIFT16_RH004, G2D_MASK16_RH004);
|
|
val = reg_value(ybits, val, G2D_SHIFT08_RH004, G2D_MASK08_RH004);
|
|
val = reg_value(abits, val, G2D_SHIFT00_RH004, G2D_MASK00_RH004);
|
|
g2dlite_cwrite(dev, 0, G2D_RH004, val);
|
|
|
|
swap = COLOR_GET_SWAP(output->fmt);
|
|
uv_mode = COLOR_GET_UV_MODE(output->fmt);
|
|
buf_fmt = COLOR_GET_BUF_FMT(output->fmt);
|
|
reforce = (output->rotation == ROTATION_TYPE_NONE) ? 1 : 0;
|
|
val = g2dlite_read(base, G2D_RH000);
|
|
val = reg_value(swap, val, G2D_SHIFT16_RH000,
|
|
G2D_MASK16_RH000);
|
|
val = reg_value(reforce, val, G2D_SHIFT08_RH000,
|
|
G2D_MASK08_RH000);
|
|
val = reg_value(uv_mode, val, G2D_SHIFT06_RH000, G2D_MASK06_RH000);
|
|
val = reg_value(buf_fmt, val, G2D_SHIFT04_RH000, G2D_MASK04_RH000);
|
|
val = reg_value(output->rotation, val, G2D_SHIFT01_RH000,
|
|
G2D_MASK03_RH000 | G2D_MASK02_RH000 |
|
|
G2D_MASK01_RH000);
|
|
g2dlite_cwrite(dev, 0, G2D_RH000, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_wp_csc_set(struct g2dlite_device *dev,
|
|
struct g2dlite_output_cfg *output,
|
|
unsigned char flag)
|
|
{
|
|
unsigned int val;
|
|
unsigned char uv_mode;
|
|
unsigned char is_yuv;
|
|
unsigned char is_yuv420 = 0;
|
|
unsigned long base = dev->reg_base;
|
|
|
|
is_yuv = COLOR_GET_IS_YUV(output->fmt);
|
|
uv_mode = COLOR_GET_UV_MODE(output->fmt);
|
|
|
|
if (uv_mode == UV_YUV420)
|
|
is_yuv420 = 1;
|
|
|
|
if (flag & G2DLITE_FUN_BLEND) {
|
|
val = g2dlite_read(base, G2D_RH040);
|
|
val = reg_value(!is_yuv, val, G2D_SHIFT00_RH040,
|
|
G2D_MASK00_RH040);
|
|
g2dlite_cwrite(dev, 0, G2D_RH040, val);
|
|
}
|
|
|
|
val = g2dlite_read(base, G2D_RH008);
|
|
val = reg_value(!is_yuv420, val, G2D_SHIFT09_RH008,
|
|
G2D_MASK09_RH008);
|
|
val = reg_value(!is_yuv, val, G2D_SHIFT08_RH008,
|
|
G2D_MASK08_RH008);
|
|
g2dlite_cwrite(dev, 0, G2D_RH008, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_init(struct g2dlite_device *dev)
|
|
{
|
|
g2dlite_com_regs_init(dev);
|
|
g2dlite_rdma_init(dev);
|
|
g2dlite_gpipe_init(dev);
|
|
g2dlite_spipe_init(dev);
|
|
g2dlite_mlc_init(dev);
|
|
g2dlite_wdma_init(dev);
|
|
g2dlite_wpipe_init(dev);
|
|
|
|
g2dlite_set_hscaler_coef(dev);
|
|
g2dlite_set_vscaler_coef(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_reset(struct g2dlite_device *dev)
|
|
{
|
|
unsigned int val;
|
|
unsigned long base = dev->reg_base;
|
|
|
|
G2DLITE_LOG_FUNC();
|
|
val = g2dlite_read(base, G2D_RA000);
|
|
val = reg_value(1, val, G2D_SHIFT31_RA000, G2D_MASK31_RA000);
|
|
g2dlite_write(base, G2D_RA000, val);
|
|
|
|
udelay(10);
|
|
|
|
val = reg_value(0, val, G2D_SHIFT31_RA000, G2D_MASK31_RA000);
|
|
g2dlite_write(base, G2D_RA000, val);
|
|
|
|
dev->status = G2DLITE_IDLE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_gpipe_set(struct g2dlite_device *dev, char cmdid,
|
|
struct g2dlite_input_cfg *input)
|
|
{
|
|
const unsigned int p_hs = 524288;
|
|
const unsigned int p_vs = 262114;
|
|
|
|
unsigned int val;
|
|
unsigned int size;
|
|
unsigned int vs_inc;
|
|
unsigned char nplanes;
|
|
int ratio_int, ratio_fra;
|
|
unsigned long base = dev->reg_base;
|
|
unsigned long input_addr;
|
|
unsigned char is_yuv = 0;
|
|
|
|
nplanes = COLOR_GET_PLANE_COUNT(input->fmt);
|
|
if (!cmdid)
|
|
g2dlite_plane_frm_comp_set(dev, input);
|
|
|
|
/*pipe related*/
|
|
size = reg_value(input->src.w - 1, 0, G2D_SHIFT00_RC008, G2D_MASK00_RC008);
|
|
size = reg_value(input->src.h - 1, size, G2D_SHIFT16_RC008, G2D_MASK16_RC008);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC008, size);
|
|
|
|
input_addr = input->addr[0];
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC00C, get_l_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC010, get_h_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC02C, input->src_stride[0] - 1);
|
|
val = reg_value(input->src.x, 0, FRM_X_SHIFT, FRM_X_MASK);
|
|
val = reg_value(input->src.y, val, FRM_Y_SHIFT, FRM_Y_MASK);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC040, val);
|
|
|
|
if (nplanes > 1) {
|
|
input_addr = input->addr[1];
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC014,
|
|
get_l_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC018,
|
|
get_h_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC030,
|
|
input->src_stride[1] - 1);
|
|
}
|
|
|
|
if (nplanes > 2) {
|
|
input_addr = input->addr[2];
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC01C,
|
|
get_l_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC020,
|
|
get_h_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC034,
|
|
input->src_stride[2] - 1);
|
|
}
|
|
|
|
/*yuv params*/
|
|
is_yuv = COLOR_GET_IS_YUV(input->fmt);
|
|
val = g2dlite_read(base, G2D_RC044);
|
|
val = reg_value(is_yuv, val, G2D_SHIFT31_RC044,
|
|
G2D_MASK31_RC044);
|
|
val = reg_value(is_yuv ? 0 : 1, val, G2D_SHIFT00_RC044,
|
|
G2D_MASK00_RC044);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC044, val);
|
|
|
|
val = g2dlite_read(base, G2D_RC200);
|
|
val =
|
|
reg_value(is_yuv ? 0 : 1, val, G2D_SHIFT00_RC200, G2D_MASK00_RC200);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC200, val);
|
|
|
|
/*scaler part*/
|
|
if (input->src.w == input->dst.w) {
|
|
val = g2dlite_read(base, G2D_RC300);
|
|
val = reg_value(0, val, G2D_SHIFT03_RC300,
|
|
G2D_MASK03_RC300);
|
|
val = reg_value(0, val, G2D_SHIFT02_RC300,
|
|
G2D_MASK02_RC300);
|
|
val = reg_value(0, val, G2D_SHIFT01_RC300,
|
|
G2D_MASK01_RC300);
|
|
val = reg_value(0, val, G2D_SHIFT00_RC300,
|
|
G2D_MASK00_RC300);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC300, val);
|
|
|
|
val = reg_value(1, 0, G2D_SHIFT19_RC308, G2D_MASK19_RC308);
|
|
val = reg_value(0, val, G2D_SHIFT00_RC308, G2D_MASK00_RC308);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC308, val);
|
|
} else {
|
|
ratio_int = input->src.w / input->dst.w;
|
|
ratio_fra = (input->src.w - ratio_int * input->dst.w) * p_hs / input->dst.w;
|
|
|
|
val = g2dlite_read(base, G2D_RC300);
|
|
val = reg_value(1, val, G2D_SHIFT03_RC300,
|
|
G2D_MASK03_RC300);
|
|
val = reg_value(1, val, G2D_SHIFT02_RC300,
|
|
G2D_MASK02_RC300);
|
|
val = reg_value(1, val, G2D_SHIFT01_RC300,
|
|
G2D_MASK01_RC300);
|
|
val = reg_value(1, val, G2D_SHIFT00_RC300,
|
|
G2D_MASK00_RC300);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC300, val);
|
|
|
|
val = reg_value(ratio_int, 0, G2D_SHIFT19_RC308,
|
|
G2D_MASK19_RC308);
|
|
val = reg_value(ratio_fra, val, G2D_SHIFT00_RC308,
|
|
G2D_MASK00_RC308);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC308, val);
|
|
}
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC30C, input->dst.w - 1);
|
|
|
|
size = reg_value(input->src.h - 1, 0, G2D_SHIFT16_RC108,
|
|
G2D_MASK16_RC108);
|
|
size = reg_value(input->dst.w - 1, size, G2D_SHIFT00_RC108,
|
|
G2D_MASK00_RC108);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC108, size);
|
|
|
|
if (input->src.h == input->dst.h) {
|
|
val = g2dlite_read(base, G2D_RC400);
|
|
val = reg_value(0, val, G2D_SHIFT00_RC400,
|
|
G2D_MASK00_RC400);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC400, val);
|
|
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC408, 0);
|
|
} else {
|
|
vs_inc = (int)((1.0 * (input->src.h - 1)) / (input->dst.h - 1) * p_vs);
|
|
val = g2dlite_read(base, G2D_RC400);
|
|
val = reg_value(2, val, G2D_SHIFT00_RC400,
|
|
G2D_MASK00_RC400);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC400, val);
|
|
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC408, vs_inc);
|
|
}
|
|
g2dlite_cwrite(dev, cmdid, G2D_RC404, input->dst.h - 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_spipe_set(struct g2dlite_device *dev, char cmdid,
|
|
struct g2dlite_input_cfg *input)
|
|
{
|
|
unsigned int val;
|
|
unsigned int size;
|
|
unsigned long input_addr;
|
|
|
|
if (!cmdid)
|
|
g2dlite_plane_frm_comp_set(dev, input);
|
|
|
|
/*pipe related*/
|
|
size = reg_value(input->src.w - 1, 0, G2D_SHIFT00_RC008, G2D_MASK00_RC008);
|
|
size = reg_value(input->src.h - 1, size, G2D_SHIFT16_RC008, G2D_MASK16_RC008);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD008, size);
|
|
|
|
input_addr = input->addr[0];
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD00C, get_l_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD010, get_h_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD02C, input->src_stride[0] - 1);
|
|
val = reg_value(input->src.x, 0, FRM_X_SHIFT, FRM_X_MASK);
|
|
val = reg_value(input->src.y, val, FRM_Y_SHIFT, FRM_Y_MASK);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD040, val);
|
|
|
|
/*rle*/
|
|
val = reg_value(input->rle.en, 0, G2D_SHIFT00_RD120, G2D_MASK00_RD120);
|
|
if (input->rle.en) {
|
|
val = reg_value(input->rle.rle_data_size, val, G2D_SHIFT01_RD120,
|
|
G2D_MASK01_RD120);
|
|
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD100, input->rle.rle_y_len);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD110,
|
|
input->rle.rle_y_checksum);
|
|
}
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD120, val);
|
|
|
|
/*clut*/
|
|
if (input->clut.en) {
|
|
u8 bpa = COLOR_GET_A_BITS_NUM(input->fmt);
|
|
u8 bpy = COLOR_GET_A_BITS_NUM(input->fmt);
|
|
u8 bpu = COLOR_GET_A_BITS_NUM(input->fmt);
|
|
u8 bpv = COLOR_GET_A_BITS_NUM(input->fmt);
|
|
|
|
/*G2D_RD200*/
|
|
val = g2dlite_read(dev->reg_base, G2D_RD200);
|
|
if (bpa) {
|
|
val = reg_value(0, val, G2D_SHIFT16_RD200, G2D_MASK16_RD200);
|
|
val = reg_value(bpa, val, G2D_SHIFT00_RD200, G2D_MASK00_RD200);
|
|
} else {
|
|
val = reg_value(1, val, G2D_SHIFT16_RD200, G2D_MASK16_RD200);
|
|
}
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD200, val);
|
|
|
|
/*G2D_RD204*/
|
|
val = g2dlite_read(dev->reg_base, G2D_RD204);
|
|
if (bpy) {
|
|
val = reg_value(0, val, G2D_SHIFT16_RD204, G2D_MASK16_RD204);
|
|
val = reg_value(bpy, val, G2D_SHIFT00_RD204, G2D_MASK00_RD204);
|
|
} else {
|
|
val = reg_value(1, val, G2D_SHIFT16_RD204, G2D_MASK16_RD204);
|
|
}
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD204, val);
|
|
|
|
/*G2D_RD208*/
|
|
val = g2dlite_read(dev->reg_base, G2D_RD208);
|
|
if (bpu) {
|
|
val = reg_value(0, val, G2D_SHIFT16_RD208, G2D_MASK16_RD208);
|
|
val = reg_value(bpu, val, G2D_SHIFT00_RD208, G2D_MASK00_RD208);
|
|
} else {
|
|
val = reg_value(1, val, G2D_SHIFT16_RD208, G2D_MASK16_RD208);
|
|
}
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD208, val);
|
|
|
|
/*G2D_RD20C*/
|
|
val = g2dlite_read(dev->reg_base, G2D_RD20C);
|
|
if (bpv) {
|
|
val = reg_value(0, val, G2D_SHIFT16_RD20C, G2D_MASK16_RD20C);
|
|
val = reg_value(bpv, val, G2D_SHIFT00_RD20C, G2D_MASK00_RD20C);
|
|
} else {
|
|
val = reg_value(1, val, G2D_SHIFT16_RD20C, G2D_MASK16_RD20C);
|
|
}
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD20C, val);
|
|
} else {
|
|
/*G2D_RD200*/
|
|
val = g2dlite_read(dev->reg_base, G2D_RD200);
|
|
val = reg_value(1, val, G2D_SHIFT16_RD200, G2D_MASK16_RD200);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD200, val);
|
|
|
|
/*G2D_RD204*/
|
|
val = g2dlite_read(dev->reg_base, G2D_RD204);
|
|
val = reg_value(1, val, G2D_SHIFT16_RD204, G2D_MASK16_RD204);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD204, val);
|
|
|
|
/*G2D_RD208*/
|
|
val = g2dlite_read(dev->reg_base, G2D_RD208);
|
|
val = reg_value(1, val, G2D_SHIFT16_RD208, G2D_MASK16_RD208);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD208, val);
|
|
|
|
/*G2D_RD20C*/
|
|
val = g2dlite_read(dev->reg_base, G2D_RD20C);
|
|
val = reg_value(1, val, G2D_SHIFT16_RD20C, G2D_MASK16_RD20C);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RD20C, val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void g2dlite_close_fastcopy(struct g2dlite_device *dev)
|
|
{
|
|
unsigned int val;
|
|
unsigned long base = dev->reg_base;
|
|
|
|
/*disable background in order to remove fastcopy
|
|
*bring affect when fastcopy using before other
|
|
*functions*/
|
|
val = g2dlite_read(base, G2D_RF004);
|
|
val = reg_value(0, val, G2D_SHIFT00_RF004,
|
|
G2D_MASK00_RF004);
|
|
g2dlite_write(base, G2D_RF004, val);
|
|
|
|
val = g2dlite_read(base, G2D_RE220);
|
|
val = reg_value(0, val, G2D_SHIFT02_RE220, G2D_MASK02_RE220);
|
|
val = reg_value(0, val, G2D_SHIFT01_RE220, G2D_MASK01_RE220);
|
|
g2dlite_write(base, G2D_RE220, val);
|
|
}
|
|
|
|
static int g2dlite_mlc_set(struct g2dlite_device *dev, char cmdid,
|
|
struct g2dlite_input *ins)
|
|
{
|
|
int i = 0;
|
|
u32 val, sf_val[G2DLITE_MLC_MAX], path_val[MLC_PATH_MAX];
|
|
u64 base = dev->reg_base;
|
|
u8 pd_types_flag = 0;
|
|
|
|
/*disable all layers*/
|
|
for (i = 0; i < G2DLITE_MLC_MAX; i++) {
|
|
val = g2dlite_read(base, G2D_RE000(i));
|
|
sf_val[i] = reg_value(0, val, G2D_SHIFT00_RE000, G2D_MASK00_RE000);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE000(i), sf_val[i]);
|
|
}
|
|
|
|
/*disable all paths*/
|
|
for (i = 0; i < MLC_PATH_MAX; i++) {
|
|
path_val[i] = 0xF777F;
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE200(i), path_val[i]);
|
|
}
|
|
|
|
if (ins->bg_layer.en) {
|
|
struct g2dlite_bg_cfg *bgcfg = &ins->bg_layer;
|
|
|
|
if (ins->pd_info.en && (ins->bg_layer.pd_type != PD_NONE)) {
|
|
switch (ins->bg_layer.pd_type) {
|
|
case PD_SRC:
|
|
path_val[0] = reg_value(0, path_val[0], G2D_SHIFT04_RE200,
|
|
G2D_MASK04_RE200);
|
|
pd_types_flag |= PD_SRC;
|
|
break;
|
|
case PD_DST:
|
|
path_val[0] = reg_value(0, path_val[0], G2D_SHIFT08_RE200,
|
|
G2D_MASK08_RE200);
|
|
pd_types_flag |= PD_DST;
|
|
break;
|
|
default:
|
|
G2DLITE_LOG_ERR("input bglayer porter-duff type isn't correct");
|
|
return -1;
|
|
}
|
|
|
|
path_val[0] = reg_value(G2DLITE_PD_IDX, path_val[0],
|
|
G2D_SHIFT00_RE200, G2D_MASK00_RE200);
|
|
} else {
|
|
/*PATH with zorder*/
|
|
path_val[0] = reg_value(bgcfg->zorder, path_val[0],
|
|
G2D_SHIFT00_RE200, G2D_MASK00_RE200);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE200(0), path_val[0]);
|
|
|
|
path_val[bgcfg->zorder] =
|
|
reg_value(0, path_val[bgcfg->zorder], G2D_SHIFT16_RE200,
|
|
G2D_MASK16_RE200);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE200(bgcfg->zorder),
|
|
path_val[bgcfg->zorder]);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < G2DLITE_MLC_MAX; i++) {
|
|
struct g2dlite_input_cfg *input = &ins->layer[i];
|
|
|
|
if (!input->layer_en)
|
|
continue;
|
|
|
|
u8 layer_index = input->layer;
|
|
u8 path_index = input->layer + 1;
|
|
|
|
if (layer_index >= G2DLITE_MLC_MAX) {
|
|
G2DLITE_LOG_ERR("input layer = %d, the number isn't correct",
|
|
input->layer);
|
|
return -1;
|
|
}
|
|
|
|
/*POS*/
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE004(layer_index), input->dst.x);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE008(layer_index), input->dst.y);
|
|
|
|
/*dst size*/
|
|
val = reg_value(input->dst.h - 1, 0, G2D_SHIFT16_RE00C,
|
|
G2D_MASK16_RE00C);
|
|
val = reg_value(input->dst.w - 1, val, G2D_SHIFT00_RE00C,
|
|
G2D_MASK00_RE00C);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE00C(layer_index), val);
|
|
|
|
if (ins->pd_info.en && (input->pd_type != PD_NONE)) {
|
|
if (pd_types_flag == (PD_SRC | PD_DST)) {
|
|
G2DLITE_LOG_ERR("porter-duff type was already input");
|
|
return -1;
|
|
}
|
|
|
|
switch (input->pd_type) {
|
|
case PD_SRC:
|
|
path_val[0] = reg_value(path_index, path_val[0],
|
|
G2D_SHIFT04_RE200, G2D_MASK04_RE200);
|
|
pd_types_flag |= PD_SRC;
|
|
break;
|
|
case PD_DST:
|
|
path_val[0] = reg_value(path_index, path_val[0],
|
|
G2D_SHIFT08_RE200, G2D_MASK08_RE200);
|
|
pd_types_flag |= PD_DST;
|
|
break;
|
|
default:
|
|
G2DLITE_LOG_ERR("input layer%d porter-duff type isn't correct",
|
|
input->layer);
|
|
return -1;
|
|
}
|
|
|
|
path_val[path_index] =
|
|
reg_value(G2DLITE_PD_IDX, path_val[path_index],
|
|
G2D_SHIFT00_RE200, G2D_MASK00_RE200);
|
|
|
|
switch (input->blend) {
|
|
case BLEND_PIXEL_NONE:
|
|
default:
|
|
sf_val[layer_index] =
|
|
reg_value(1, sf_val[layer_index], G2D_SHIFT02_RE000,
|
|
G2D_MASK02_RE000);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE018(layer_index),
|
|
input->alpha);
|
|
break;
|
|
case BLEND_PIXEL_COVERAGE:
|
|
sf_val[layer_index] =
|
|
reg_value(0, sf_val[layer_index], G2D_SHIFT02_RE000,
|
|
G2D_MASK02_RE000);
|
|
break;
|
|
}
|
|
} else {
|
|
/*PATH with zorder*/
|
|
path_val[path_index] =
|
|
reg_value(input->zorder, path_val[path_index],
|
|
G2D_SHIFT00_RE200, G2D_MASK00_RE200);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE200(path_index),
|
|
path_val[path_index]);
|
|
|
|
path_val[input->zorder] =
|
|
reg_value(path_index, path_val[input->zorder],
|
|
G2D_SHIFT16_RE200, G2D_MASK16_RE200);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE200(input->zorder),
|
|
path_val[input->zorder]);
|
|
|
|
/*Blend mode*/
|
|
switch (input->blend) {
|
|
case BLEND_PIXEL_NONE:
|
|
default:
|
|
sf_val[layer_index] =
|
|
reg_value(1, sf_val[layer_index], G2D_SHIFT02_RE000,
|
|
G2D_MASK02_RE000);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE018(layer_index),
|
|
input->alpha);
|
|
break;
|
|
case BLEND_PIXEL_PREMULTI:
|
|
sf_val[layer_index] =
|
|
reg_value(0, sf_val[layer_index], G2D_SHIFT02_RE000,
|
|
G2D_MASK02_RE000);
|
|
|
|
path_val[input->zorder] = reg_value(1, path_val[input->zorder],
|
|
G2D_SHIFT29_RE200, G2D_MASK29_RE200);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE200(input->zorder),
|
|
path_val[input->zorder]);
|
|
break;
|
|
case BLEND_PIXEL_COVERAGE:
|
|
sf_val[layer_index] =
|
|
reg_value(0, sf_val[layer_index], G2D_SHIFT02_RE000,
|
|
G2D_MASK02_RE000);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*enable layer*/
|
|
sf_val[layer_index] =
|
|
reg_value(1, sf_val[layer_index], G2D_SHIFT00_RE000, G2D_MASK00_RE000);
|
|
|
|
/*ckey*/
|
|
sf_val[layer_index] =
|
|
reg_value(input->ckey.en, sf_val[layer_index], G2D_SHIFT03_RE000,
|
|
G2D_MASK03_RE000);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE000(layer_index),
|
|
sf_val[layer_index]);
|
|
if (input->ckey.en) {
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE01C(layer_index),
|
|
input->ckey.alpha);
|
|
val = reg_value(input->ckey.range.r_dn, 0, G2D_SHIFT00_RE020,
|
|
G2D_MASK00_RE020);
|
|
val = reg_value(input->ckey.range.r_up, val,
|
|
G2D_SHIFT16_RE020, G2D_MASK16_RE020);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE020(layer_index), val);
|
|
val = reg_value(input->ckey.range.g_dn, 0, G2D_SHIFT00_RE020,
|
|
G2D_MASK00_RE020);
|
|
val = reg_value(input->ckey.range.g_up, val,
|
|
G2D_SHIFT16_RE020, G2D_MASK16_RE020);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE024(layer_index), val);
|
|
val = reg_value(input->ckey.range.b_dn, 0, G2D_SHIFT00_RE020,
|
|
G2D_MASK00_RE020);
|
|
val = reg_value(input->ckey.range.b_up, val,
|
|
G2D_SHIFT16_RE020, G2D_MASK16_RE020);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE028(layer_index), val);
|
|
}
|
|
}
|
|
|
|
if (ins->pd_info.en) {
|
|
path_val[0] = reg_value(ins->pd_info.mode, path_val[0], G2D_SHIFT20_RE200,
|
|
G2D_MASK20_RE200);
|
|
path_val[0] = reg_value(ins->pd_info.zorder, path_val[0],
|
|
G2D_SHIFT12_RE200, G2D_MASK12_RE200);
|
|
path_val[ins->pd_info.zorder] =
|
|
reg_value(G2DLITE_PD_IDX, path_val[ins->pd_info.zorder],
|
|
G2D_SHIFT16_RE200, G2D_MASK16_RE200);
|
|
|
|
for (i = 0; i < MLC_PATH_MAX; i++) {
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE200(i), path_val[i]);
|
|
}
|
|
|
|
/*We bypass alpha blend for output alpha.If we input 3 layers(2 layers
|
|
for porter-duff, 1 layer for alpha blend with porter-duff output, we
|
|
must clear this bit. G2DLite W-pipe output set 0xFF to alpha value.
|
|
*/
|
|
val = g2dlite_read(base, G2D_RE220);
|
|
if (ins->pd_info.alpha_need)
|
|
val = reg_value(1, val, G2D_SHIFT00_RE220, G2D_MASK00_RE220);
|
|
else
|
|
val = reg_value(0, val, G2D_SHIFT00_RE220, G2D_MASK00_RE220);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE220, val);
|
|
} else {
|
|
val = g2dlite_read(base, G2D_RE220);
|
|
val = reg_value(0, val, G2D_SHIFT00_RE220, G2D_MASK00_RE220);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RE220, val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_wpipe_set(struct g2dlite_device *dev, char cmdid,
|
|
struct g2dlite_output_cfg *output)
|
|
{
|
|
unsigned int val;
|
|
unsigned char nplanes;
|
|
unsigned char bpp[3] = {0};
|
|
unsigned long input_addr;
|
|
|
|
if (!cmdid) {
|
|
g2dlite_wpipe_pixcomp_set(dev, output);
|
|
g2dlite_wp_csc_set(dev, output, G2DLITE_FUN_BLEND);
|
|
}
|
|
|
|
val = reg_value(output->height - 1, 0, G2D_SHIFT16_RA00C,
|
|
G2D_MASK16_RA00C);
|
|
val = reg_value(output->width - 1, val, G2D_SHIFT00_RA00C,
|
|
G2D_MASK00_RA00C);
|
|
g2dlite_cwrite(dev, cmdid, G2D_RA00C, val);
|
|
|
|
nplanes = COLOR_GET_PLANE_COUNT(output->fmt);
|
|
get_bpp_by_format(output->fmt, bpp);
|
|
input_addr = output->addr[0];
|
|
g2dlite_cwrite(dev, cmdid, G2D_RH010, get_l_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RH014, get_h_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RH028, output->stride[0] - 1);
|
|
|
|
if (nplanes > 1) {
|
|
input_addr = output->addr[1];
|
|
g2dlite_cwrite(dev, cmdid, G2D_RH018, get_l_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RH01C, get_h_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RH02C, output->stride[1] - 1);
|
|
}
|
|
|
|
if (nplanes > 2) {
|
|
input_addr = output->addr[2];
|
|
g2dlite_cwrite(dev, cmdid, G2D_RH020, get_l_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RH024, get_h_addr(input_addr));
|
|
g2dlite_cwrite(dev, cmdid, G2D_RH030, output->stride[2] - 1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void g2dlite_slice_input(struct g2dlite_input_cfg *src,
|
|
struct g2dlite_input_cfg *slice_input,
|
|
unsigned int slice_w,
|
|
unsigned char max_slice_num,
|
|
unsigned char slice_idx)
|
|
{
|
|
unsigned int slice_width;
|
|
unsigned long src_addr;
|
|
unsigned char nplanes;
|
|
unsigned char bpp[3] = {0};
|
|
/* copy */
|
|
if (!slice_idx) {
|
|
slice_input->layer = src->layer;
|
|
slice_input->layer_en = src->layer_en;
|
|
slice_input->fmt = src->fmt;
|
|
slice_input->zorder = src->zorder;
|
|
slice_input->src.x = src->src.x;
|
|
slice_input->src.y = src->src.y;
|
|
slice_input->src.h = src->src.h;
|
|
slice_input->dst.x = src->dst.x;
|
|
slice_input->dst.y = src->dst.y;
|
|
slice_input->dst.h = src->dst.h;
|
|
slice_input->ckey.en = src->ckey.en;
|
|
slice_input->ckey = src->ckey;
|
|
slice_input->blend = src->blend;
|
|
slice_input->alpha = src->alpha;
|
|
slice_input->src_stride[0] = src->src_stride[0];
|
|
slice_input->src_stride[1] = src->src_stride[1];
|
|
slice_input->src_stride[2] = src->src_stride[2];
|
|
slice_input->src_stride[3] = src->src_stride[3];
|
|
}
|
|
|
|
/*change to slice*/
|
|
nplanes = COLOR_GET_PLANE_COUNT(src->fmt);
|
|
get_bpp_by_format(src->fmt, bpp);
|
|
slice_width =
|
|
(slice_idx == (max_slice_num - 1))
|
|
? ((src->dst.w % slice_w) ? (src->dst.w % slice_w) : slice_w)
|
|
: slice_w;
|
|
slice_input->src.w = slice_width;
|
|
slice_input->dst.w = slice_width;
|
|
src_addr = src->addr[0] + slice_idx * slice_w * bpp[0] / 8;
|
|
slice_input->addr[0] = src_addr;
|
|
slice_input->src_stride[0] = src->src_stride[0];
|
|
if (nplanes > 1) {
|
|
src_addr = src->addr[1] + slice_idx * slice_w * bpp[1] / 8;
|
|
slice_input->addr[1] = src_addr;
|
|
}
|
|
if (nplanes > 2) {
|
|
src_addr = src->addr[2] + slice_idx * slice_w * bpp[2] / 8;
|
|
slice_input->addr[2] = src_addr;
|
|
}
|
|
}
|
|
|
|
static void g2dlite_slice_output(struct g2dlite_output_cfg *src,
|
|
struct g2dlite_output_cfg *slice_output,
|
|
unsigned int slice_w,
|
|
unsigned char max_slice_num,
|
|
unsigned char slice_idx)
|
|
{
|
|
unsigned int slice_width;
|
|
unsigned char nplanes;
|
|
unsigned char bpp[3] = {0};
|
|
|
|
if (!slice_idx) {
|
|
slice_output->height = src->height;
|
|
slice_output->fmt = src->fmt;
|
|
slice_output->stride[0] = src->stride[0];
|
|
slice_output->stride[1] = src->stride[1];
|
|
slice_output->stride[2] = src->stride[2];
|
|
slice_output->stride[3] = src->stride[3];
|
|
slice_output->rotation = src->rotation;
|
|
}
|
|
nplanes = COLOR_GET_PLANE_COUNT(src->fmt);
|
|
get_bpp_by_format(src->fmt, bpp);
|
|
slice_width =
|
|
(slice_idx == (max_slice_num - 1))
|
|
? ((src->width % slice_w) ? (src->width % slice_w) : slice_w)
|
|
: slice_w;
|
|
slice_output->width = slice_width;
|
|
switch (src->rotation) {
|
|
case ROTATION_TYPE_NONE:
|
|
case ROTATION_TYPE_VFLIP:
|
|
slice_output->addr[0] = src->addr[0] + slice_idx * slice_w * bpp[0] / 8;
|
|
if (nplanes > 1) {
|
|
slice_output->addr[1] =
|
|
src->addr[1] + slice_idx * slice_w * bpp[1] / 8;
|
|
}
|
|
if (nplanes > 2) {
|
|
slice_output->addr[2] =
|
|
src->addr[2] + slice_idx * slice_w * bpp[2] / 8;
|
|
}
|
|
break;
|
|
case ROTATION_TYPE_ROT_90:
|
|
case ROTATION_TYPE_HF_90:
|
|
slice_output->addr[0] =
|
|
src->addr[0] + slice_idx * slice_w * src->stride[0];
|
|
if (nplanes > 1) {
|
|
slice_output->addr[1] =
|
|
src->addr[1] + slice_idx * slice_w * src->stride[1];
|
|
}
|
|
if (nplanes > 2) {
|
|
slice_output->addr[2] =
|
|
src->addr[2] + slice_idx * slice_w * src->stride[2];
|
|
}
|
|
break;
|
|
case ROTATION_TYPE_HFLIP:
|
|
case ROTATION_TYPE_ROT_180:
|
|
slice_output->addr[0] =
|
|
src->addr[0] +
|
|
(src->width - (slice_idx * slice_w + slice_width)) * bpp[0] / 8;
|
|
if (nplanes > 1) {
|
|
slice_output->addr[1] =
|
|
src->addr[1] +
|
|
(src->width - (slice_idx * slice_w + slice_width)) * bpp[1] / 8;
|
|
}
|
|
if (nplanes > 2) {
|
|
slice_output->addr[2] =
|
|
src->addr[2] +
|
|
(src->width - (slice_idx * slice_w + slice_width)) * bpp[2] / 8;
|
|
}
|
|
break;
|
|
case ROTATION_TYPE_ROT_270:
|
|
case ROTATION_TYPE_VF_90:
|
|
slice_output->addr[0] =
|
|
src->addr[0] +
|
|
(src->width - (slice_idx * slice_w + slice_width)) * src->stride[0];
|
|
if (nplanes > 1) {
|
|
slice_output->addr[1] =
|
|
src->addr[1] +
|
|
(src->width - (slice_idx * slice_w + slice_width)) *
|
|
src->stride[1];
|
|
}
|
|
if (nplanes > 2) {
|
|
slice_output->addr[2] =
|
|
src->addr[2] +
|
|
(src->width - (slice_idx * slice_w + slice_width)) *
|
|
src->stride[2];
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int g2dlite_rotation(struct g2dlite_device *dev,
|
|
struct g2dlite_input *ins)
|
|
{
|
|
const unsigned int slice_w = 256;
|
|
unsigned int slice_count;
|
|
struct g2dlite_input slice_ins;
|
|
memset(&slice_ins, 0, sizeof(struct g2dlite_input));
|
|
struct g2dlite_input_cfg *input = &slice_ins.layer[0];
|
|
struct g2dlite_output_cfg *output = &slice_ins.output;
|
|
|
|
if (!dev || !ins) {
|
|
G2DLITE_LOG_ERR("dev or input isn't inited.[dev:%p, ins:%p]", dev, ins);
|
|
return -1;
|
|
}
|
|
|
|
u8 r_idx = get_r_idx(ins);
|
|
u8 w_idx = get_w_idx(&ins->output);
|
|
g2dlite_rwdma_set(dev, r_idx, w_idx);
|
|
g2dlite_close_fastcopy(dev);
|
|
|
|
slice_count = (ins->layer[0].dst.w / slice_w) +
|
|
((ins->layer[0].dst.w % slice_w) ? 1 : 0);
|
|
for (unsigned int i = 0; i < slice_count; i++) {
|
|
G2DLITE_LOG_INFO("slice[%d|%d]", i, slice_count);
|
|
g2dlite_slice_input(&ins->layer[0], input, slice_w, slice_count, i);
|
|
g2dlite_gpipe_set(dev, i, input);
|
|
g2dlite_mlc_set(dev, i, &slice_ins);
|
|
|
|
g2dlite_slice_output(&ins->output, output, slice_w, slice_count, i);
|
|
g2dlite_wpipe_set(dev, i, output);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_bg_set(struct g2dlite_device *dev,
|
|
struct g2dlite_bg_cfg *bgcfg,
|
|
struct g2dlite_output_cfg *output,
|
|
u8 bypass_alpha_blending)
|
|
{
|
|
|
|
u32 val, a_addr_l, a_addr_h, a_stride;
|
|
unsigned long base = dev->reg_base;
|
|
unsigned long a_addr;
|
|
u8 alpha_select = 0;
|
|
|
|
if (bgcfg->aaddr) {
|
|
a_addr = bgcfg->aaddr;
|
|
a_addr_l = get_l_addr(a_addr);
|
|
a_addr_h = get_h_addr(a_addr);
|
|
a_stride = bgcfg->astride;
|
|
alpha_select = 1;
|
|
if (!a_stride)
|
|
a_stride = (output->width * bgcfg->bpa + 7) / 8 - 1;
|
|
|
|
/*AP_PIX_COMP*/
|
|
val = g2dlite_read(base, G2D_RF000);
|
|
val = reg_value(bgcfg->bpa, val, G2D_SHIFT00_RF000,
|
|
G2D_MASK00_RF000);
|
|
g2dlite_cwrite(dev, 0, G2D_RF000, val);
|
|
|
|
/*AP_FRM_SIZE*/
|
|
val = reg_value(output->height - 1, 0, G2D_SHIFT16_RF008,
|
|
G2D_MASK16_RF008);
|
|
val = reg_value(output->width - 1, val, G2D_SHIFT00_RF008,
|
|
G2D_MASK00_RF008);
|
|
g2dlite_cwrite(dev, 0, G2D_RF008, val);
|
|
|
|
/*AP_BADDR_L*/
|
|
val = reg_value(a_addr_l, 0, G2D_SHIFT00_RF00C, G2D_MASK00_RF00C);
|
|
g2dlite_cwrite(dev, 0, G2D_RF00C, val);
|
|
|
|
/*AP_BADDR_H*/
|
|
val = reg_value(a_addr_h, 0, G2D_SHIFT00_RF010, G2D_MASK00_RF010);
|
|
g2dlite_cwrite(dev, 0, G2D_RF010, val);
|
|
|
|
/*AP_STRIDE*/
|
|
val = reg_value(a_stride - 1, 0, G2D_SHIFT00_RF02C, G2D_MASK00_RF02C);
|
|
g2dlite_cwrite(dev, 0, G2D_RF02C, val);
|
|
}
|
|
|
|
/*G2D_RE220*/
|
|
val = g2dlite_read(base, G2D_RE220);
|
|
val = reg_value(bgcfg->g_alpha, val, G2D_SHIFT08_RE220, G2D_MASK08_RE220);
|
|
val = reg_value(alpha_select, val, G2D_SHIFT02_RE220, G2D_MASK02_RE220);
|
|
val = reg_value(1, val, G2D_SHIFT01_RE220, G2D_MASK01_RE220);
|
|
val = reg_value(bypass_alpha_blending, val,
|
|
G2D_SHIFT00_RE220, G2D_MASK00_RE220);
|
|
g2dlite_write(base, G2D_RE220, val);
|
|
|
|
/*G2D_RE224*/
|
|
g2dlite_cwrite(dev, 0, G2D_RE224, bgcfg->color);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_fill_rect(struct g2dlite_device *dev,
|
|
struct g2dlite_bg_cfg *bgcfg,
|
|
struct g2dlite_output_cfg *output)
|
|
{
|
|
int i = 0;
|
|
u32 val;
|
|
u64 base = dev->reg_base;
|
|
|
|
u8 w_idx = get_w_idx(output);
|
|
g2dlite_rwdma_set(dev, 0, w_idx);
|
|
g2dlite_close_fastcopy(dev);
|
|
|
|
/*disable all layers*/
|
|
for (i = 0; i < G2DLITE_MLC_MAX; i++) {
|
|
val = g2dlite_read(base, G2D_RE000(i));
|
|
val = reg_value(0, val, G2D_SHIFT00_RE000, G2D_MASK00_RE000);
|
|
g2dlite_cwrite(dev, 0, G2D_RE000(i), val);
|
|
}
|
|
|
|
/*disable all layer's paths*/
|
|
for (i = 1; i < MLC_PATH_MAX; i++) {
|
|
g2dlite_cwrite(dev, 0, G2D_RE200(i), 0xF777F);
|
|
}
|
|
g2dlite_cwrite(dev, 0, G2D_RE200(0), 0x07770);
|
|
|
|
g2dlite_bg_set(dev, bgcfg, output, 1);
|
|
|
|
g2dlite_wpipe_set(dev, 0, output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_fastcopy(struct g2dlite_device *dev, struct fcopy_t *in,
|
|
struct fcopy_t *out)
|
|
{
|
|
u32 val, i_addr_l, i_addr_h, o_addr_l, o_addr_h;
|
|
unsigned long base = dev->reg_base;
|
|
unsigned long i_addr, o_addr;
|
|
|
|
i_addr = in->addr;
|
|
i_addr_l = get_l_addr(i_addr);
|
|
i_addr_h = get_h_addr(i_addr);
|
|
o_addr = out->addr;
|
|
o_addr_l = get_l_addr(o_addr);
|
|
o_addr_h = get_h_addr(o_addr);
|
|
|
|
g2dlite_rwdma_set(dev, 0, 0);
|
|
/*AP_FRM_CTRL*/
|
|
val = g2dlite_read(base, G2D_RF004);
|
|
val = reg_value(1, val, G2D_SHIFT00_RF004,
|
|
G2D_MASK00_RF004);
|
|
g2dlite_cwrite(dev, 0, G2D_RF004, val);
|
|
|
|
/*AP_FRM_SIZE*/
|
|
val = reg_value(in->height - 1, 0, G2D_SHIFT16_RF008,
|
|
G2D_MASK16_RF008);
|
|
val = reg_value(in->width - 1, val, G2D_SHIFT00_RF008,
|
|
G2D_MASK00_RF008);
|
|
g2dlite_cwrite(dev, 0, G2D_RF008, val);
|
|
|
|
/*AP_BADDR_L*/
|
|
val = reg_value(i_addr_l, 0, G2D_SHIFT00_RF00C, G2D_MASK00_RF00C);
|
|
g2dlite_cwrite(dev, 0, G2D_RF00C, val);
|
|
|
|
/*AP_BADDR_H*/
|
|
val = reg_value(i_addr_h, 0, G2D_SHIFT00_RF010, G2D_MASK00_RF010);
|
|
g2dlite_cwrite(dev, 0, G2D_RF010, val);
|
|
|
|
/*AP_STRIDE*/
|
|
val = reg_value(in->stride - 1, 0, G2D_SHIFT00_RF02C, G2D_MASK00_RF02C);
|
|
g2dlite_cwrite(dev, 0, G2D_RF02C, val);
|
|
|
|
/*Config W-pipe*/
|
|
val = reg_value(out->height - 1, 0, G2D_SHIFT16_RA00C,
|
|
G2D_MASK16_RA00C);
|
|
val = reg_value(out->width - 1, val, G2D_SHIFT00_RA00C,
|
|
G2D_MASK00_RA00C);
|
|
g2dlite_cwrite(dev, 0, G2D_RA00C, val);
|
|
|
|
g2dlite_cwrite(dev, 0, G2D_RH010, o_addr_l);
|
|
g2dlite_cwrite(dev, 0, G2D_RH014, o_addr_h);
|
|
g2dlite_cwrite(dev, 0, G2D_RH028, out->stride - 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_update(struct g2dlite_device *dev, struct g2dlite_input *ins)
|
|
{
|
|
if (!dev || !ins) {
|
|
G2DLITE_LOG_ERR("dev or input isn't inited.[dev:%p, ins:%p]", dev, ins);
|
|
return -1;
|
|
}
|
|
|
|
u8 r_idx = get_r_idx(ins);
|
|
u8 w_idx = get_w_idx(&ins->output);
|
|
g2dlite_rwdma_set(dev, r_idx, w_idx);
|
|
g2dlite_close_fastcopy(dev);
|
|
|
|
if (ins->bg_layer.en)
|
|
g2dlite_bg_set(dev, &ins->bg_layer, &ins->output, 0);
|
|
|
|
for (unsigned int i = 0; i < ins->layer_num; i++) {
|
|
if (ins->layer[i].layer == G2DLITE_TYPE_SPIPE) {
|
|
g2dlite_spipe_set(dev, 0, &ins->layer[i]);
|
|
} else {
|
|
g2dlite_gpipe_set(dev, 0, &ins->layer[i]);
|
|
}
|
|
}
|
|
g2dlite_mlc_set(dev, 0, ins);
|
|
g2dlite_wpipe_set(dev, 0, &ins->output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_clut_index_set(struct g2dlite_device *dev, char *clut_src)
|
|
{
|
|
u32 value;
|
|
u32 offset = 0;
|
|
u64 base = dev->reg_base;
|
|
u32 size = (G2DLITE_CLUT_EADDR - G2DLITE_CLUT_SADDR + 1) / 4;
|
|
|
|
for (u32 i = 0; i < size; i++, offset += 4) {
|
|
value = (clut_src[offset + 3] << 24) | (clut_src[offset + 2] << 16) |
|
|
(clut_src[offset + 1] << 8) | (clut_src[offset]);
|
|
g2dlite_write(base, G2DLITE_CLUT_SADDR, value);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_enable(struct g2dlite_device *dev)
|
|
{
|
|
int i = 0;
|
|
unsigned int val;
|
|
unsigned long base = dev->reg_base;
|
|
unsigned char valid_count = 0;
|
|
cmdfile_info *cmd;
|
|
unsigned long input_addr;
|
|
|
|
if (dev->write_mode == G2DLITE_CMD_WRITE) {
|
|
for (i = 0; i < G2DLITE_CMDFILE_MAX_NUM; i++) {
|
|
cmd = &dev->cmd_info[i];
|
|
if (!cmd->dirty) {
|
|
valid_count = i;
|
|
break;
|
|
} else {
|
|
cmd->dirty = 0;
|
|
}
|
|
}
|
|
G2DLITE_LOG_INFO("valid_count = %d", valid_count);
|
|
for (i = 0; i < valid_count; i++) {
|
|
cmd = &dev->cmd_info[i];
|
|
if (i < valid_count - 1) {
|
|
input_addr = (paddr_t)dev->cmd_info[i + 1].arg;
|
|
G2DLITE_LOG_INFO("input_addr = 0x%lx", input_addr);
|
|
cmd->arg[cmd->len++] = G2D_RA010;
|
|
cmd->arg[cmd->len++] = get_l_addr(input_addr);
|
|
cmd->arg[cmd->len++] = G2D_RA014;
|
|
cmd->arg[cmd->len++] = get_h_addr(input_addr);
|
|
cmd->arg[cmd->len++] = G2D_RA018;
|
|
cmd->len++;
|
|
} else {
|
|
cmd->arg[cmd->len++] = G2D_RA01C;
|
|
cmd->arg[cmd->len++] = 0;
|
|
|
|
G2DLITE_LOG_INFO("G2DLITE_CMDFILE_CFG = %d",
|
|
G2D_RA01C);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < valid_count - 1; i++) {
|
|
cmd = &dev->cmd_info[i];
|
|
cmd->arg[cmd->len - 1] = dev->cmd_info[i + 1].len / 2 - 1;
|
|
G2DLITE_LOG_INFO("dev->cmd_info[%d].len / 2 - 1 = 0x%x", i + 1,
|
|
dev->cmd_info[i + 1].len / 2 - 1);
|
|
}
|
|
|
|
for (i = 0; i < valid_count; i++) {
|
|
cmd = &dev->cmd_info[i];
|
|
arch_clean_cache_range((addr_t)cmd->arg, cmd->len * 4);
|
|
}
|
|
|
|
input_addr = (paddr_t)dev->cmd_info[0].arg;
|
|
g2dlite_write(base, G2D_RA010, get_l_addr(input_addr));
|
|
g2dlite_write(base, G2D_RA014, get_h_addr(input_addr));
|
|
g2dlite_write(base, G2D_RA018,
|
|
dev->cmd_info[0].len / 2 - 1);
|
|
val = g2dlite_read(base, G2D_RA01C);
|
|
val = reg_value(1, val, G2D_SHIFT03_RA01C,
|
|
G2D_MASK03_RA01C);
|
|
g2dlite_write(base, G2D_RA01C, val);
|
|
|
|
for (i = 0; i < valid_count; i++) {
|
|
dev->cmd_info[i].len = 0;
|
|
}
|
|
}
|
|
|
|
val = g2dlite_read(base, G2D_RA000);
|
|
val = reg_value(1, val, G2D_SHIFT00_RA000, G2D_MASK00_RA000);
|
|
g2dlite_write(base, G2D_RA000, val);
|
|
|
|
dev->status = G2DLITE_WORKING;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_irq_handler(u32 irq, void *arg)
|
|
{
|
|
|
|
unsigned int value;
|
|
struct g2dlite_device *dev = (struct g2dlite_device *)arg;
|
|
|
|
unsigned long base = dev->reg_base;
|
|
value = g2dlite_read(base, G2D_RA024);
|
|
g2dlite_write(base, G2D_RA024, value);
|
|
|
|
if (value & G2D_MASK06_RA020) {
|
|
dev->status = G2DLITE_DONE;
|
|
#if CONFIG_OS_FREERTOS
|
|
BaseType_t taskwoken;
|
|
xSemaphoreGiveFromISR(done_sema, &taskwoken);
|
|
#endif
|
|
if (dev->done_callback)
|
|
dev->done_callback();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int g2dlite_check_status(struct g2dlite_device *dev)
|
|
{
|
|
return dev->status;
|
|
}
|
|
|
|
const struct g2dlite_ops ops = {
|
|
.init = g2dlite_init,
|
|
.reset = g2dlite_reset,
|
|
.clut_index_set = g2dlite_clut_index_set,
|
|
.update = g2dlite_update,
|
|
.rotation = g2dlite_rotation,
|
|
.fill_rect = g2dlite_fill_rect,
|
|
.fastcopy = g2dlite_fastcopy,
|
|
.enable = g2dlite_enable,
|
|
.irq_handler = g2dlite_irq_handler,
|
|
.check_status = g2dlite_check_status,
|
|
};
|