blob: 3aea0f0f8a6eab479573730a6e9a931809045629 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <common.h>
#include <malloc.h>
#include <fdtdec.h>
#include <dm.h>
#include <asm/arch/cpu.h>
#include <amlogic/cpu_id.h>
#include <amlogic/media/vout/aml_vout.h>
#include <amlogic/media/vout/aml_cvbs.h>
#include "cvbs_reg.h"
#include "cvbs_config.h"
#include "cvbs.h"
#include "vdac.h"
/*----------------------------------------------------------------------------*/
static struct cvbs_drv_s cvbs_drv = {
.data = NULL,
};
static struct cvbs_data_s cvbs_data_g12a = {
.chip_type = CVBS_CHIP_G12A,
.reg_vid_pll_clk_div = HHI_VID_PLL_CLK_DIV,
.reg_vid_clk_div = HHI_VID_CLK_DIV,
.reg_vid_clk_ctrl = HHI_VID_CLK_CNTL,
.reg_vid2_clk_div = HHI_VIID_CLK_DIV,
.reg_vid2_clk_ctrl = HHI_VIID_CLK_CNTL,
.reg_vid_clk_ctrl2 = HHI_VID_CLK_CNTL2,
.vdac_vref_adj = 0x10,
.vdac_gsw = 0x0,
};
static struct cvbs_data_s cvbs_data_g12b = {
.chip_type = CVBS_CHIP_G12B,
.reg_vid_pll_clk_div = HHI_VID_PLL_CLK_DIV,
.reg_vid_clk_div = HHI_VID_CLK_DIV,
.reg_vid_clk_ctrl = HHI_VID_CLK_CNTL,
.reg_vid2_clk_div = HHI_VIID_CLK_DIV,
.reg_vid2_clk_ctrl = HHI_VIID_CLK_CNTL,
.reg_vid_clk_ctrl2 = HHI_VID_CLK_CNTL2,
.vdac_vref_adj = 0xf,
.vdac_gsw = 0x0,
};
static struct cvbs_data_s cvbs_data_sc2 = {
.chip_type = CVBS_CHIP_SC2,
.reg_vid_pll_clk_div = CLKCTRL_VID_PLL_CLK_DIV,
.reg_vid_clk_div = CLKCTRL_VID_CLK_DIV,
.reg_vid_clk_ctrl = CLKCTRL_VID_CLK_CTRL,
.reg_vid2_clk_div = CLKCTRL_VIID_CLK_DIV,
.reg_vid2_clk_ctrl = CLKCTRL_VIID_CLK_CTRL,
.reg_vid_clk_ctrl2 = CLKCTRL_VID_CLK_CTRL2,
.vdac_vref_adj = 0x10,
.vdac_gsw = 0x0,
};
static struct cvbs_data_s cvbs_data_s4 = {
.chip_type = CVBS_CHIP_S4,
.reg_vid_pll_clk_div = CLKCTRL_VID_PLL_CLK_DIV,
.reg_vid_clk_div = CLKCTRL_VID_CLK_DIV,
.reg_vid_clk_ctrl = CLKCTRL_VID_CLK_CTRL,
.reg_vid2_clk_div = CLKCTRL_VIID_CLK_DIV,
.reg_vid2_clk_ctrl = CLKCTRL_VIID_CLK_CTRL,
.reg_vid_clk_ctrl2 = CLKCTRL_VID_CLK_CTRL2,
.vdac_vref_adj = 0x10,
.vdac_gsw = 0x0,
};
unsigned int cvbs_mode = VMODE_MAX;
/*bit[0]: 0=vid_pll, 1=gp0_pll*/
/*bit[1]: 0=vid2_clk, 1=vid1_clk*/
/*path 0:vid_pll vid2_clk*/
/*path 1:gp0_pll vid2_clk*/
/*path 2:vid_pll vid1_clk*/
/*path 3:gp0_pll vid1_clk*/
static unsigned int s_enci_clk_path = 0;
/*----------------------------------------------------------------------------*/
// configuration for enci bist
int cvbs_set_bist(char* bist_mode)
{
if (!strcmp(bist_mode, "off")) {
cvbs_write_vcbus(ENCI_VIDEO_MODE_ADV, 0x26);
cvbs_write_vcbus(ENCI_TST_EN, 0x0);
} else {
unsigned int mode = 0;
if (!strcmp(bist_mode, "fixval") || !strcmp(bist_mode, "0"))
mode = 0;
else if (!strcmp(bist_mode, "colorbar") || !strcmp(bist_mode, "1"))
mode = 1;
else if (!strcmp(bist_mode, "thinline") || !strcmp(bist_mode, "2"))
mode = 2;
else if (!strcmp(bist_mode, "dotgrid") || !strcmp(bist_mode, "3"))
mode = 3;
cvbs_write_vcbus(ENCI_VIDEO_MODE_ADV, 0x2);
cvbs_write_vcbus(ENCI_TST_MDSEL, mode);
cvbs_write_vcbus(ENCI_TST_CLRBAR_STRT, 0x112);
cvbs_write_vcbus(ENCI_TST_CLRBAR_WIDTH, 0xb4);
cvbs_write_vcbus(ENCI_TST_EN, 0x1);
}
return 0;
}
/*----------------------------------------------------------------------------*/
int cvbs_set_vdac(int status)
{
switch (status) {
case 0:// close vdac
if (cvbs_drv.data)
vdac_enable(0, VDAC_MODULE_CVBS_OUT);
else
printf("cvbs ERROR:need run cvbs init.\n");
break;
case 1:// from enci to vdac
cvbs_set_vcbus_bits(VENC_VDAC_DACSEL0, 0, 5, 1);
if (cvbs_drv.data) {
vdac_ctrl_vref_adj(cvbs_drv.data->vdac_vref_adj);
vdac_enable(1, VDAC_MODULE_CVBS_OUT);
} else {
printf("cvbs ERROR:need run cvbs init.\n");
}
break;
default:
break;
}
return 0;
}
/*----------------------------------------------------------------------------*/
// interface for debug
static void cvbs_dump_cvbs_regs(void)
{
struct reg_s *p = NULL;
if (VMODE_PAL == cvbs_mode) {
// 576cvbs
p = (struct reg_s*)&tvregs_576cvbs_enc[0];
} else if (VMODE_NTSC == cvbs_mode) {
// 480cvbs
p = (struct reg_s*)&tvregs_480cvbs_enc[0];
}
if (NULL == p) {
printf("it's not in cvbs mode!\n");
return;
}
if (MREG_END_MARKER != p->reg)
printf("cvbs enci registers:\n");
while (MREG_END_MARKER != p->reg) {
printf(" vcbus[0x%.2x] = 0x%.4x\n", p->reg, cvbs_read_vcbus(p->reg));
p ++;
}
return;
}
unsigned int cvbs_clk_regs[] = {
HHI_HDMI_PLL_CNTL0,
HHI_HDMI_PLL_CNTL1,
HHI_HDMI_PLL_CNTL2,
HHI_HDMI_PLL_CNTL3,
HHI_HDMI_PLL_CNTL4,
HHI_HDMI_PLL_CNTL5,
HHI_HDMI_PLL_CNTL6,
HHI_VID_PLL_CLK_DIV,
HHI_VIID_CLK_DIV,
HHI_VIID_CLK_CNTL,
HHI_VID_CLK_DIV,
HHI_VID_CLK_CNTL2,
MREG_END_MARKER
};
static void cvbs_dump_clock_regs(void)
{
unsigned int *p = &cvbs_clk_regs[0];
if (MREG_END_MARKER != *p)
printf("cvbs clock registers:\n");
while (MREG_END_MARKER != *p) {
printf(" hiu[0x%.2x] = 0x%.4x\n", *p, cvbs_read_hiu(*p));
p ++;
}
return;
}
int cvbs_reg_debug(int argc, char* const argv[])
{
unsigned int value;
if (!cvbs_drv.data) {
printf("cvbs: error: %s: no cvbs data\n", __func__);
return -1;
}
if (!strcmp(argv[1], "clock")) {
if (argc != 2)
goto fail_cmd;
cvbs_dump_clock_regs();
} else if (!strcmp(argv[1], "enci")) {
if (argc != 2)
goto fail_cmd;
cvbs_dump_cvbs_regs();
} else if (!strcmp(argv[1], "clkpath")) {
if (argc != 3)
goto fail_cmd;
value = simple_strtoul(argv[2], NULL, 0);
if ((cvbs_drv.data->chip_type == CVBS_CHIP_G12A) ||
(cvbs_drv.data->chip_type == CVBS_CHIP_G12B)) {
if (value == 1 || value == 2 ||
value == 3 || value == 0) {
s_enci_clk_path = value;
printf("path 0:vid_pll vid2_clk\n");
printf("path 1:gp0_pll vid2_clk\n");
printf("path 2:vid_pll vid1_clk\n");
printf("path 3:gp0_pll vid1_clk\n");
printf("you select path %d\n", s_enci_clk_path);
} else {
printf("invalid value, only 0/1/2/3\n");
printf("bit[0]: 0=vid_pll, 1=gp0_pll\n");
printf("bit[1]: 0=vid2_clk, 1=vid1_clk\n");
}
} else {
printf("don't support for current chip\n");
}
}
return 0;
fail_cmd:
return 1;
}
/*----------------------------------------------------------------------------*/
// configuration for clock
#define WAIT_FOR_PLL_LOCKED(reg) \
do { \
unsigned int pll_lock; \
unsigned int time_out = 0; \
do { \
udelay(20); \
pll_lock = cvbs_get_hiu_bits(reg, 31, 1); \
time_out ++; \
} while ((pll_lock == 0) && (time_out < 10000)); \
if (pll_lock == 0) \
printf("[error]: cvbs pll lock failed\n"); \
} while(0);
static void cvbs_config_hdmipll_g12a(void)
{
printf("%s\n", __func__);
cvbs_write_hiu(HHI_HDMI_PLL_CNTL0, 0x1a0504f7);
cvbs_write_hiu(HHI_HDMI_PLL_CNTL1, 0x00010000);
cvbs_write_hiu(HHI_HDMI_PLL_CNTL2, 0x00000000);
cvbs_write_hiu(HHI_HDMI_PLL_CNTL3, 0x6a28dc00);
cvbs_write_hiu(HHI_HDMI_PLL_CNTL4, 0x65771290);
cvbs_write_hiu(HHI_HDMI_PLL_CNTL5, 0x39272000);
cvbs_write_hiu(HHI_HDMI_PLL_CNTL6, 0x56540000);
cvbs_write_hiu(HHI_HDMI_PLL_CNTL0, 0x3a0504f7);
udelay(100);
cvbs_write_hiu(HHI_HDMI_PLL_CNTL0, 0x1a0504f7);
WAIT_FOR_PLL_LOCKED(HHI_HDMI_PLL_CNTL0);
return;
}
static void cvbs_config_gp0pll_g12a(void)
{
printf("%s\n", __func__);
cvbs_write_hiu(HHI_GP0_PLL_CNTL0, 0x180204f7);
cvbs_write_hiu(HHI_GP0_PLL_CNTL1, 0x00010000);
cvbs_write_hiu(HHI_GP0_PLL_CNTL2, 0x00000000);
cvbs_write_hiu(HHI_GP0_PLL_CNTL3, 0x6a28dc00);
cvbs_write_hiu(HHI_GP0_PLL_CNTL4, 0x65771290);
cvbs_write_hiu(HHI_GP0_PLL_CNTL5, 0x39272000);
cvbs_write_hiu(HHI_GP0_PLL_CNTL6, 0x56540000);
cvbs_write_hiu(HHI_GP0_PLL_CNTL0, 0x380204f7);
udelay(100);
cvbs_write_hiu(HHI_GP0_PLL_CNTL0, 0x180204f7);
WAIT_FOR_PLL_LOCKED(HHI_GP0_PLL_CNTL0);
return;
}
static void cvbs_config_hdmipll_sc2(void)
{
printf("%s\n", __func__);
cvbs_write_hiu(ANACTRL_HDMIPLL_CTRL0, 0x3b01047b);
cvbs_write_hiu(ANACTRL_HDMIPLL_CTRL1, 0x00018000);
cvbs_write_hiu(ANACTRL_HDMIPLL_CTRL2, 0x00000000);
cvbs_write_hiu(ANACTRL_HDMIPLL_CTRL3, 0x0a691c00);
cvbs_write_hiu(ANACTRL_HDMIPLL_CTRL4, 0x33771290);
cvbs_write_hiu(ANACTRL_HDMIPLL_CTRL5, 0x39270000);
cvbs_write_hiu(ANACTRL_HDMIPLL_CTRL6, 0x50540000);
udelay(100);
cvbs_write_hiu(ANACTRL_HDMIPLL_CTRL0, 0x1b01047b);
WAIT_FOR_PLL_LOCKED(ANACTRL_HDMIPLL_CTRL0);
}
static void cvbs_set_vid1_clk(unsigned int src_pll)
{
int sel = 0;
if (!cvbs_drv.data) {
printf("cvbs: error: %s: no cvbs data\n", __func__);
return;
}
printf("%s\n", __func__);
if (src_pll == 0) { /* hpll */
/* divider: 1 */
/* Disable the div output clock */
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_pll_clk_div, 0, 19, 1);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_pll_clk_div, 0, 15, 1);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_pll_clk_div, 1, 18, 1);
/* Enable the final output clock */
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_pll_clk_div, 1, 19, 1);
sel = 0;
} else { /* gp0_pll */
sel = 1;
}
/* xd: 55 */
/* setup the XD divider value */
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_clk_div, (55 - 1), VCLK_XD0, 8);
//udelay(5);
/*0x59[16]/0x5f[19]/0x5f[20]*/
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_clk_ctrl, sel, VCLK_CLK_IN_SEL, 3);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_clk_ctrl, 1, VCLK_EN0, 1);
//udelay(2);
/* vclk: 27M */
/* [31:28]=0 enci_clk_sel, select vclk_div1 */
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_clk_div, 0, 28, 4);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid2_clk_div, 0, 28, 4);
/* release vclk_div_reset and enable vclk_div */
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_clk_div, 1, VCLK_XD_EN, 2);
//udelay(5);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_clk_ctrl, 1, VCLK_DIV1_EN, 1);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_clk_ctrl, 1, VCLK_SOFT_RST, 1);
//udelay(10);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_clk_ctrl, 0, VCLK_SOFT_RST, 1);
//udelay(5);
}
static void cvbs_set_vid2_clk(unsigned int src_pll)
{
int sel = 0;
if (!cvbs_drv.data) {
printf("cvbs: error: %s: no cvbs data\n", __func__);
return;
}
printf("%s\n", __func__);
if (src_pll == 0) { /* hpll */
/* divider: 1 */
/* Disable the div output clock */
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_pll_clk_div, 0, 19, 1);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_pll_clk_div, 0, 15, 1);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_pll_clk_div, 1, 18, 1);
/* Enable the final output clock */
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_pll_clk_div, 1, 19, 1);
sel = 0;
} else { /* gp0_pll */
sel = 1;
}
/* xd: 55 */
/* setup the XD divider value */
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid2_clk_div, (55 - 1), VCLK2_XD, 8);
//udelay(5);
/* Bit[18:16] - v2_cntl_clk_in_sel: vid_pll */
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid2_clk_ctrl, sel, VCLK2_CLK_IN_SEL, 3);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid2_clk_ctrl, 1, VCLK2_EN, 1);
//udelay(2);
/* vclk: 27M */
/* [31:28]=8 enci_clk_sel, select vclk2_div1 */
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_clk_div, 8, 28, 4);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid2_clk_div, 8, 28, 4);
/* release vclk2_div_reset and enable vclk2_div */
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid2_clk_div, 1, VCLK2_XD_EN, 2);
//udelay(5);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid2_clk_ctrl, 1, VCLK2_DIV1_EN, 1);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid2_clk_ctrl, 1, VCLK2_SOFT_RST, 1);
//udelay(10);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid2_clk_ctrl, 0, VCLK2_SOFT_RST, 1);
//udelay(5);
}
static int cvbs_config_clock(void)
{
if (!cvbs_drv.data) {
printf("cvbs: error: %s: no cvbs data\n", __func__);
return -1;
}
/* pll output 1485M */
switch (cvbs_drv.data->chip_type) {
case CVBS_CHIP_G12A:
case CVBS_CHIP_G12B:
if (s_enci_clk_path & 0x1)
cvbs_config_gp0pll_g12a();
else
cvbs_config_hdmipll_g12a();
if (s_enci_clk_path & 0x2)
cvbs_set_vid1_clk(s_enci_clk_path & 0x1);
else
cvbs_set_vid2_clk(s_enci_clk_path & 0x1);
break;
case CVBS_CHIP_SC2:
case CVBS_CHIP_S4:
cvbs_config_hdmipll_sc2();
cvbs_set_vid2_clk(0);
break;
default:
printf("cvbs: %s: invalid chip type\n", __func__);
return -1;
}
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_clk_ctrl2, 1, 0, 1);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_clk_ctrl2, 1, 4, 1);
return 0;
}
static void cvbs_disable_clock(void)
{
if (!cvbs_drv.data) {
printf("cvbs: error: %s: no cvbs data\n", __func__);
return;
}
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_clk_ctrl2, 0, 4, 1);
cvbs_set_hiu_bits(cvbs_drv.data->reg_vid_clk_ctrl2, 0, 0, 1);
}
/*----------------------------------------------------------------------------*/
// configuration for enci
static void cvbs_performance_enhancement(int mode)
{
const struct reg_s *s = NULL;
struct performance_config_s *perfconf = NULL;
int i = 0;
switch (mode) {
case VMODE_PAL:
perfconf = &cvbs_drv.perf_conf_pal;
break;
case VMODE_NTSC:
case VMODE_NTSC_M:
perfconf = &cvbs_drv.perf_conf_ntsc;
break;
default:
break;
}
if (!perfconf)
return;
if (!perfconf->reg_table) {
printf("no performance table\n");
return;
}
i = 0;
s = perfconf->reg_table;
while (i < perfconf->reg_cnt) {
cvbs_write_vcbus(s->reg, s->val);
//printf("vcbus reg[0x%04x] = 0x%08x\n", s->reg, s->val);
s++;
i++;
}
printf("%s\n", __func__);
}
static int cvbs_config_enci(int vmode)
{
const struct reg_s *s = NULL;
switch (vmode) {
case VMODE_PAL:
s = &tvregs_576cvbs_enc[0];
break;
case VMODE_NTSC:
case VMODE_NTSC_M:
s = &tvregs_480cvbs_enc[0];
break;
case VMODE_PAL_M:
s = &tvregs_pal_m_enc[0];
break;
case VMODE_PAL_N:
s = &tvregs_pal_n_enc[0];
break;
default:
break;
}
if (s == NULL)
return -1;
while ((s->reg != MREG_END_MARKER)) {
cvbs_write_vcbus(s->reg, s->val);
//printf("reg[0x%.2x] = 0x%.4x\n", s->reg, s->val);
s ++;
}
cvbs_performance_enhancement(vmode);
return 0;
}
/*----------------------------------------------------------------------------*/
// configuration for output
// output vmode: 576cvbs, 480cvbs
int cvbs_set_vmode(char* vmode_name)
{
if (!strncmp(vmode_name, "576cvbs", strlen("576cvbs"))) {
cvbs_mode = VMODE_PAL;
cvbs_config_enci(0);
cvbs_config_clock();
cvbs_set_vdac(1);
return 0;
} else if (!strncmp(vmode_name, "480cvbs", strlen("480cvbs"))) {
cvbs_mode = VMODE_NTSC;
cvbs_config_enci(1);
cvbs_config_clock();
cvbs_set_vdac(1);
return 0;
} else if (!strncmp(vmode_name, "ntsc_m", strlen("ntsc_m"))) {
cvbs_mode = VMODE_NTSC_M;
cvbs_config_enci(VMODE_NTSC_M);
cvbs_config_clock();
cvbs_set_vdac(1);
return 0;
} else if (!strncmp(vmode_name, "pal_m", strlen("pal_m"))) {
cvbs_mode = VMODE_PAL_M;
cvbs_config_enci(VMODE_PAL_M);
cvbs_config_clock();
cvbs_set_vdac(1);
return 0;
} else if (!strncmp(vmode_name, "pal_n", strlen("pal_n"))) {
cvbs_mode = VMODE_PAL_N;
cvbs_config_enci(VMODE_PAL_N);
cvbs_config_clock();
cvbs_set_vdac(1);
return 0;
} else if (!strncmp(vmode_name, "disable", strlen("disable"))) {
cvbs_set_vdac(0);
cvbs_write_vcbus(ENCI_VIDEO_EN, 0);
cvbs_disable_clock();
return 0;
} else {
printf("[%s] is invalid for cvbs.\n", vmode_name);
return -1;
}
return 0;
}
/*----------------------------------------------------------------------------*/
#define CVBS_MODE_CNT 5
static char *cvbs_mode_str[CVBS_MODE_CNT] = {
"576cvbs",
"480cvbs",
"ntsc_m",
"pal_m",
"pal_n",
};
/***********************************************
* parameters: vmode_name, such as 576cvbs, 480cvbs...
* frac, cvbs alway 0. don't support.
* return: viu_mux
************************************************/
unsigned int cvbs_outputmode_check(char *vmode_name, unsigned int frac)
{
unsigned int i;
if (frac) {
printf("cvbs: don't support frac\n");
return VIU_MUX_MAX;
}
for (i = 0; i < CVBS_MODE_CNT; i++) {
if (!strncmp(vmode_name, cvbs_mode_str[i], strlen(cvbs_mode_str[i])))
return VIU_MUX_ENCI;
}
//printf("cvbs: outputmode[%s] is invalid\n", vmode_name);
return VIU_MUX_MAX;
}
// list for valid video mode
void cvbs_show_valid_vmode(void)
{
unsigned int i;
for (i = 0; i < CVBS_MODE_CNT; i++)
printf("%s\n", cvbs_mode_str[i]);
}
static char *cvbsout_performance_str[] = {
"performance", /* default for pal */
"performance_pal",
"performance_ntsc",
};
static void cvbs_get_config(void)
{
const void *dt_blob = NULL;
int node;
char *propdata;
const char *str;
struct reg_s *s;
unsigned int i, j, temp, cnt;
int ret;
dt_blob = gd->fdt_blob;
if (!dt_blob) {
printf("cvbs: error: dt_blob is null, load default setting\n");
return;
}
ret = fdt_check_header(dt_blob);
if (ret < 0) {
printf("cvbs: error: check dts: %s, load default setting\n",
fdt_strerror(ret));
return;
}
node = fdt_path_offset(dt_blob, "/cvbsout");
if (node < 0) {
printf("not find /cvbsout node: %s\n",
fdt_strerror(node));
return;
}
/* clk_path */
propdata = (char *)fdt_getprop(dt_blob, node, "clk_path", NULL);
if (propdata) {
s_enci_clk_path = be32_to_cpup((u32*)propdata);
printf("cvbs: find clk_path: 0x%x\n", s_enci_clk_path);
}
/* performance */
str = cvbsout_performance_str[1];
propdata = (char *)fdt_getprop(dt_blob, node, str, NULL);
if (!propdata) {
str = cvbsout_performance_str[0];
propdata = (char *)fdt_getprop(dt_blob, node, str, NULL);
if (!propdata)
goto cvbs_performance_config_ntsc;
}
cnt = 0;
while (cnt < CVBS_PERFORMANCE_CNT_MAX) {
j = 2 * cnt;
temp = be32_to_cpup((((u32*)propdata)+j));
if (temp == MREG_END_MARKER) /* ending */
break;
cnt++;
}
if (cnt >= CVBS_PERFORMANCE_CNT_MAX)
cnt = 0;
if (cnt > 0) {
printf("cvbs: find performance_pal config\n");
cvbs_drv.perf_conf_pal.reg_table = malloc(sizeof(struct reg_s) * cnt);
if (!cvbs_drv.perf_conf_pal.reg_table) {
printf("cvbs: error: failed to alloc %s table\n", str);
cnt = 0;
}
memset(cvbs_drv.perf_conf_pal.reg_table, 0, (sizeof(struct reg_s) * cnt));
cvbs_drv.perf_conf_pal.reg_cnt = cnt;
i = 0;
s = cvbs_drv.perf_conf_pal.reg_table;
while (i < cvbs_drv.perf_conf_pal.reg_cnt) {
j = 2 * i;
s->reg = be32_to_cpup((((u32*)propdata)+j));
s->val = be32_to_cpup((((u32*)propdata)+j+1));
/* printf("%p: 0x%04x = 0x%x\n", s, s->reg, s->val); */
s++;
i++;
}
}
cvbs_performance_config_ntsc:
str = cvbsout_performance_str[2];
propdata = (char *)fdt_getprop(dt_blob, node, str, NULL);
if (!propdata)
return;
cnt = 0;
while (cnt < CVBS_PERFORMANCE_CNT_MAX) {
j = 2 * cnt;
temp = be32_to_cpup((((u32*)propdata)+j));
if (temp == MREG_END_MARKER) /* ending */
break;
cnt++;
}
if (cnt >= CVBS_PERFORMANCE_CNT_MAX)
cnt = 0;
if (cnt > 0) {
printf("cvbs: find performance_ntsc config\n");
cvbs_drv.perf_conf_ntsc.reg_table = malloc(sizeof(struct reg_s) * cnt);
if (!cvbs_drv.perf_conf_ntsc.reg_table) {
printf("cvbs: error: failed to alloc %s table\n", str);
cnt = 0;
}
memset(cvbs_drv.perf_conf_ntsc.reg_table, 0, (sizeof(struct reg_s) * cnt));
cvbs_drv.perf_conf_ntsc.reg_cnt = cnt;
i = 0;
s = cvbs_drv.perf_conf_ntsc.reg_table;
while (i < cvbs_drv.perf_conf_ntsc.reg_cnt) {
j = 2 * i;
s->reg = be32_to_cpup((((u32*)propdata)+j));
s->val = be32_to_cpup((((u32*)propdata)+j+1));
/* printf("%p: 0x%04x = 0x%x\n", s, s->reg, s->val); */
s++;
i++;
}
}
}
void vdac_data_config(void)
{
printf("cvbs: cpuid:0x%x\n", get_cpu_id().family_id);
switch (get_cpu_id().family_id) {
case MESON_CPU_MAJOR_ID_G12A:
cvbs_drv.data = &cvbs_data_g12a;
break;
case MESON_CPU_MAJOR_ID_G12B:
cvbs_drv.data = &cvbs_data_g12b;
break;
case MESON_CPU_MAJOR_ID_SC2:
cvbs_drv.data = &cvbs_data_sc2;
break;
case MESON_CPU_MAJOR_ID_S4:
cvbs_drv.data = &cvbs_data_s4;
break;
default:
cvbs_drv.data = &cvbs_data_s4;
break;
}
}
void cvbs_init(void)
{
vdac_data_config();
vdac_ctrl_config_probe();
cvbs_get_config();
}