Files
MilkV-Duo/u-boot-2021.10/drivers/video/cvitek/scaler.c
wangliang.wang 607778300c [uboot] Upgrade the MMF SDK from V4.0.0 to V4.1.0
1. add cv181x functions
	2. Delete some useless files and add .gitignore

Change-Id: Iea2b2fa43b5a1152e5e99fb32b88f8d2c249251a
2023-03-10 20:42:30 +08:00

1427 lines
37 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <common.h>
#include <linux/delay.h>
#include "vip_common.h"
#include "scaler.h"
#include "scaler_reg.h"
#include "reg.h"
#include "dsi_phy.h"
/****************************************************************************
* Global parameters
****************************************************************************/
static struct sclr_top_cfg g_top_cfg;
static struct sclr_disp_cfg g_disp_cfg;
static struct sclr_disp_timing disp_timing;
static uintptr_t reg_base;
/****************************************************************************
* Initial info
****************************************************************************/
#define DEFINE_CSC_COEF0(a, b, c) \
.coef[0][0] = a, .coef[0][1] = b, .coef[0][2] = c,
#define DEFINE_CSC_COEF1(a, b, c) \
.coef[1][0] = a, .coef[1][1] = b, .coef[1][2] = c,
#define DEFINE_CSC_COEF2(a, b, c) \
.coef[2][0] = a, .coef[2][1] = b, .coef[2][2] = c,
static struct sclr_csc_matrix csc_mtrx[SCL_CSC_MAX] = {
// none
{
DEFINE_CSC_COEF0(BIT(10), 0, 0)
DEFINE_CSC_COEF1(0, BIT(10), 0)
DEFINE_CSC_COEF2(0, 0, BIT(10))
.sub[0] = 0, .sub[1] = 0, .sub[2] = 0,
.add[0] = 0, .add[1] = 0, .add[2] = 0
},
// yuv2rgb
// 601 Limited
// R = Y + 1.402* Pr //
// G = Y - 0.344 * Pb - 0.792* Pr //
// B = Y + 1.772 * Pb //
{
DEFINE_CSC_COEF0(BIT(10), 0, 1436)
DEFINE_CSC_COEF1(BIT(10), BIT(13) | 352, BIT(13) | 731)
DEFINE_CSC_COEF2(BIT(10), 1815, 0)
.sub[0] = 0, .sub[1] = 128, .sub[2] = 128,
.add[0] = 0, .add[1] = 0, .add[2] = 0
},
// 601 Full
// R = 1.164 *(Y - 16) + 1.596 *(Cr - 128) //
// G = 1.164 *(Y - 16) - 0.392 *(Cb - 128) - 0.812 *(Cr - 128) //
// B = 1.164 *(Y - 16) + 2.016 *(Cb - 128) //
{
DEFINE_CSC_COEF0(1192, 0, 1634)
DEFINE_CSC_COEF1(1192, BIT(13) | 401, BIT(13) | 833)
DEFINE_CSC_COEF2(1192, 2065, 0)
.sub[0] = 16, .sub[1] = 128, .sub[2] = 128,
.add[0] = 0, .add[1] = 0, .add[2] = 0
},
// 709 Limited
// R = Y + 1.540(Cr 128)
// G = Y - 0.183(Cb 128) 0.459(Cr 128)
// B = Y + 1.816(Cb 128)
{
DEFINE_CSC_COEF0(BIT(10), 0, 1577)
DEFINE_CSC_COEF1(BIT(10), BIT(13) | 187, BIT(13) | 470)
DEFINE_CSC_COEF2(BIT(10), 1860, 0)
.sub[0] = 0, .sub[1] = 128, .sub[2] = 128,
.add[0] = 0, .add[1] = 0, .add[2] = 0
},
// 709 Full
// R = 1.164 *(Y - 16) + 1.792 *(Cr - 128) //
// G = 1.164 *(Y - 16) - 0.213 *(Cb - 128) - 0.534 *(Cr - 128) //
// B = 1.164 *(Y - 16) + 2.114 *(Cb - 128) //
{
DEFINE_CSC_COEF0(1192, 0, 1836)
DEFINE_CSC_COEF1(1192, BIT(13) | 218, BIT(13) | 547)
DEFINE_CSC_COEF2(1192, 2166, 0)
.sub[0] = 16, .sub[1] = 128, .sub[2] = 128,
.add[0] = 0, .add[1] = 0, .add[2] = 0
},
// rgb2yuv
// 601 Limited
// Y = 0.299 * R + 0.587 * G + 0.114 * B //
// Pb =-0.169 * R - 0.331 * G + 0.500 * B //
// Pr = 0.500 * R - 0.419 * G - 0.081 * B //
{
DEFINE_CSC_COEF0(306, 601, 117)
DEFINE_CSC_COEF1(BIT(13) | 173, BIT(13) | 339, 512)
DEFINE_CSC_COEF2(512, BIT(13) | 429, BIT(13) | 83)
.sub[0] = 0, .sub[1] = 0, .sub[2] = 0,
.add[0] = 0, .add[1] = 128, .add[2] = 128
},
// 601 Full
// Y = 16 + 0.257 * R + 0.504 * g + 0.098 * b //
// Cb = 128 - 0.148 * R - 0.291 * g + 0.439 * b //
// Cr = 128 + 0.439 * R - 0.368 * g - 0.071 * b //
{
DEFINE_CSC_COEF0(263, 516, 100)
DEFINE_CSC_COEF1(BIT(13) | 152, BIT(13) | 298, 450)
DEFINE_CSC_COEF2(450, BIT(13) | 377, BIT(13) | 73)
.sub[0] = 0, .sub[1] = 0, .sub[2] = 0,
.add[0] = 16, .add[1] = 128, .add[2] = 128
},
// 709 Limited
// Y = 0.2126 0.7152 0.0722
// Cb = 128 - 0.1146 -0.3854 0.5000
// Cr = 128 + 0.5000 -0.4542 -0.0468
{
DEFINE_CSC_COEF0(218, 732, 74)
DEFINE_CSC_COEF1(BIT(13) | 117, BIT(13) | 395, 512)
DEFINE_CSC_COEF2(512, BIT(13) | 465, BIT(13) | 48)
.sub[0] = 0, .sub[1] = 0, .sub[2] = 0,
.add[0] = 0, .add[1] = 128, .add[2] = 128
},
// 709 Full
// Y = 16 + 0.183 * R + 0.614 * g + 0.062 * b //
// Cb = 128 - 0.101 * R - 0.339 * g + 0.439 * b //
// Cr = 128 + 0.439 * R - 0.399 * g - 0.040 * b //
{
DEFINE_CSC_COEF0(187, 629, 63)
DEFINE_CSC_COEF1(BIT(13) | 103, BIT(13) | 347, 450)
DEFINE_CSC_COEF2(450, BIT(13) | 408, BIT(13) | 41)
.sub[0] = 0, .sub[1] = 0, .sub[2] = 0,
.add[0] = 16, .add[1] = 128, .add[2] = 128
},
};
/****************************************************************************
* Interfaces
****************************************************************************/
void sclr_set_base_addr(void *base)
{
reg_base = (uintptr_t)base;
}
/**
* sclr_top_set_cfg - set scl-top's configurations.
*
* @param cfg: scl-top's settings.
*/
void sclr_top_set_cfg(struct sclr_top_cfg *cfg)
{
u32 sc_top = 0;
union vip_sys_clk clk;
_reg_write(reg_base + REG_SCL_TOP_CFG0, cfg->ip_trig_src << 3);
clk = vip_get_clk_lp();
clk.b.sc_top = 1;
vip_set_clk_lp(clk);
if (cfg->sclr_enable[0])
sc_top |= BIT(0);
if (cfg->sclr_enable[1])
sc_top |= BIT(1);
if (cfg->sclr_enable[2])
sc_top |= BIT(2);
if (cfg->sclr_enable[3])
sc_top |= BIT(3);
if (cfg->disp_enable)
sc_top |= BIT(4);
if (cfg->disp_from_sc)
sc_top |= BIT(8);
if (cfg->sclr_d_src)
sc_top |= BIT(9);
_reg_write(reg_base + REG_SCL_TOP_CFG1, sc_top);
sclr_img_set_trig(SCL_IMG_D, cfg->img_in_d_trig_src);
sclr_img_set_trig(SCL_IMG_V, cfg->img_in_v_trig_src);
sclr_top_reg_done();
sclr_top_reg_force_up();
g_top_cfg = *cfg;
}
/**
* sclr_top_get_cfg - get scl_top's cfg
*
* @return: scl_top's cfg
*/
struct sclr_top_cfg *sclr_top_get_cfg(void)
{
return &g_top_cfg;
}
/**
* sclr_top_reg_done - to mark all sc-reg valid for update.
*
*/
void sclr_top_reg_done(void)
{
_reg_write_mask(reg_base + REG_SCL_TOP_CFG0, 0, 1);
}
/**
* sclr_top_reg_force_up - trigger reg update by sw.
*
*/
void sclr_top_reg_force_up(void)
{
_reg_write_mask(reg_base + REG_SCL_TOP_SHD, 0x00ff, 0xff);
}
u8 sclr_top_pg_late_get_bus(void)
{
return (_reg_read(reg_base + REG_SCL_TOP_PG) >> 8) & 0xff;
}
void sclr_top_pg_late_clr(void)
{
_reg_write_mask(reg_base + REG_SCL_TOP_PG, 0x0f0000, 0x80000);
}
union sclr_intr sclr_get_intr_mask(void)
{
union sclr_intr intr_mask;
intr_mask.raw = _reg_read(reg_base + REG_SCL_TOP_INTR_MASK);
return intr_mask;
}
/**
* sclr_set_intr_mask - sclr's interrupt mask. Only enable ones will be
* integrated to vip_subsys. check 'union sclr_intr'
* for each bit mask.
*
* @param intr_mask: On/Off ctrl of the interrupt.
*/
void sclr_set_intr_mask(union sclr_intr intr_mask)
{
_reg_write(reg_base + REG_SCL_TOP_INTR_MASK, intr_mask.raw);
}
/**
* sclr_intr_clr - clear sclr's interrupt
* check 'union sclr_intr' for each bit mask
*
* @param intr_mask: On/Off ctrl of the interrupt.
*/
void sclr_intr_clr(union sclr_intr intr_mask)
{
_reg_write(reg_base + REG_SCL_TOP_INTR_STATUS, intr_mask.raw);
}
/**
* sclr_intr_status - sclr's interrupt status
* check 'union sclr_intr' for each bit mask
*
* @return: The interrupt's status
*/
union sclr_intr sclr_intr_status(void)
{
union sclr_intr status;
status.raw = (_reg_read(reg_base + REG_SCL_TOP_INTR_STATUS) & 0xffff);
return status;
}
/**
* sclr_img_set_trig - set img's src of job_start.
*
* @param inst: (0~1), the instance of img-in which want to be configured.
* @param trig_src: img's src of job_start.
*/
void sclr_img_set_trig(u8 inst, enum sclr_img_trig_src trig_src)
{
u32 mask = BIT(12) | BIT(8);
u32 val = 0;
switch (trig_src) {
case SCL_IMG_TRIG_SRC_SW:
break;
case SCL_IMG_TRIG_SRC_DISP:
val |= BIT(8);
break;
case SCL_IMG_TRIG_SRC_ISP:
val |= BIT(12);
break;
default:
break;
}
if (inst == SCL_IMG_V) {
mask <<= 1;
val <<= 1;
g_top_cfg.img_in_v_trig_src = trig_src;
} else {
g_top_cfg.img_in_d_trig_src = trig_src;
}
//uartlog("mask(%#x) val(%#x)\n", mask, val);
_reg_write_mask(reg_base + REG_SCL_TOP_IMG_CTRL, mask, val);
}
/****************************************************************************
* SCALER GOP
****************************************************************************/
/**
* sclr_gop_set_cfg - configure gop
*
* @param inst: (0~4), the instance of gop which want to be configured.
* 0~3 is on scl, 4 is on disp.
* @param cfg: gop's settings
*/
void sclr_gop_set_cfg(u8 inst, struct sclr_gop_cfg *cfg)
{
_reg_write(reg_base + REG_SCL_DISP_GOP_CFG, cfg->raw & 0xffff);
_reg_write(reg_base + REG_SCL_DISP_GOP_FONTCOLOR,
(cfg->font_fg_color << 16) | cfg->font_bg_color);
if (cfg->b.colorkey_en)
_reg_write(reg_base + REG_SCL_DISP_GOP_COLORKEY,
cfg->colorkey);
g_disp_cfg.gop_cfg = *cfg;
}
/**
* sclr_gop_get_cfg - get gop's configurations.
*
* @param inst: (0~4), the instance of gop which want to be configured.
* 0~3 is on scl, 4 is on disp.
*/
struct sclr_gop_cfg *sclr_gop_get_cfg(u8 inst)
{
return &g_disp_cfg.gop_cfg;
return NULL;
}
/**
* sclr_gop_setup LUT - setup gop's Look-up table
*
* @param inst: (0~4), the instance of gop which want to be configured.
* 0~3 is on scl, 4 is on disp.
* @param data: values of LUT-table. There should be 256 instances.
*/
void sclr_gop_setup_LUT(u8 inst, u16 *data)
{
u16 i = 0;
for (i = 0; i < 256; ++i) {
_reg_write(reg_base + REG_SCL_DISP_GOP_LUT0,
(i << 16) | *(data + i));
_reg_write(reg_base + REG_SCL_DISP_GOP_LUT1, (u32)~BIT(16));
_reg_write(reg_base + REG_SCL_DISP_GOP_LUT1, BIT(16));
}
}
/**
* sclr_gop_update_LUT - update gop's Look-up table by index.
*
* @param inst: (0~4), the instance of gop which want to be configured.
* 0~3 is on scl, 4 is on disp.
* @param index: start address of LUT-table. There should be 256 instances.
* @param data: value of LUT-table.
*/
int sclr_gop_update_LUT(u8 inst, u8 index, u16 data)
{
if (index > 255)
return -1;
_reg_write(reg_base + REG_SCL_DISP_GOP_LUT0,
(index << 16) | data);
_reg_write(reg_base + REG_SCL_DISP_GOP_LUT1, (u32)~BIT(16));
_reg_write(reg_base + REG_SCL_DISP_GOP_LUT1, BIT(16));
return 0;
}
/**
* sclr_gop_ow_set_cfg - set gop's osd-window configurations.
*
* @param inst: (0~4), the instance of gop which want to be configured.
* 0~3 is on scl, 4 is on disp.
* @param ow_inst: (0~7), the instance of ow which want to be configured.
* @param cfg: ow's settings.
*/
void sclr_gop_ow_set_cfg(u8 inst, u8 ow_inst, struct sclr_gop_ow_cfg *cfg)
{
static u8 reg_map_fmt[SCL_GOP_FMT_MAX] = {0, 0x4, 0x5, 0x8, 0xc};
_reg_write(reg_base + REG_SCL_DISP_GOP_FMT(ow_inst),
reg_map_fmt[cfg->fmt]);
_reg_write(reg_base + REG_SCL_DISP_GOP_H_RANGE(ow_inst),
(cfg->end.x << 16) | cfg->start.x);
_reg_write(reg_base + REG_SCL_DISP_GOP_V_RANGE(ow_inst),
(cfg->end.y << 16) | cfg->start.y);
_reg_write(reg_base + REG_SCL_DISP_GOP_ADDR_L(ow_inst),
cfg->addr);
_reg_write(reg_base + REG_SCL_DISP_GOP_ADDR_H(ow_inst),
cfg->addr >> 32);
_reg_write(reg_base + REG_SCL_DISP_GOP_PITCH(ow_inst),
cfg->pitch);
_reg_write(reg_base + REG_SCL_DISP_GOP_SIZE(ow_inst),
(cfg->mem_size.h << 16) | cfg->mem_size.w);
g_disp_cfg.gop_cfg.ow_cfg[ow_inst] = *cfg;
}
/****************************************************************************
* SCALER DISP
****************************************************************************/
/**
* sclr_disp_reg_shadow_sel - control the read reg-bank.
*
* @param read_shadow: true(shadow); false(working)
*/
void sclr_disp_reg_shadow_sel(bool read_shadow)
{
_reg_write_mask(reg_base + REG_SCL_DISP_CFG, BIT(18),
(read_shadow ? 0x0 : BIT(18)));
}
/**
* sclr_disp_reg_shadow_mask - reg won't be update by sw/hw until unmask.
*
* @param mask: true(mask); false(unmask)
* @return: mask status before thsi modification.
*/
bool sclr_disp_reg_shadow_mask(bool mask)
{
bool is_masked = (_reg_read(reg_base + REG_SCL_DISP_CFG) & BIT(17));
if (is_masked != mask)
_reg_write_mask(reg_base + REG_SCL_DISP_CFG, BIT(17),
(mask ? 0x0 : BIT(17)));
return is_masked;
}
/**
* sclr_disp_reg_force_up - trigger reg update by sw.
*
*/
void sclr_disp_reg_force_up(void)
{
_reg_write_mask(reg_base + REG_SCL_DISP_CFG, BIT(16), BIT(16));
}
/**
* sclr_disp_tgen - enable timing-generator on disp.
*
* @param enable: AKA.
* @return: tgen's enable status before change.
*/
bool sclr_disp_tgen_enable(bool enable)
{
bool is_enable = (_reg_read(reg_base + REG_SCL_DISP_CFG) & 0x80);
if (is_enable != enable) {
_reg_write_mask(reg_base + REG_SCL_DISP_CFG, 0x0080,
enable ? 0x80 : 0x00);
g_disp_cfg.tgen_en = enable;
}
return is_enable;
}
/**
* sclr_disp_set_cfg - set disp's configurations.
*
* @param cfg: disp's settings.
*/
void sclr_disp_set_cfg(struct sclr_disp_cfg *cfg)
{
u32 tmp = 0;
bool is_enable = false;
tmp |= cfg->disp_from_sc;
tmp |= (cfg->fmt << 12);
if (cfg->sync_ext)
tmp |= BIT(4);
if (cfg->tgen_en)
tmp |= BIT(7);
if (cfg->dw1_en)
tmp |= BIT(8);
if (cfg->dw2_en)
tmp |= BIT(9);
is_enable = sclr_disp_reg_shadow_mask(false);
if (!cfg->disp_from_sc) {
sclr_disp_set_mem(&cfg->mem);
_reg_write_mask(reg_base + REG_SCL_DISP_PITCH_Y, 0xf0000000,
cfg->burst << 28);
sclr_disp_set_in_csc(cfg->in_csc);
}
sclr_disp_set_out_csc(cfg->out_csc);
_reg_write_mask(reg_base + REG_SCL_DISP_CFG, 0x0000ff9f, tmp);
_reg_write_mask(reg_base + REG_SCL_DISP_CACHE, BIT(0), cfg->cache_mode);
switch (cfg->out_bit) {
case 6:
tmp = 3 << 16;
break;
case 8:
tmp = 2 << 16;
break;
default:
tmp = 0;
break;
}
tmp |= cfg->drop_mode << 18;
_reg_write_mask(reg_base + REG_SCL_DISP_PAT_COLOR4, 0x000f0000, tmp);
if (is_enable)
sclr_disp_reg_shadow_mask(true);
g_disp_cfg = *cfg;
}
/**
* sclr_disp_get_cfg - get scl_disp's cfg
*
* @return: scl_disp's cfg
*/
struct sclr_disp_cfg *sclr_disp_get_cfg(void)
{
return &g_disp_cfg;
}
/**
* sclr_disp_set_timing - modify disp's timing-generator.
*
* @param timing: new timing of disp.
*/
void sclr_disp_set_timing(struct sclr_disp_timing *timing)
{
u32 tmp = 0;
bool is_enable = sclr_disp_tgen_enable(false);
if (timing->vsync_pol)
tmp |= 0x20;
if (timing->hsync_pol)
tmp |= 0x40;
_reg_write_mask(reg_base + REG_SCL_DISP_CFG, 0x0060, tmp);
_reg_write(reg_base + REG_SCL_DISP_TOTAL,
(timing->htotal << 16) | timing->vtotal);
_reg_write(reg_base + REG_SCL_DISP_VSYNC,
(timing->vsync_end << 16) | timing->vsync_start);
_reg_write(reg_base + REG_SCL_DISP_VFDE,
(timing->vfde_end << 16) | timing->vfde_start);
_reg_write(reg_base + REG_SCL_DISP_VMDE,
(timing->vmde_end << 16) | timing->vmde_start);
_reg_write(reg_base + REG_SCL_DISP_HSYNC,
(timing->hsync_end << 16) | timing->hsync_start);
_reg_write(reg_base + REG_SCL_DISP_HFDE,
(timing->hfde_end << 16) | timing->hfde_start);
_reg_write(reg_base + REG_SCL_DISP_HMDE,
(timing->hmde_end << 16) | timing->hmde_start);
if (is_enable)
sclr_disp_tgen_enable(true);
disp_timing = *timing;
}
struct sclr_disp_timing *sclr_disp_get_timing(void)
{
return &disp_timing;
}
/**
* sclr_disp_set_rect - setup rect(me) of disp
*
* @param rect: the pos/size of me, which should fit with disp's input.
*/
int sclr_disp_set_rect(struct sclr_rect rect)
{
bool is_enable = sclr_disp_reg_shadow_mask(false);
if ((rect.y > disp_timing.vfde_end) ||
(rect.x > disp_timing.hfde_end) ||
((disp_timing.vfde_start + rect.y + rect.h - 1) >
disp_timing.vfde_end) ||
((disp_timing.hfde_start + rect.x + rect.w - 1) >
disp_timing.hfde_end)) {
debug("[cvi-vip][sc] %s: me's pos(%d, %d) size(%d, %d) ",
__func__, rect.x, rect.y, rect.w, rect.h);
debug(" out of range(%d, %d).\n",
disp_timing.hfde_end, disp_timing.vfde_end);
return -EINVAL;
}
disp_timing.vmde_start = rect.y + disp_timing.vfde_start;
disp_timing.hmde_start = rect.x + disp_timing.hfde_start;
disp_timing.vmde_end = disp_timing.vmde_start + rect.h - 1;
disp_timing.hmde_end = disp_timing.hmde_start + rect.w - 1;
_reg_write(reg_base + REG_SCL_DISP_HMDE,
(disp_timing.hmde_end << 16) | disp_timing.hmde_start);
_reg_write(reg_base + REG_SCL_DISP_VMDE,
(disp_timing.vmde_end << 16) | disp_timing.vmde_start);
if (is_enable)
sclr_disp_reg_shadow_mask(true);
return 0;
}
/**
* sclr_disp_set_mem - setup disp's mem settings. Only work if disp from mem.
*
* @param mem: mem settings for disp
*/
void sclr_disp_set_mem(struct sclr_mem *mem)
{
bool is_enable = sclr_disp_reg_shadow_mask(false);
_reg_write(reg_base + REG_SCL_DISP_OFFSET,
(mem->start_y << 16) | mem->start_x);
_reg_write(reg_base + REG_SCL_DISP_SIZE,
((mem->height - 1) << 16) | (mem->width - 1));
_reg_write_mask(reg_base + REG_SCL_DISP_PITCH_Y, 0x00ffffff,
mem->pitch_y);
_reg_write(reg_base + REG_SCL_DISP_PITCH_C, mem->pitch_c);
sclr_disp_set_addr(mem->addr0, mem->addr1, mem->addr2);
if (is_enable)
sclr_disp_reg_shadow_mask(true);
g_disp_cfg.mem = *mem;
}
/**
* sclr_disp_set_addr - setup disp's mem address. Only work if disp from mem.
*
* @param addr0: address of planar0
* @param addr1: address of planar1
* @param addr2: address of planar2
*/
void sclr_disp_set_addr(u64 addr0, u64 addr1, u64 addr2)
{
_reg_write(reg_base + REG_SCL_DISP_ADDR0_L, addr0);
_reg_write(reg_base + REG_SCL_DISP_ADDR0_H, addr0 >> 32);
_reg_write(reg_base + REG_SCL_DISP_ADDR1_L, addr1);
_reg_write(reg_base + REG_SCL_DISP_ADDR1_H, addr1 >> 32);
_reg_write(reg_base + REG_SCL_DISP_ADDR2_L, addr2);
_reg_write(reg_base + REG_SCL_DISP_ADDR2_H, addr2 >> 32);
g_disp_cfg.mem.addr0 = addr0;
g_disp_cfg.mem.addr1 = addr1;
g_disp_cfg.mem.addr2 = addr2;
}
/**
* sclr_disp_set_csc - configure disp's input CSC's coefficient/offset
*
* @param cfg: The settings for CSC
*/
void sclr_disp_set_csc(struct sclr_csc_matrix *cfg)
{
_reg_write(reg_base + REG_SCL_DISP_IN_CSC0, BIT(31) |
(cfg->coef[0][1] << 16) | (cfg->coef[0][0]));
_reg_write(reg_base + REG_SCL_DISP_IN_CSC1,
(cfg->coef[1][0] << 16) | (cfg->coef[0][2]));
_reg_write(reg_base + REG_SCL_DISP_IN_CSC2,
(cfg->coef[1][2] << 16) | (cfg->coef[1][1]));
_reg_write(reg_base + REG_SCL_DISP_IN_CSC3,
(cfg->coef[2][1] << 16) | (cfg->coef[2][0]));
_reg_write(reg_base + REG_SCL_DISP_IN_CSC4, (cfg->coef[2][2]));
_reg_write(reg_base + REG_SCL_DISP_IN_CSC_SUB,
(cfg->sub[2] << 16) | (cfg->sub[1] << 8) |
cfg->sub[0]);
_reg_write(reg_base + REG_SCL_DISP_IN_CSC_ADD,
(cfg->add[2] << 16) | (cfg->add[1] << 8) |
cfg->add[0]);
}
/**
* sclr_disp_set_in_csc - setup disp's csc on input. Only work if disp from mem.
*
* @param csc: csc settings
*/
void sclr_disp_set_in_csc(enum sclr_csc csc)
{
if (csc == SCL_CSC_NONE)
_reg_write(reg_base + REG_SCL_DISP_IN_CSC0, 0);
else if (csc < SCL_CSC_MAX)
sclr_disp_set_csc(&csc_mtrx[csc]);
g_disp_cfg.in_csc = csc;
}
/**
* sclr_disp_set_out_csc - setup disp's csc on output.
*
* @param csc: csc settings
*/
void sclr_disp_set_out_csc(enum sclr_csc csc)
{
if (csc == SCL_CSC_NONE) {
_reg_write(reg_base + REG_SCL_DISP_OUT_CSC0, 0);
} else if (csc < SCL_CSC_MAX) {
struct sclr_csc_matrix *cfg = &csc_mtrx[csc];
_reg_write(reg_base + REG_SCL_DISP_OUT_CSC0, BIT(31) |
(cfg->coef[0][1] << 16) | (cfg->coef[0][0]));
_reg_write(reg_base + REG_SCL_DISP_OUT_CSC1,
(cfg->coef[1][0] << 16) | (cfg->coef[0][2]));
_reg_write(reg_base + REG_SCL_DISP_OUT_CSC2,
(cfg->coef[1][2] << 16) | (cfg->coef[1][1]));
_reg_write(reg_base + REG_SCL_DISP_OUT_CSC3,
(cfg->coef[2][1] << 16) | (cfg->coef[2][0]));
_reg_write(reg_base + REG_SCL_DISP_OUT_CSC4, (cfg->coef[2][2]));
_reg_write(reg_base + REG_SCL_DISP_OUT_CSC_SUB,
(cfg->sub[2] << 16) | (cfg->sub[1] << 8) |
cfg->sub[0]);
_reg_write(reg_base + REG_SCL_DISP_OUT_CSC_ADD,
(cfg->add[2] << 16) | (cfg->add[1] << 8) |
cfg->add[0]);
}
g_disp_cfg.out_csc = csc;
}
/**
* sclr_disp_set_pattern - setup disp's pattern generator.
*
* @param type: type of pattern
* @param color: color of pattern. Only for Gradient/FULL type.
*/
void sclr_disp_set_pattern(enum sclr_disp_pat_type type,
enum sclr_disp_pat_color color, const u16 *rgb)
{
switch (type) {
case SCL_PAT_TYPE_OFF:
_reg_write_mask(reg_base + REG_SCL_DISP_PAT_CFG, 0x16, 0);
break;
case SCL_PAT_TYPE_SNOW:
_reg_write_mask(reg_base + REG_SCL_DISP_PAT_CFG, 0x16, 0x10);
break;
case SCL_PAT_TYPE_AUTO:
_reg_write(reg_base + REG_SCL_DISP_PAT_COLOR0, 0x03ff03ff);
_reg_write_mask(reg_base + REG_SCL_DISP_PAT_COLOR1, 0x000003ff, 0x3ff);
_reg_write_mask(reg_base + REG_SCL_DISP_PAT_CFG, 0xff0016,
0x780006);
break;
case SCL_PAT_TYPE_V_GRAD:
case SCL_PAT_TYPE_H_GRAD:
case SCL_PAT_TYPE_FULL: {
if (color == SCL_PAT_COLOR_USR) {
_reg_write(reg_base + REG_SCL_DISP_PAT_COLOR0, rgb[1] << 16 | rgb[0]);
_reg_write_mask(reg_base + REG_SCL_DISP_PAT_COLOR1, 0x000003ff, rgb[2]);
_reg_write_mask(reg_base + REG_SCL_DISP_PAT_CFG, 0x1f000016,
(type << 27) | (SCL_PAT_COLOR_WHITE << 24) | 0x0002);
} else {
_reg_write(reg_base + REG_SCL_DISP_PAT_COLOR0, 0x03ff03ff);
_reg_write_mask(reg_base + REG_SCL_DISP_PAT_COLOR1, 0x000003ff, 0x3ff);
_reg_write_mask(reg_base + REG_SCL_DISP_PAT_CFG, 0x1f000016,
(type << 27) | (color << 24) | 0x0002);
}
break;
}
default:
printf("%s - unacceptiable pattern-type(%d)\n", __func__, type);
break;
}
}
/**
* sclr_disp_set_frame_bgcolro - setup disp frame(area outside mde)'s
* background color.
*
* @param r: 10bit red value
* @param g: 10bit green value
* @param b: 10bit blue value
*/
void sclr_disp_set_frame_bgcolor(u16 r, u16 g, u16 b)
{
_reg_write_mask(reg_base + REG_SCL_DISP_PAT_COLOR1, 0x0fff0000,
r << 16);
_reg_write(reg_base + REG_SCL_DISP_PAT_COLOR2, b << 16 | g);
}
/**
* sclr_disp_set_window_bgcolro - setup disp window's background color.
*
* @param r: 10bit red value
* @param g: 10bit green value
* @param b: 10bit blue value
*/
void sclr_disp_set_window_bgcolor(u16 r, u16 g, u16 b)
{
_reg_write(reg_base + REG_SCL_DISP_PAT_COLOR3, g << 16 | r);
_reg_write_mask(reg_base + REG_SCL_DISP_PAT_COLOR4, 0x0fff, b);
}
/**
* sclr_disp_enable_window_bgcolor - Use window bg-color to hide everything
* including test-pattern.
*
* @param enable: enable window bgcolor or not.
*/
void sclr_disp_enable_window_bgcolor(bool enable)
{
_reg_write_mask(reg_base + REG_SCL_DISP_PAT_CFG, 0x20, enable ? 0x20 : 0);
}
union sclr_disp_dbg_status sclr_disp_get_dbg_status(bool clr)
{
union sclr_disp_dbg_status status;
status.raw = _reg_read(reg_base + REG_SCL_DISP_DBG);
if (clr) {
status.b.err_fwr_clr = 1;
status.b.err_erd_clr = 1;
status.b.bw_fail_clr = 1;
_reg_write(reg_base + REG_SCL_DISP_DBG, status.raw);
}
return status;
}
void sclr_disp_gamma_ctrl(bool enable, bool pre_osd)
{
u32 value = 0;
if (enable)
value |= 0x04;
if (pre_osd)
value |= 0x08;
_reg_write_mask(reg_base + REG_SCL_DISP_GAMMA_CTRL, 0x0C, value);
}
void sclr_disp_gamma_lut_update(const u8 *b, const u8 *g, const u8 *r)
{
u8 i;
u32 value;
_reg_write_mask(reg_base + REG_SCL_DISP_GAMMA_CTRL, 0x03, 0x03);
for (i = 0; i < 65; ++i) {
value = *(b + i) | (*(g + i) << 8) | (*(r + i) << 16)
| (i << 24) | 0x80000000;
_reg_write(reg_base + REG_SCL_DISP_GAMMA_WR_LUT, value);
}
_reg_write_mask(reg_base + REG_SCL_DISP_GAMMA_CTRL, 0x03, 0x00);
}
void sclr_lvdstx_set(union sclr_lvdstx cfg)
{
_reg_write(reg_base + REG_SCL_TOP_LVDSTX, cfg.raw);
}
void sclr_lvdstx_get(union sclr_lvdstx *cfg)
{
cfg->raw = _reg_read(reg_base + REG_SCL_TOP_LVDSTX);
}
void sclr_bt_set(union sclr_bt_enc enc, union sclr_bt_sync_code sync)
{
_reg_write(reg_base + REG_SCL_TOP_BT_ENC, enc.raw);
_reg_write(reg_base + REG_SCL_TOP_BT_SYNC_CODE, sync.raw);
}
void sclr_bt_get(union sclr_bt_enc *enc, union sclr_bt_sync_code *sync)
{
enc->raw = _reg_read(reg_base + REG_SCL_TOP_BT_ENC);
sync->raw = _reg_read(reg_base + REG_SCL_TOP_BT_SYNC_CODE);
}
void sclr_disp_mux_sel(enum sclr_vo_sel sel)
{
_reg_write_mask(reg_base + REG_SCL_TOP_VO_MUX, 0x07, sel);
}
void sclr_disp_set_intf(enum sclr_vo_intf intf)
{
bool data_en[5] = {true, true, true, true};
if (intf == SCLR_VO_INTF_DISABLE)
_reg_write_mask(0x03002840, 0xa, 0);
else
_reg_write_mask(0x03002840, 0xa, 0xa);
dphy_init(intf);
if (intf == SCLR_VO_INTF_DISABLE) {
sclr_disp_mux_sel(SCLR_VO_SEL_DISABLE);
} else if ((intf == SCLR_VO_INTF_BT601) || (intf == SCLR_VO_INTF_BT656) || (intf == SCLR_VO_INTF_BT1120)) {
if (intf == SCLR_VO_INTF_BT601)
sclr_disp_mux_sel(SCLR_VO_SEL_BT601);
else if (intf == SCLR_VO_INTF_BT656)
sclr_disp_mux_sel(SCLR_VO_SEL_BT656);
else if (intf == SCLR_VO_INTF_BT1120)
sclr_disp_mux_sel(SCLR_VO_SEL_BT1120);
dphy_dsi_lane_en(true, data_en, false);
} else if (intf == SCLR_VO_INTF_I80) {
sclr_disp_mux_sel(SCLR_VO_SEL_I80);
dphy_dsi_lane_en(true, data_en, false);
_reg_write_mask(reg_base + REG_SCL_DISP_MCU_IF_CTRL, BIT(0), 1);
} else if (intf == SCLR_VO_INTF_SW) {
sclr_disp_mux_sel(SCLR_VO_SEL_SW);
} else if (intf == SCLR_VO_INTF_MIPI) {
sclr_disp_mux_sel(SCLR_VO_SEL_DISABLE);
} else if (intf == SCLR_VO_INTF_LVDS) {
sclr_disp_mux_sel(SCLR_VO_SEL_DISABLE);
}
}
/**
* sclr_dsi_get_mode - get current dsi mode
*
* @return: current dsi mode
*/
enum sclr_dsi_mode sclr_dsi_get_mode(void)
{
return (_reg_read(reg_base + REG_SCL_DSI_MAC_EN) & 0x0f);
}
/**
* sclr_dsi_clr_mode - let dsi back to idle mode
*
*/
void sclr_dsi_clr_mode(void)
{
u32 mode = _reg_read(reg_base + REG_SCL_DSI_MAC_EN);
if (mode != SCLR_DSI_MODE_IDLE)
_reg_write(reg_base + REG_SCL_DSI_MAC_EN, mode);
}
/**
* sclr_dsi_set_mode - set dsi mode
*
* @param mode: new dsi mode except for idle
* @return: 0 if success
*/
int sclr_dsi_set_mode(enum sclr_dsi_mode mode)
{
if (mode >= SCLR_DSI_MODE_MAX)
return -1;
if (mode == SCLR_DSI_MODE_IDLE) {
sclr_dsi_clr_mode();
return 0;
}
if (_reg_read(reg_base + REG_SCL_DSI_MAC_EN))
return -1;
_reg_write(reg_base + REG_SCL_DSI_MAC_EN, mode);
return 0;
}
/**
* sclr_dsi_chk_mode_done - check if dsi's work done.
*
* @param mode: the mode to check.
* @return: 0 if success
*/
int sclr_dsi_chk_mode_done(enum sclr_dsi_mode mode)
{
u32 val = 0;
if ((mode == SCLR_DSI_MODE_ESC) || (mode == SCLR_DSI_MODE_SPKT)) {
val = _reg_read(reg_base + REG_SCL_DSI_MAC_EN) & 0xf0;
return (val ^ (mode << 4)) ? -1 : 0;
}
if ((mode == SCLR_DSI_MODE_IDLE) || (mode == SCLR_DSI_MODE_HS)) {
val = _reg_read(reg_base + REG_SCL_DSI_MAC_EN) & 0x0f;
return (val == (mode)) ? 0 : -1;
}
return -1;
}
int _dsi_chk_and_clean_mode(enum sclr_dsi_mode mode)
{
int i, ret;
for (i = 0; i < 5; ++i) {
udelay(20);
ret = sclr_dsi_chk_mode_done(mode);
if (ret == 0) {
sclr_dsi_clr_mode();
break;
}
}
return ret;
}
#define POLY 0x8408
/*
* 16 12 5
* this is the CCITT CRC 16 polynomial X + X + X + 1.
* This works out to be 0x1021, but the way the algorithm works
* lets us use 0x8408 (the reverse of the bit pattern). The high
* bit is always assumed to be set, thus we only use 16 bits to
* represent the 17 bit value.
*/
static u16 crc16(unsigned char *data_p, unsigned short length)
{
u8 i, data;
u16 crc = 0xffff;
if (length == 0)
return (~crc);
do {
for (i = 0, data = 0xff & *data_p++; i < 8; i++, data >>= 1) {
if ((crc & 0x0001) ^ (data & 0x0001))
crc = (crc >> 1) ^ POLY;
else
crc >>= 1;
}
} while (--length);
return crc;
}
static unsigned char ecc(unsigned char *data)
{
char D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12;
char D13, D14, D15, D16, D17, D18, D19, D20, D21, D22, D23;
char P0, P1, P2, P3, P4, P5, P6, P7;
D0 = data[0] & 0x01;
D1 = (data[0] >> 1) & 0x01;
D2 = (data[0] >> 2) & 0x01;
D3 = (data[0] >> 3) & 0x01;
D4 = (data[0] >> 4) & 0x01;
D5 = (data[0] >> 5) & 0x01;
D6 = (data[0] >> 6) & 0x01;
D7 = (data[0] >> 7) & 0x01;
D8 = data[1] & 0x01;
D9 = (data[1] >> 1) & 0x01;
D10 = (data[1] >> 2) & 0x01;
D11 = (data[1] >> 3) & 0x01;
D12 = (data[1] >> 4) & 0x01;
D13 = (data[1] >> 5) & 0x01;
D14 = (data[1] >> 6) & 0x01;
D15 = (data[1] >> 7) & 0x01;
D16 = data[2] & 0x01;
D17 = (data[2] >> 1) & 0x01;
D18 = (data[2] >> 2) & 0x01;
D19 = (data[2] >> 3) & 0x01;
D20 = (data[2] >> 4) & 0x01;
D21 = (data[2] >> 5) & 0x01;
D22 = (data[2] >> 6) & 0x01;
D23 = (data[2] >> 7) & 0x01;
P7 = 0;
P6 = 0;
P5 = (D10 ^ D11 ^ D12 ^ D13 ^ D14 ^ D15 ^ D16 ^ D17 ^ D18 ^ D19 ^ D21 ^ D22 ^ D23) & 0x01;
P4 = (D4 ^ D5 ^ D6 ^ D7 ^ D8 ^ D9 ^ D16 ^ D17 ^ D18 ^ D19 ^ D20 ^ D22 ^ D23) & 0x01;
P3 = (D1 ^ D2 ^ D3 ^ D7 ^ D8 ^ D9 ^ D13 ^ D14 ^ D15 ^ D19 ^ D20 ^ D21 ^ D23) & 0x01;
P2 = (D0 ^ D2 ^ D3 ^ D5 ^ D6 ^ D9 ^ D11 ^ D12 ^ D15 ^ D18 ^ D20 ^ D21 ^ D22) & 0x01;
P1 = (D0 ^ D1 ^ D3 ^ D4 ^ D6 ^ D8 ^ D10 ^ D12 ^ D14 ^ D17 ^ D20 ^ D21 ^ D22 ^ D23) & 0x01;
P0 = (D0 ^ D1 ^ D2 ^ D4 ^ D5 ^ D7 ^ D10 ^ D11 ^ D13 ^ D16 ^ D20 ^ D21 ^ D22 ^ D23) & 0x01;
return (P7 << 7) | (P6 << 6) | (P5 << 5) | (P4 << 4) |
(P3 << 3) | (P2 << 2) | (P1 << 1) | P0;
}
/**
* sclr_dsi_long_packet_raw - send dsi long packet by escapet-lpdt.
*
* @param data: long packet data including header and crc.
* @param count: number of long packet data, 16 at most.
* @return: 0 if success
*/
int sclr_dsi_long_packet_raw(const u8 *data, u8 count)
{
u64 addr = reg_base + REG_SCL_DSI_ESC_TX0;
u32 val = 0;
u8 i = 0;
if ((count > SCL_MAX_DSI_LP) || (count == 0)) {
printf("%s: count(%d) invalid\n", __func__, count);
return -1;
}
val = 0x01 | ((count - 1) << 8);
_reg_write(reg_base + REG_SCL_DSI_ESC, val);
for (i = 0; i < count; i += 4) {
if (count - i < 4) {
val = 0;
memcpy(&val, &data[i], count - i);
_reg_write(addr + i, val);
break;
}
memcpy(&val, &data[i], 4);
_reg_write(addr + i, val);
}
sclr_dsi_set_mode(SCLR_DSI_MODE_ESC);
return _dsi_chk_and_clean_mode(SCLR_DSI_MODE_ESC);
}
/**
* sclr_dsi_long_packet - send dsi long packet by escapet-lpdt.
*
* @param di: data ID
* @param data: long packet data
* @param count: number of long packet data, 100 at most.
* @param sw_mode: use sw-overwrite to create dcs cmd
* @return: 0 if success
*/
int sclr_dsi_long_packet(u8 di, const u8 *data, u8 count, bool sw_mode)
{
u8 packet[100] = {di, count, 0, 0};
u16 crc;
packet[3] = ecc(packet);
memcpy(&packet[4], data, count);
count += 4;
crc = crc16(packet, count);
packet[count++] = crc & 0xff;
packet[count++] = crc >> 8;
if (!sw_mode && count < SCL_MAX_DSI_LP)
return sclr_dsi_long_packet_raw(packet, count);
dpyh_mipi_tx_manual_packet(packet, count);
return 0;
}
/**
* sclr_dsi_short_packet - send dsi short packet by escapet-lpdt.
* *NOTE*: ecc is hw-generated.
*
* @param di: data ID
* @param data: short packet data
* @param count: number of short packet data, 1 or 2.
* @param sw_mode: use sw-overwrite to create dcs cmd
* @return: 0 if success
*/
int sclr_dsi_short_packet(u8 di, const u8 *data, u8 count, bool sw_mode)
{
u32 val = 0;
if ((count > SCL_MAX_DSI_SP) || (count == 0))
return -1;
val = di;
if (count == 2) {
//val = 0x15;
val |= (data[0] << 8) | (data[1] << 16);
} else {
//val = 0x05;
val |= data[0] << 8;
}
if (!sw_mode) {
_reg_write_mask(reg_base + REG_SCL_DSI_HS_0, 0x00ffffff, val);
sclr_dsi_set_mode(SCLR_DSI_MODE_SPKT);
return _dsi_chk_and_clean_mode(SCLR_DSI_MODE_SPKT);
}
val |= (ecc((u8 *)&val) << 24);
dpyh_mipi_tx_manual_packet((u8 *)&val, 4);
return 0;
}
/**
* sclr_dsi_dcs_write_buffer - send dsi packet by escapet-lpdt.
*
* @param di: data ID
* @param data: packet data
* @param count: number of packet data
* @param sw_mode: use sw-overwrite to create dcs cmd
* @return: Zero on success or a negative error code on failure.
*/
int sclr_dsi_dcs_write_buffer(u8 di, const void *data, size_t len, bool sw_mode)
{
if (len == 0) {
printf("[cvi_mipi_tx] %s: 0 param unacceptable.\n", __func__);
return -1;
}
if ((di == 0x06) || (di == 0x05) || (di == 0x04) || (di == 0x03)) {
if (len != 1) {
printf("[cvi_mipi_tx] %s: cmd(0x%02x) should has 1 param.\n", __func__, di);
return -1;
}
return sclr_dsi_short_packet(di, data, len, sw_mode);
}
if ((di == 0x15) || (di == 0x37) || (di == 0x13) || (di == 0x14)) {
if (len != 2) {
printf("[cvi_mipi_tx] %s: cmd(0x%02x) should has 2 param.\n", __func__, di);
return -1;
}
return sclr_dsi_short_packet(di, data, len, sw_mode);
}
if ((di == 0x29) || (di == 0x39))
return sclr_dsi_long_packet(di, data, len, sw_mode);
return sclr_dsi_long_packet(di, data, len, sw_mode);
}
#define ACK_WR 0x02
#define GEN_READ_LP 0x1A
#define GEN_READ_SP1 0x11
#define GEN_READ_SP2 0x12
#define DCS_READ_LP 0x1C
#define DCS_READ_SP1 0x21
#define DCS_READ_SP2 0x22
int sclr_dsi_dcs_read_buffer(u8 di, const u16 data_param, u8 *data, size_t len, bool sw_mode)
{
int ret = 0;
u32 rx_data;
int i = 0;
if (len > 4)
len = 4;
if (sclr_dsi_get_mode() == SCLR_DSI_MODE_HS) {
printf("[cvi_mipi_tx] %s: not work in HS.\n", __func__);
return -1;
}
// only set necessery bits
_reg_write_mask(reg_base + REG_SCL_DSI_ESC, 0x07, 0x04);
// send read cmd
sclr_dsi_short_packet(di, (u8 *)&data_param, 2, sw_mode);
// goto BTA
sclr_dsi_set_mode(SCLR_DSI_MODE_ESC);
udelay(20);
ret = sclr_dsi_chk_mode_done(SCLR_DSI_MODE_ESC);
if (ret == 0) {
sclr_dsi_clr_mode();
} else {
printf("[cvi_mipi_tx] %s: BTA error.\n", __func__);
return ret;
}
// check result
rx_data = _reg_read(reg_base + REG_SCL_DSI_ESC_RX0);
switch (rx_data & 0xff) {
case GEN_READ_SP1:
case DCS_READ_SP1:
data[0] = (rx_data >> 8) & 0xff;
break;
case GEN_READ_SP2:
case DCS_READ_SP2:
data[0] = (rx_data >> 8) & 0xff;
data[1] = (rx_data >> 16) & 0xff;
break;
case GEN_READ_LP:
case DCS_READ_LP:
rx_data = _reg_read(reg_base + REG_SCL_DSI_ESC_RX1);
for (i = 0; i < len; ++i)
data[i] = (rx_data >> (i * 8)) & 0xff;
break;
case ACK_WR:
printf("[cvi_mipi_tx] %s: dcs read, ack with error(%#x %#x).\n"
, __func__, (rx_data >> 8) & 0xff, (rx_data >> 16) & 0xff);
ret = -1;
break;
default:
printf("[cvi_mipi_tx] %s: unknown DT, %#x.", __func__, rx_data);
ret = -1;
break;
}
//debug("%s: %#x %#x\n", __func__, rx_data0, rx_data1);
return ret;
}
int sclr_dsi_config(u8 lane_num, enum sclr_dsi_fmt fmt, u16 width)
{
u32 val = 0;
u8 bit_depth[] = {24, 18, 16, 30};
if ((lane_num != 1) && (lane_num != 2) && (lane_num != 4))
return -EINVAL;
if (fmt > SCLR_DSI_FMT_MAX)
return -EINVAL;
lane_num >>= 1;
val = (fmt << 30) | (lane_num << 24);
_reg_write_mask(reg_base + REG_SCL_DSI_HS_0, 0xc3000000, val);
val = (width / 10) << 16 | ((width * bit_depth[fmt] + 7) >> 3);
_reg_write(reg_base + REG_SCL_DSI_HS_1, val);
return 0;
}
void sclr_i80_sw_mode(bool enable)
{
_reg_write_mask(reg_base + REG_SCL_DISP_MCU_IF_CTRL, BIT(11) | BIT(1), enable ? 0x802 : 0x000);
if (enable) {
sclr_disp_tgen_enable(true);
mdelay(40);
sclr_disp_tgen_enable(false);
}
}
void sclr_i80_packet(u32 cmd)
{
u8 cnt = 0;
_reg_write(reg_base + REG_SCL_DISP_MCU_SW_CTRL, cmd);
_reg_write_mask(reg_base + REG_SCL_DISP_MCU_SW_CTRL, BIT(31), BIT(31));
do {
udelay(1);
if (_reg_read(reg_base + REG_SCL_DISP_MCU_SW_CTRL) & BIT(24))
break;
} while (++cnt < 10);
if (cnt == 10)
printf("[cvi_vip] %s: cmd(%#x) not ready.\n", __func__, cmd);
}
void sclr_i80_run(void)
{
u8 cnt = 0;
_reg_write_mask(reg_base + REG_SCL_DISP_MCU_IF_CTRL, BIT(11), BIT(11));
do {
udelay(5 * 1000);
if (_reg_read(reg_base + REG_SCL_DISP_MCU_STATUS) == 0x08)
break;
} while (++cnt < 10);
if (cnt == 10) {
printf("[cvi_vip] %s: not finish. sw clear it.\n", __func__);
_reg_write_mask(reg_base + REG_SCL_DISP_MCU_IF_CTRL, BIT(10), BIT(10));
}
}
/****************************************************************************
* SCALER CTRL
****************************************************************************/
/**
* sclr_ctrl_init - setup all sc instances.
*
*/
void sclr_ctrl_init(void)
{
union sclr_intr intr_mask;
bool disp_from_sc = false;
// init variables
memset(&g_top_cfg, 0, sizeof(g_top_cfg));
memset(&g_disp_cfg, 0, sizeof(g_disp_cfg));
memset(&disp_timing, 0, sizeof(disp_timing));
g_top_cfg.ip_trig_src = true;
g_top_cfg.sclr_enable[0] = false;
g_top_cfg.sclr_enable[1] = false;
g_top_cfg.sclr_enable[2] = false;
g_top_cfg.sclr_enable[3] = false;
g_top_cfg.disp_enable = false;
g_top_cfg.disp_from_sc = disp_from_sc;
g_top_cfg.img_in_d_trig_src = SCL_IMG_TRIG_SRC_SW;
g_top_cfg.img_in_v_trig_src = SCL_IMG_TRIG_SRC_SW;
g_disp_cfg.disp_from_sc = disp_from_sc;
g_disp_cfg.cache_mode = true;
g_disp_cfg.sync_ext = false;
g_disp_cfg.tgen_en = false;
g_disp_cfg.fmt = SCL_FMT_RGB_PLANAR;
g_disp_cfg.in_csc = SCL_CSC_NONE;
g_disp_cfg.out_csc = SCL_CSC_NONE;
g_disp_cfg.burst = 7;
g_disp_cfg.out_bit = 8;
g_disp_cfg.drop_mode = SCL_DISP_DROP_MODE_DITHER;
// init hw
sclr_top_set_cfg(&g_top_cfg);
sclr_disp_reg_shadow_sel(false);
sclr_disp_tgen_enable(false);
sclr_disp_set_cfg(&g_disp_cfg);
intr_mask.b.img_in_d_frame_end = true;
intr_mask.b.img_in_v_frame_end = true;
intr_mask.b.scl0_frame_end = true;
intr_mask.b.scl1_frame_end = true;
intr_mask.b.scl2_frame_end = true;
intr_mask.b.scl3_frame_end = true;
intr_mask.b.prog_too_late = true;
intr_mask.b.cmdq = true;
intr_mask.b.disp_frame_end = true;
sclr_set_intr_mask(intr_mask);
sclr_top_reg_done();
sclr_top_reg_force_up();
sclr_top_pg_late_clr();
}
/**
* sclr_ctrl_set_disp_src - setup input-src of disp.
*
* @param disp_from_sc: true(from sc_0); false(from mem)
* @return: 0 if success
*/
int sclr_ctrl_set_disp_src(bool disp_from_sc)
{
g_top_cfg.disp_from_sc = disp_from_sc;
g_disp_cfg.disp_from_sc = disp_from_sc;
sclr_top_set_cfg(&g_top_cfg);
sclr_disp_set_cfg(&g_disp_cfg);
return 0;
}
int set_disp_ctrl_gpios(struct disp_ctrl_gpios *ctrl_gpios)
{
g_disp_cfg.ctrl_gpios = *ctrl_gpios;
return 0;
}
int get_disp_ctrl_gpios(struct disp_ctrl_gpios *ctrl_gpios)
{
*ctrl_gpios = g_disp_cfg.ctrl_gpios;
return 0;
}