blob: 784f8f17bec81be0c91c852a6d93e24849aa7414 [file] [log] [blame]
/*
* drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/major.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/amlogic/media/vout/vinfo.h>
#include <linux/amlogic/media/vout/hdmi_tx/enc_clk_config.h>
#include <linux/amlogic/media/vout/hdmi_tx/hdmi_info_global.h>
#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h>
#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_ddc.h>
#include <linux/reset.h>
#include <linux/compiler.h>
#include "mach_reg.h"
#include "hdmi_tx_reg.h"
#include "tvenc_conf.h"
#include "common.h"
#include "hw_clk.h"
#include <linux/arm-smccc.h>
#include "checksha.h"
static void mode420_half_horizontal_para(void);
static void hdmi_phy_suspend(void);
static void hdmi_phy_wakeup(struct hdmitx_dev *hdev);
static void hdmitx_set_phy(struct hdmitx_dev *hdev);
static void hdmitx_set_hw(struct hdmitx_dev *hdev);
static void set_hdmi_audio_source(unsigned int src);
static void hdmitx_csc_config(unsigned char input_color_format,
unsigned char output_color_format, unsigned char color_depth);
static int hdmitx_hdmi_dvi_config(struct hdmitx_dev *hdev,
unsigned int dvi_mode);
static void hdmitx_set_avi_colorimetry(struct hdmi_format_para *para);
struct ksv_lists_ {
unsigned char valid;
unsigned int no;
unsigned char lists[MAX_KSV_LISTS * 5];
};
static struct ksv_lists_ tmp_ksv_lists;
static void hdmitx_set_packet(int type, unsigned char *DB, unsigned char *HB);
static void hdmitx_set_datapacket(int type, unsigned char *DB,
unsigned char *HB);
static void hdmitx_setaudioinfoframe(unsigned char *AUD_DB,
unsigned char *CHAN_STAT_BUF);
static int hdmitx_set_dispmode(struct hdmitx_dev *hdev);
static int hdmitx_set_audmode(struct hdmitx_dev *hdev,
struct hdmitx_audpara *audio_param);
static void hdmitx_setupirq(struct hdmitx_dev *hdev);
static void hdmitx_debug(struct hdmitx_dev *hdev, const char *buf);
static void hdmitx_uninit(struct hdmitx_dev *hdev);
static int hdmitx_cntl(struct hdmitx_dev *hdev, unsigned int cmd,
unsigned int argv);
static int hdmitx_cntl_ddc(struct hdmitx_dev *hdev, unsigned int cmd,
unsigned long argv);
static int hdmitx_get_state(struct hdmitx_dev *hdev, unsigned int cmd,
unsigned int argv);
static int hdmitx_cntl_config(struct hdmitx_dev *hdev, unsigned int cmd,
unsigned int argv);
static int hdmitx_cntl_misc(struct hdmitx_dev *hdev, unsigned int cmd,
unsigned int argv);
#define EDID_RAM_ADDR_SIZE (8)
/* HSYNC polarity: active high */
#define HSYNC_POLARITY 1
/* VSYNC polarity: active high */
#define VSYNC_POLARITY 1
/* Pixel format: 0=RGB444; 1=YCbCr444; 2=Rsrv; 3=YCbCr422. */
#define TX_INPUT_COLOR_FORMAT COLORSPACE_YUV444
/* Pixel range: 0=16-235/240; 1=16-240; 2=1-254; 3=0-255. */
#define TX_INPUT_COLOR_RANGE 0
/* Pixel bit width: 4=24-bit; 5=30-bit; 6=36-bit; 7=48-bit. */
#define TX_COLOR_DEPTH COLORDEPTH_24B
int hdmitx_hpd_hw_op(enum hpd_op cmd)
{
struct hdmitx_dev *hdev = get_hdmitx_device();
switch (hdev->chip_type) {
case MESON_CPU_ID_GXBB:
return hdmitx_hpd_hw_op_gxbb(cmd);
case MESON_CPU_ID_GXTVBB:
return hdmitx_hpd_hw_op_gxtvbb(cmd);
case MESON_CPU_ID_GXL:
case MESON_CPU_ID_GXM:
return hdmitx_hpd_hw_op_gxl(cmd);
case MESON_CPU_ID_TXLX:
return hdmitx_hpd_hw_op_txlx(cmd);
case MESON_CPU_ID_G12A:
case MESON_CPU_ID_G12B:
case MESON_CPU_ID_SM1:
return hdmitx_hpd_hw_op_g12a(cmd);
default:
break;
}
return 0;
}
EXPORT_SYMBOL(hdmitx_hpd_hw_op);
int read_hpd_gpio(void)
{
struct hdmitx_dev *hdev = get_hdmitx_device();
switch (hdev->chip_type) {
case MESON_CPU_ID_GXBB:
return read_hpd_gpio_gxbb();
case MESON_CPU_ID_GXTVBB:
return read_hpd_gpio_gxtvbb();
case MESON_CPU_ID_GXL:
case MESON_CPU_ID_GXM:
return read_hpd_gpio_gxl();
case MESON_CPU_ID_TXLX:
case MESON_CPU_ID_G12A:
case MESON_CPU_ID_G12B:
case MESON_CPU_ID_SM1:
return read_hpd_gpio_txlx();
default:
break;
}
return 0;
}
EXPORT_SYMBOL(read_hpd_gpio);
int hdmitx_ddc_hw_op(enum ddc_op cmd)
{
struct hdmitx_dev *hdev = get_hdmitx_device();
switch (hdev->chip_type) {
case MESON_CPU_ID_GXBB:
return hdmitx_ddc_hw_op_gxbb(cmd);
case MESON_CPU_ID_GXTVBB:
return hdmitx_ddc_hw_op_gxtvbb(cmd);
case MESON_CPU_ID_GXL:
case MESON_CPU_ID_GXM:
return hdmitx_ddc_hw_op_gxl(cmd);
case MESON_CPU_ID_TXLX:
case MESON_CPU_ID_G12A:
case MESON_CPU_ID_G12B:
case MESON_CPU_ID_SM1:
return hdmitx_ddc_hw_op_txlx(cmd);
default:
break;
}
return 0;
}
EXPORT_SYMBOL(hdmitx_ddc_hw_op);
static int hdcp_topo_st = -1;
int hdmitx_hdcp_opr(unsigned int val)
{
struct arm_smccc_res res;
if (val == 1) { /* HDCP14_ENABLE */
arm_smccc_smc(0x82000010, 0, 0, 0, 0, 0, 0, 0, &res);
}
if (val == 2) { /* HDCP14_RESULT */
arm_smccc_smc(0x82000011, 0, 0, 0, 0, 0, 0, 0, &res);
return (unsigned int)((res.a0)&0xffffffff);
}
if (val == 0) { /* HDCP14_INIT */
arm_smccc_smc(0x82000012, 0, 0, 0, 0, 0, 0, 0, &res);
}
if (val == 3) { /* HDCP14_EN_ENCRYPT */
arm_smccc_smc(0x82000013, 0, 0, 0, 0, 0, 0, 0, &res);
}
if (val == 4) { /* HDCP14_OFF */
arm_smccc_smc(0x82000014, 0, 0, 0, 0, 0, 0, 0, &res);
}
if (val == 5) { /* HDCP_MUX_22 */
arm_smccc_smc(0x82000015, 0, 0, 0, 0, 0, 0, 0, &res);
}
if (val == 6) { /* HDCP_MUX_14 */
arm_smccc_smc(0x82000016, 0, 0, 0, 0, 0, 0, 0, &res);
}
if (val == 7) { /* HDCP22_RESULT */
arm_smccc_smc(0x82000017, 0, 0, 0, 0, 0, 0, 0, &res);
return (unsigned int)((res.a0)&0xffffffff);
}
if (val == 0xa) { /* HDCP14_KEY_LSTORE */
arm_smccc_smc(0x8200001a, 0, 0, 0, 0, 0, 0, 0, &res);
return (unsigned int)((res.a0)&0xffffffff);
}
if (val == 0xb) { /* HDCP22_KEY_LSTORE */
arm_smccc_smc(0x8200001b, 0, 0, 0, 0, 0, 0, 0, &res);
return (unsigned int)((res.a0)&0xffffffff);
}
if (val == 0xc) { /* HDCP22_KEY_SET_DUK */
arm_smccc_smc(0x8200001c, 0, 0, 0, 0, 0, 0, 0, &res);
return (unsigned int)((res.a0)&0xffffffff);
}
if (val == 0xd) { /* HDCP22_SET_TOPO */
arm_smccc_smc(0x82000083, hdcp_topo_st, 0, 0, 0, 0, 0, 0, &res);
}
if (val == 0xe) { /* HDCP22_GET_TOPO */
arm_smccc_smc(0x82000084, 0, 0, 0, 0, 0, 0, 0, &res);
return (unsigned int)((res.a0)&0xffffffff);
}
return -1;
}
static void config_avmute(unsigned int val)
{
pr_info(HW "avmute set to %d\n", val);
switch (val) {
case SET_AVMUTE:
hdmitx_set_reg_bits(HDMITX_DWC_FC_GCP, 1, 1, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_GCP, 0, 0, 1);
break;
case CLR_AVMUTE:
hdmitx_set_reg_bits(HDMITX_DWC_FC_GCP, 0, 1, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_GCP, 1, 0, 1);
break;
case OFF_AVMUTE:
default:
hdmitx_set_reg_bits(HDMITX_DWC_FC_GCP, 0, 1, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_GCP, 0, 0, 1);
break;
}
}
void hdmitx_set_avi_vic(enum hdmi_vic vic)
{
hdmitx_wr_reg(HDMITX_DWC_FC_AVIVID, vic);
}
static int read_avmute(void)
{
int val;
int ret = 0;
val = hdmitx_rd_reg(HDMITX_DWC_FC_GCP) & 0x3;
switch (val) {
case 2:
ret = 1;
break;
case 1:
ret = -1;
break;
case 0:
ret = 0;
break;
default:
ret = 3;
break;
}
return ret;
}
static void config_video_mapping(enum hdmi_color_space cs,
enum hdmi_color_depth cd)
{
unsigned int val = 0;
pr_info("config: cs = %d cd = %d\n", cs, cd);
switch (cs) {
case COLORSPACE_RGB444:
switch (cd) {
case COLORDEPTH_24B:
val = 0x1;
break;
case COLORDEPTH_30B:
val = 0x3;
break;
case COLORDEPTH_36B:
val = 0x5;
break;
case COLORDEPTH_48B:
val = 0x7;
break;
default:
break;
}
break;
case COLORSPACE_YUV444:
case COLORSPACE_YUV420:
switch (cd) {
case COLORDEPTH_24B:
val = 0x9;
break;
case COLORDEPTH_30B:
val = 0xb;
break;
case COLORDEPTH_36B:
val = 0xd;
break;
case COLORDEPTH_48B:
val = 0xf;
break;
default:
break;
}
break;
case COLORSPACE_YUV422:
switch (cd) {
case COLORDEPTH_24B:
val = 0x16;
break;
case COLORDEPTH_30B:
val = 0x14;
break;
case COLORDEPTH_36B:
val = 0x12;
break;
case COLORDEPTH_48B:
pr_info("y422 no 48bits mode\n");
break;
default:
break;
}
break;
default:
break;
}
hdmitx_set_reg_bits(HDMITX_DWC_TX_INVID0, val, 0, 4);
switch (cd) {
case COLORDEPTH_24B:
val = 0x4;
break;
case COLORDEPTH_30B:
val = 0x5;
break;
case COLORDEPTH_36B:
val = 0x6;
break;
case COLORDEPTH_48B:
val = 0x7;
break;
default:
break;
}
hdmitx_set_reg_bits(HDMITX_DWC_VP_PR_CD, val, 4, 4);
switch (cd) {
case COLORDEPTH_30B:
case COLORDEPTH_36B:
case COLORDEPTH_48B:
hdmitx_set_reg_bits(HDMITX_DWC_VP_CONF, 0, 6, 1);
hdmitx_set_reg_bits(HDMITX_DWC_VP_CONF, 1, 5, 1);
hdmitx_set_reg_bits(HDMITX_DWC_VP_CONF, 1, 2, 1);
hdmitx_set_reg_bits(HDMITX_DWC_VP_CONF, 0, 0, 2);
break;
case COLORDEPTH_24B:
break;
default:
break;
}
hdmitx_set_reg_bits(HDMITX_DWC_VP_PR_CD, val, 4, 4);
}
/* record HDMITX current format, matched with uboot */
/* ISA_DEBUG_REG0 0x2600
* bit[11]: Y420
* bit[10:8]: HDMI VIC
* bit[7:0]: CEA VIC
*/
static unsigned int hdmitx_get_format(void)
{
unsigned int ret = 0;
struct hdmitx_dev *hdev = get_hdmitx_device();
switch (hdev->chip_type) {
case MESON_CPU_ID_TXLX:
case MESON_CPU_ID_G12A:
case MESON_CPU_ID_G12B:
case MESON_CPU_ID_SM1:
ret = hdmitx_get_format_txlx();
break;
case MESON_CPU_ID_GXBB:
case MESON_CPU_ID_GXTVBB:
case MESON_CPU_ID_GXL:
case MESON_CPU_ID_GXM:
default:
ret = hd_read_reg(P_ISA_DEBUG_REG0);
break;
}
return ret;
}
static int hdmitx_uboot_already_display(void)
{
int ret = 0;
if ((hd_read_reg(P_HHI_HDMI_CLK_CNTL) & (1 << 8))
&& (hd_read_reg(P_HHI_HDMI_PLL_CNTL) & (1 << 31))
&& (hdmitx_get_format())) {
pr_info(HW "alread display in uboot 0x%x\n",
hdmitx_get_format());
ret = 1;
} else {
pr_info(HW "hdmitx_get_format:0x%x\n",
hdmitx_get_format());
pr_info(HW "P_HHI_HDMI_CLK_CNTL :0x%x\n",
hd_read_reg(P_HHI_HDMI_CLK_CNTL));
pr_info(HW "P_HHI_HDMI_PLL_CNTL :0x%x\n",
hd_read_reg(P_HHI_HDMI_PLL_CNTL));
ret = 0;
}
return ret;
}
/* reset HDMITX APB & TX */
void hdmitx_sys_reset(void)
{
struct hdmitx_dev *hdev = get_hdmitx_device();
switch (hdev->chip_type) {
case MESON_CPU_ID_TXLX:
case MESON_CPU_ID_G12A:
case MESON_CPU_ID_G12B:
case MESON_CPU_ID_SM1:
hdmitx_sys_reset_txlx();
break;
case MESON_CPU_ID_GXBB:
case MESON_CPU_ID_GXTVBB:
case MESON_CPU_ID_GXL:
case MESON_CPU_ID_GXM:
default:
hd_set_reg_bits(P_RESET0_REGISTER, 1, 19, 1);
hd_set_reg_bits(P_RESET2_REGISTER, 1, 15, 1);
hd_set_reg_bits(P_RESET2_REGISTER, 1, 2, 1);
break;
}
}
/* for 30bits colordepth */
static void set_vmode_clk(struct hdmitx_dev *hdev)
{
hdmitx_set_clk(hdev);
}
static void hdmi_hwp_init(struct hdmitx_dev *hdev)
{
hdmitx_set_sys_clk(hdev, 0xff);
hdmitx_set_cts_hdcp22_clk(hdev);
hdmitx_set_hdcp_pclk(hdev);
/* wire wr_enable = control[3]; */
/* wire fifo_enable = control[2]; */
/* assign phy_clk_en = control[1]; */
/* Bring HDMITX MEM output of power down */
hd_set_reg_bits(P_HHI_MEM_PD_REG0, 0, 8, 8);
/* enable CLK_TO_DIG */
hd_set_reg_bits(P_HHI_HDMI_PHY_CNTL3, 0x3, 0, 2);
if (hdmitx_uboot_already_display()) {
hdev->ready = 1;
/* Get uboot output color space from AVI */
switch (hdmitx_rd_reg(HDMITX_DWC_FC_AVICONF0) & 0x3) {
case 1:
hdev->para->cs = COLORSPACE_YUV422;
break;
case 2:
hdev->para->cs = COLORSPACE_YUV444;
break;
case 3:
hdev->para->cs = COLORSPACE_YUV420;
break;
default:
hdev->para->cs = COLORSPACE_RGB444;
break;
}
/* If color space is not 422, then get depth from VP_PR_CD */
if (hdev->para->cs != COLORSPACE_YUV422) {
switch ((hdmitx_rd_reg(HDMITX_DWC_VP_PR_CD) >> 4) &
0xf) {
case 5:
hdev->para->cd = COLORDEPTH_30B;
break;
case 6:
hdev->para->cd = COLORDEPTH_36B;
break;
case 7:
hdev->para->cd = COLORDEPTH_48B;
break;
case 0:
case 4:
default:
hdev->para->cd = COLORDEPTH_24B;
break;
}
} else {
/* If colorspace is 422, then get depth from VP_REMAP */
switch (hdmitx_rd_reg(HDMITX_DWC_VP_REMAP) & 0x3) {
case 1:
hdev->para->cd = COLORDEPTH_30B;
break;
case 2:
hdev->para->cd = COLORDEPTH_36B;
break;
case 0:
default:
hdev->para->cd = COLORDEPTH_24B;
break;
}
}
} else {
hdev->para->cd = COLORDEPTH_RESERVED;
hdev->para->cs = COLORSPACE_RESERVED;
/* reset HDMITX APB & TX & PHY */
hdmitx_sys_reset();
if ((hdev->chip_type) < MESON_CPU_ID_G12A) {
/* Enable APB3 fail on error */
hd_set_reg_bits(P_HDMITX_CTRL_PORT, 1, 15, 1);
hd_set_reg_bits((P_HDMITX_CTRL_PORT + 0x10), 1, 15, 1);
}
/* Bring out of reset */
hdmitx_wr_reg(HDMITX_TOP_SW_RESET, 0);
udelay(200);
hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 3, 0, 2);
hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 3, 4, 2);
hdmitx_wr_reg(HDMITX_DWC_MC_LOCKONCLOCK, 0xff);
hdmitx_wr_reg(HDMITX_TOP_INTR_MASKN, 0x1f);
}
}
static void hdmi_hwi_init(struct hdmitx_dev *hdev)
{
unsigned int data32 = 0;
hdmitx_set_reg_bits(HDMITX_DWC_FC_INVIDCONF, 1, 7, 1);
hdmitx_wr_reg(HDMITX_DWC_A_HDCPCFG1, 0x7);
hdmitx_wr_reg(HDMITX_DWC_A_HDCPCFG0, 0x13);
/* Enable skpclk to HDCP2.2 IP */
hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 1, 7, 1);
/* Enable esmclk to HDCP2.2 IP */
hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 1, 6, 1);
/* Enable tmds_clk to HDCP2.2 IP */
hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 1, 5, 1);
hdmitx_hpd_hw_op(HPD_INIT_DISABLE_PULLUP);
hdmitx_hpd_hw_op(HPD_INIT_SET_FILTER);
hdmitx_ddc_hw_op(DDC_INIT_DISABLE_PULL_UP_DN);
hdmitx_ddc_hw_op(DDC_MUX_DDC);
/* Configure E-DDC interface */
data32 = 0;
data32 |= (1 << 24); /* [26:24] infilter_ddc_intern_clk_divide */
data32 |= (0 << 16); /* [23:16] infilter_ddc_sample_clk_divide */
data32 |= (0 << 8); /* [10: 8] infilter_cec_intern_clk_divide */
data32 |= (1 << 0); /* [ 7: 0] infilter_cec_sample_clk_divide */
hdmitx_wr_reg(HDMITX_TOP_INFILTER, data32);
data32 = 0;
data32 |= (0 << 6); /* [ 6] read_req_mask */
data32 |= (0 << 2); /* [ 2] done_mask */
hdmitx_wr_reg(HDMITX_DWC_I2CM_INT, data32);
data32 = 0;
data32 |= (0 << 6); /* [ 6] nack_mask */
data32 |= (0 << 2); /* [ 2] arbitration_error_mask */
hdmitx_wr_reg(HDMITX_DWC_I2CM_CTLINT, data32);
/* [ 3] i2c_fast_mode: 0=standard mode; 1=fast mode. */
data32 = 0;
data32 |= (0 << 3);
hdmitx_wr_reg(HDMITX_DWC_I2CM_DIV, data32);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_HCNT_1, 0);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_HCNT_0, 0xcf);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_LCNT_1, 0);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_LCNT_0, 0xff);
if (hdev->repeater_tx == 1) {
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_HCNT_0, 0x67);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_LCNT_0, 0x78);
}
hdmitx_wr_reg(HDMITX_DWC_I2CM_FS_SCL_HCNT_1, 0);
hdmitx_wr_reg(HDMITX_DWC_I2CM_FS_SCL_HCNT_0, 0x0f);
hdmitx_wr_reg(HDMITX_DWC_I2CM_FS_SCL_LCNT_1, 0);
hdmitx_wr_reg(HDMITX_DWC_I2CM_FS_SCL_LCNT_0, 0x20);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SDA_HOLD, 0x08);
data32 = 0;
data32 |= (0 << 5); /* [ 5] updt_rd_vsyncpoll_en */
data32 |= (0 << 4); /* [ 4] read_request_en // scdc */
data32 |= (0 << 0); /* [ 0] read_update */
hdmitx_wr_reg(HDMITX_DWC_I2CM_SCDC_UPDATE, data32);
}
void HDMITX_Meson_Init(struct hdmitx_dev *hdev)
{
hdev->HWOp.SetPacket = hdmitx_set_packet;
hdev->HWOp.SetDataPacket = hdmitx_set_datapacket;
hdev->HWOp.SetAudioInfoFrame = hdmitx_setaudioinfoframe;
hdev->HWOp.SetDispMode = hdmitx_set_dispmode;
hdev->HWOp.SetAudMode = hdmitx_set_audmode;
hdev->HWOp.SetupIRQ = hdmitx_setupirq;
hdev->HWOp.DebugFun = hdmitx_debug;
hdev->HWOp.UnInit = hdmitx_uninit;
hdev->HWOp.Cntl = hdmitx_cntl; /* todo */
hdev->HWOp.CntlDDC = hdmitx_cntl_ddc;
hdev->HWOp.GetState = hdmitx_get_state;
hdev->HWOp.CntlPacket = hdmitx_cntl;
hdev->HWOp.CntlConfig = hdmitx_cntl_config;
hdev->HWOp.CntlMisc = hdmitx_cntl_misc;
init_reg_map(hdev->chip_type);
hdmi_hwp_init(hdev);
hdmi_hwi_init(hdev);
hdev->HWOp.CntlMisc(hdev, MISC_AVMUTE_OP, CLR_AVMUTE);
}
static irqreturn_t intr_handler(int irq, void *dev)
{
/* get interrupt status */
unsigned int dat_top = hdmitx_rd_reg(HDMITX_TOP_INTR_STAT);
unsigned int dat_dwc = hdmitx_rd_reg(HDMITX_DWC_HDCP22REG_STAT);
struct hdmitx_dev *hdev = (struct hdmitx_dev *)dev;
/* ack INTERNAL_INTR or else we stuck with no interrupts at all */
hdmitx_wr_reg(HDMITX_TOP_INTR_STAT_CLR, ~0);
hdmitx_wr_reg(HDMITX_DWC_HDCP22REG_STAT, 0xff);
pr_info(SYS "irq %x\n", dat_top);
if (dat_dwc)
pr_info(SYS "irq %x\n", dat_dwc);
if (hdev->hpd_lock == 1) {
pr_info(HW "HDMI hpd locked\n");
goto next;
}
/* check HPD status */
if ((dat_top & (1 << 1)) && (dat_top & (1 << 2))) {
if (hdmitx_hpd_hw_op(HPD_READ_HPD_GPIO))
dat_top &= ~(1 << 2);
else
dat_top &= ~(1 << 1);
}
/* HPD rising */
if (dat_top & (1 << 1)) {
hdev->hdmitx_event |= HDMI_TX_HPD_PLUGIN;
hdev->hdmitx_event &= ~HDMI_TX_HPD_PLUGOUT;
hdev->rhpd_state = 1;
queue_delayed_work(hdev->hdmi_wq,
&hdev->work_hpd_plugin, HZ / 2);
}
/* HPD falling */
if (dat_top & (1 << 2)) {
hdev->hdmitx_event |= HDMI_TX_HPD_PLUGOUT;
hdev->hdmitx_event &= ~HDMI_TX_HPD_PLUGIN;
hdev->rhpd_state = 0;
queue_delayed_work(hdev->hdmi_wq,
&hdev->work_hpd_plugout, HZ / 20);
}
/* internal interrupt */
if (dat_top & (1 << 0)) {
hdev->hdmitx_event |= HDMI_TX_INTERNAL_INTR;
queue_work(hdev->hdmi_wq, &hdev->work_internal_intr);
}
if (dat_top & (1 << 3)) {
unsigned int rd_nonce_mode =
hdmitx_rd_reg(HDMITX_TOP_SKP_CNTL_STAT) & 0x1;
pr_info(HW "hdcp22: Nonce %s Vld: %d\n",
rd_nonce_mode ? "HW" : "SW",
((hdmitx_rd_reg(HDMITX_TOP_SKP_CNTL_STAT) >> 31) & 1));
if (!rd_nonce_mode) {
hdmitx_wr_reg(HDMITX_TOP_NONCE_0, 0x32107654);
hdmitx_wr_reg(HDMITX_TOP_NONCE_1, 0xba98fedc);
hdmitx_wr_reg(HDMITX_TOP_NONCE_2, 0xcdef89ab);
hdmitx_wr_reg(HDMITX_TOP_NONCE_3, 0x45670123);
hdmitx_wr_reg(HDMITX_TOP_NONCE_0, 0x76543210);
hdmitx_wr_reg(HDMITX_TOP_NONCE_1, 0xfedcba98);
hdmitx_wr_reg(HDMITX_TOP_NONCE_2, 0x89abcdef);
hdmitx_wr_reg(HDMITX_TOP_NONCE_3, 0x01234567);
}
}
if (dat_top & (1 << 30))
pr_info("hdcp22: reg stat: 0x%x\n", dat_dwc);
next:
return IRQ_HANDLED;
}
static unsigned long modulo(unsigned long a, unsigned long b)
{
if (a >= b)
return a - b;
else
return a;
}
static signed int to_signed(unsigned int a)
{
if (a <= 7)
return a;
else
return a - 16;
}
/*
* mode: 1 means Progressive; 0 means interlaced
*/
static void enc_vpu_bridge_reset(int mode)
{
unsigned int wr_clk = 0;
wr_clk = (hd_read_reg(P_VPU_HDMI_SETTING) & 0xf00) >> 8;
if (mode) {
hd_write_reg(P_ENCP_VIDEO_EN, 0);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 0, 0, 2);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 0, 8, 4);
mdelay(1);
hd_write_reg(P_ENCP_VIDEO_EN, 1);
mdelay(1);
hd_set_reg_bits(P_VPU_HDMI_SETTING, wr_clk, 8, 4);
mdelay(1);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 2, 0, 2);
} else {
hd_write_reg(P_ENCI_VIDEO_EN, 0);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 0, 0, 2);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 0, 8, 4);
mdelay(1);
hd_write_reg(P_ENCI_VIDEO_EN, 1);
mdelay(1);
hd_set_reg_bits(P_VPU_HDMI_SETTING, wr_clk, 8, 4);
mdelay(1);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 0, 2);
}
}
static void hdmi_tvenc1080i_set(struct hdmitx_vidpara *param)
{
unsigned long VFIFO2VD_TO_HDMI_LATENCY = 2;
unsigned long TOTAL_PIXELS = 0, PIXEL_REPEAT_HDMI = 0,
PIXEL_REPEAT_VENC = 0, ACTIVE_PIXELS = 0;
unsigned int FRONT_PORCH = 88, HSYNC_PIXELS = 0, ACTIVE_LINES = 0,
INTERLACE_MODE = 0, TOTAL_LINES = 0, SOF_LINES = 0,
VSYNC_LINES = 0;
unsigned int LINES_F0 = 0, LINES_F1 = 563, BACK_PORCH = 0,
EOF_LINES = 2, TOTAL_FRAMES = 0;
unsigned long total_pixels_venc = 0;
unsigned long active_pixels_venc = 0;
unsigned long front_porch_venc = 0;
unsigned long hsync_pixels_venc = 0;
unsigned long de_h_begin = 0, de_h_end = 0;
unsigned long de_v_begin_even = 0, de_v_end_even = 0,
de_v_begin_odd = 0, de_v_end_odd = 0;
unsigned long hs_begin = 0, hs_end = 0;
unsigned long vs_adjust = 0;
unsigned long vs_bline_evn = 0, vs_eline_evn = 0,
vs_bline_odd = 0, vs_eline_odd = 0;
unsigned long vso_begin_evn = 0, vso_begin_odd = 0;
if (param->VIC == HDMI_1080i60) {
INTERLACE_MODE = 1;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (1920*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (1080/(1+INTERLACE_MODE));
LINES_F0 = 562;
LINES_F1 = 563;
FRONT_PORCH = 88;
HSYNC_PIXELS = 44;
BACK_PORCH = 148;
EOF_LINES = 2;
VSYNC_LINES = 5;
SOF_LINES = 15;
TOTAL_FRAMES = 4;
} else if (param->VIC == HDMI_1080i50) {
INTERLACE_MODE = 1;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (1920*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (1080/(1+INTERLACE_MODE));
LINES_F0 = 562;
LINES_F1 = 563;
FRONT_PORCH = 528;
HSYNC_PIXELS = 44;
BACK_PORCH = 148;
EOF_LINES = 2;
VSYNC_LINES = 5;
SOF_LINES = 15;
TOTAL_FRAMES = 4;
}
TOTAL_PIXELS = (FRONT_PORCH+HSYNC_PIXELS+BACK_PORCH+ACTIVE_PIXELS);
TOTAL_LINES = (LINES_F0+(LINES_F1*INTERLACE_MODE));
total_pixels_venc = (TOTAL_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
active_pixels_venc = (ACTIVE_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
front_porch_venc = (FRONT_PORCH / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
hsync_pixels_venc =
(HSYNC_PIXELS / (1+PIXEL_REPEAT_HDMI)) * (1+PIXEL_REPEAT_VENC);
hd_write_reg(P_ENCP_VIDEO_MODE, hd_read_reg(P_ENCP_VIDEO_MODE)|(1<<14));
/* Program DE timing */
de_h_begin = modulo(hd_read_reg(P_ENCP_VIDEO_HAVON_BEGIN) +
VFIFO2VD_TO_HDMI_LATENCY, total_pixels_venc);
de_h_end = modulo(de_h_begin + active_pixels_venc, total_pixels_venc);
hd_write_reg(P_ENCP_DE_H_BEGIN, de_h_begin);
hd_write_reg(P_ENCP_DE_H_END, de_h_end);
/* Program DE timing for even field */
de_v_begin_even = hd_read_reg(P_ENCP_VIDEO_VAVON_BLINE);
de_v_end_even = de_v_begin_even + ACTIVE_LINES;
hd_write_reg(P_ENCP_DE_V_BEGIN_EVEN, de_v_begin_even);
hd_write_reg(P_ENCP_DE_V_END_EVEN, de_v_end_even);
/* Program DE timing for odd field if needed */
if (INTERLACE_MODE) {
de_v_begin_odd = to_signed((
hd_read_reg(P_ENCP_VIDEO_OFLD_VOAV_OFST) & 0xf0)>>4)
+ de_v_begin_even + (TOTAL_LINES-1)/2;
de_v_end_odd = de_v_begin_odd + ACTIVE_LINES;
hd_write_reg(P_ENCP_DE_V_BEGIN_ODD, de_v_begin_odd);/* 583 */
hd_write_reg(P_ENCP_DE_V_END_ODD, de_v_end_odd); /* 1123 */
}
/* Program Hsync timing */
if (de_h_end + front_porch_venc >= total_pixels_venc) {
hs_begin = de_h_end + front_porch_venc - total_pixels_venc;
vs_adjust = 1;
} else {
hs_begin = de_h_end + front_porch_venc;
vs_adjust = 0;
}
hs_end = modulo(hs_begin + hsync_pixels_venc, total_pixels_venc);
hd_write_reg(P_ENCP_DVI_HSO_BEGIN, hs_begin);
hd_write_reg(P_ENCP_DVI_HSO_END, hs_end);
/* Program Vsync timing for even field */
if (de_v_begin_even >= SOF_LINES + VSYNC_LINES + (1-vs_adjust))
vs_bline_evn = de_v_begin_even - SOF_LINES - VSYNC_LINES
- (1-vs_adjust);
else
vs_bline_evn = TOTAL_LINES + de_v_begin_even - SOF_LINES
- VSYNC_LINES - (1-vs_adjust);
vs_eline_evn = modulo(vs_bline_evn + VSYNC_LINES, TOTAL_LINES);
hd_write_reg(P_ENCP_DVI_VSO_BLINE_EVN, vs_bline_evn); /* 0 */
hd_write_reg(P_ENCP_DVI_VSO_ELINE_EVN, vs_eline_evn); /* 5 */
vso_begin_evn = hs_begin; /* 2 */
hd_write_reg(P_ENCP_DVI_VSO_BEGIN_EVN, vso_begin_evn); /* 2 */
hd_write_reg(P_ENCP_DVI_VSO_END_EVN, vso_begin_evn); /* 2 */
/* Program Vsync timing for odd field if needed */
if (INTERLACE_MODE) {
vs_bline_odd = de_v_begin_odd-1 - SOF_LINES - VSYNC_LINES;
vs_eline_odd = de_v_begin_odd-1 - SOF_LINES;
vso_begin_odd = modulo(hs_begin + (total_pixels_venc>>1),
total_pixels_venc);
hd_write_reg(P_ENCP_DVI_VSO_BLINE_ODD, vs_bline_odd);
hd_write_reg(P_ENCP_DVI_VSO_ELINE_ODD, vs_eline_odd);
hd_write_reg(P_ENCP_DVI_VSO_BEGIN_ODD, vso_begin_odd);
hd_write_reg(P_ENCP_DVI_VSO_END_ODD, vso_begin_odd);
}
hd_write_reg(P_VPU_HDMI_SETTING, (0 << 0) |
(0 << 1) |
(HSYNC_POLARITY << 2) |
(VSYNC_POLARITY << 3) |
(0 << 4) |
(4 << 5) |
(0 << 8) |
(0 << 12)
);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 1, 1);
}
static void hdmi_tvenc4k2k_set(struct hdmitx_vidpara *param)
{
unsigned long VFIFO2VD_TO_HDMI_LATENCY = 2;
unsigned long TOTAL_PIXELS = 4400, PIXEL_REPEAT_HDMI = 0,
PIXEL_REPEAT_VENC = 0, ACTIVE_PIXELS = 3840;
unsigned int FRONT_PORCH = 1020, HSYNC_PIXELS = 0, ACTIVE_LINES = 2160,
INTERLACE_MODE = 0U, TOTAL_LINES = 0, SOF_LINES = 0,
VSYNC_LINES = 0;
unsigned int LINES_F0 = 2250, LINES_F1 = 2250, BACK_PORCH = 0,
EOF_LINES = 8, TOTAL_FRAMES = 0;
unsigned long total_pixels_venc = 0;
unsigned long active_pixels_venc = 0;
unsigned long front_porch_venc = 0;
unsigned long hsync_pixels_venc = 0;
unsigned long de_h_begin = 0, de_h_end = 0;
unsigned long de_v_begin_even = 0, de_v_end_even = 0;
unsigned long hs_begin = 0, hs_end = 0;
unsigned long vs_adjust = 0;
unsigned long vs_bline_evn = 0, vs_eline_evn = 0;
unsigned long vso_begin_evn = 0;
switch (param->VIC) {
case HDMI_4k2k_30:
case HDMI_3840x2160p60_16x9:
case HDMI_3840x2160p60_16x9_Y420:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (3840*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (2160/(1+INTERLACE_MODE));
LINES_F0 = 2250;
LINES_F1 = 2250;
FRONT_PORCH = 176;
HSYNC_PIXELS = 88;
BACK_PORCH = 296;
EOF_LINES = 8 + 1;
VSYNC_LINES = 10;
SOF_LINES = 72 + 1;
TOTAL_FRAMES = 3;
break;
case HDMI_4k2k_25:
case HDMI_3840x2160p50_16x9:
case HDMI_3840x2160p50_16x9_Y420:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (3840*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (2160/(1+INTERLACE_MODE));
LINES_F0 = 2250;
LINES_F1 = 2250;
FRONT_PORCH = 1056;
HSYNC_PIXELS = 88;
BACK_PORCH = 296;
EOF_LINES = 8 + 1;
VSYNC_LINES = 10;
SOF_LINES = 72 + 1;
TOTAL_FRAMES = 3;
break;
case HDMI_4k2k_24:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (3840*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (2160/(1+INTERLACE_MODE));
LINES_F0 = 2250;
LINES_F1 = 2250;
FRONT_PORCH = 1276;
HSYNC_PIXELS = 88;
BACK_PORCH = 296;
EOF_LINES = 8 + 1;
VSYNC_LINES = 10;
SOF_LINES = 72 + 1;
TOTAL_FRAMES = 3;
break;
case HDMI_4k2k_smpte_24:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (4096*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (2160/(1+INTERLACE_MODE));
LINES_F0 = 2250;
LINES_F1 = 2250;
FRONT_PORCH = 1020;
HSYNC_PIXELS = 88;
BACK_PORCH = 296;
EOF_LINES = 8 + 1;
VSYNC_LINES = 10;
SOF_LINES = 72 + 1;
TOTAL_FRAMES = 3;
break;
case HDMI_4096x2160p25_256x135:
case HDMI_4096x2160p50_256x135:
case HDMI_4096x2160p50_256x135_Y420:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (4096*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (2160/(1+INTERLACE_MODE));
LINES_F0 = 2250;
LINES_F1 = 2250;
FRONT_PORCH = 968;
HSYNC_PIXELS = 88;
BACK_PORCH = 128;
EOF_LINES = 8;
VSYNC_LINES = 10;
SOF_LINES = 72;
TOTAL_FRAMES = 3;
break;
case HDMI_4096x2160p30_256x135:
case HDMI_4096x2160p60_256x135:
case HDMI_4096x2160p60_256x135_Y420:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (4096*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (2160/(1+INTERLACE_MODE));
LINES_F0 = 2250;
LINES_F1 = 2250;
FRONT_PORCH = 88;
HSYNC_PIXELS = 88;
BACK_PORCH = 128;
EOF_LINES = 8;
VSYNC_LINES = 10;
SOF_LINES = 72;
TOTAL_FRAMES = 3;
break;
default:
pr_info("hdmitx20: no setting for VIC = %d\n", param->VIC);
break;
}
TOTAL_PIXELS = (FRONT_PORCH+HSYNC_PIXELS+BACK_PORCH+ACTIVE_PIXELS);
TOTAL_LINES = (LINES_F0+(LINES_F1*INTERLACE_MODE));
total_pixels_venc = (TOTAL_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
active_pixels_venc = (ACTIVE_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
front_porch_venc = (FRONT_PORCH / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
hsync_pixels_venc = (HSYNC_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
de_h_begin = modulo(hd_read_reg(P_ENCP_VIDEO_HAVON_BEGIN) +
VFIFO2VD_TO_HDMI_LATENCY, total_pixels_venc);
de_h_end = modulo(de_h_begin + active_pixels_venc, total_pixels_venc);
hd_write_reg(P_ENCP_DE_H_BEGIN, de_h_begin);
hd_write_reg(P_ENCP_DE_H_END, de_h_end);
/* Program DE timing for even field */
de_v_begin_even = hd_read_reg(P_ENCP_VIDEO_VAVON_BLINE);
de_v_end_even = modulo(de_v_begin_even + ACTIVE_LINES, TOTAL_LINES);
hd_write_reg(P_ENCP_DE_V_BEGIN_EVEN, de_v_begin_even);
hd_write_reg(P_ENCP_DE_V_END_EVEN, de_v_end_even);
/* Program Hsync timing */
if (de_h_end + front_porch_venc >= total_pixels_venc) {
hs_begin = de_h_end + front_porch_venc - total_pixels_venc;
vs_adjust = 1;
} else {
hs_begin = de_h_end + front_porch_venc;
vs_adjust = 1;
}
hs_end = modulo(hs_begin + hsync_pixels_venc, total_pixels_venc);
hd_write_reg(P_ENCP_DVI_HSO_BEGIN, hs_begin);
hd_write_reg(P_ENCP_DVI_HSO_END, hs_end);
/* Program Vsync timing for even field */
if (de_v_begin_even >= SOF_LINES + VSYNC_LINES + (1-vs_adjust))
vs_bline_evn = de_v_begin_even - SOF_LINES - VSYNC_LINES
- (1-vs_adjust);
else
vs_bline_evn = TOTAL_LINES + de_v_begin_even - SOF_LINES
- VSYNC_LINES - (1-vs_adjust);
vs_eline_evn = modulo(vs_bline_evn + VSYNC_LINES, TOTAL_LINES);
hd_write_reg(P_ENCP_DVI_VSO_BLINE_EVN, vs_bline_evn);
hd_write_reg(P_ENCP_DVI_VSO_ELINE_EVN, vs_eline_evn);
vso_begin_evn = hs_begin;
hd_write_reg(P_ENCP_DVI_VSO_BEGIN_EVN, vso_begin_evn);
hd_write_reg(P_ENCP_DVI_VSO_END_EVN, vso_begin_evn);
hd_write_reg(P_VPU_HDMI_SETTING, (0 << 0) |
(0 << 1) |
(HSYNC_POLARITY << 2) |
(VSYNC_POLARITY << 3) |
(0 << 4) |
(4 << 5) |
(0 << 8) |
(0 << 12)
);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 1, 1);
hd_write_reg(P_ENCP_VIDEO_EN, 1);
}
static void hdmi_tvenc480i_set(struct hdmitx_vidpara *param)
{
unsigned long VFIFO2VD_TO_HDMI_LATENCY = 1;
unsigned long TOTAL_PIXELS = 0, PIXEL_REPEAT_HDMI = 0,
PIXEL_REPEAT_VENC = 0, ACTIVE_PIXELS = 0;
unsigned int FRONT_PORCH = 38, HSYNC_PIXELS = 124, ACTIVE_LINES = 0,
INTERLACE_MODE = 0, TOTAL_LINES = 0, SOF_LINES = 0,
VSYNC_LINES = 0;
unsigned int LINES_F0 = 262, LINES_F1 = 263, BACK_PORCH = 114,
EOF_LINES = 2, TOTAL_FRAMES = 0;
unsigned long total_pixels_venc = 0;
unsigned long active_pixels_venc = 0;
unsigned long front_porch_venc = 0;
unsigned long hsync_pixels_venc = 0;
unsigned long de_h_begin = 0, de_h_end = 0;
unsigned long de_v_begin_even = 0, de_v_end_even = 0,
de_v_begin_odd = 0, de_v_end_odd = 0;
unsigned long hs_begin = 0, hs_end = 0;
unsigned long vs_adjust = 0;
unsigned long vs_bline_evn = 0, vs_eline_evn = 0,
vs_bline_odd = 0, vs_eline_odd = 0;
unsigned long vso_begin_evn = 0, vso_begin_odd = 0;
hd_set_reg_bits(P_HHI_GCLK_OTHER, 1, 8, 1);
switch (param->VIC) {
case HDMI_480i60:
case HDMI_480i60_16x9:
case HDMI_480i60_16x9_rpt:
INTERLACE_MODE = 1;
PIXEL_REPEAT_VENC = 1;
PIXEL_REPEAT_HDMI = 1;
ACTIVE_PIXELS = (720*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (480/(1+INTERLACE_MODE));
LINES_F0 = 262;
LINES_F1 = 263;
FRONT_PORCH = 38;
HSYNC_PIXELS = 124;
BACK_PORCH = 114;
EOF_LINES = 4;
VSYNC_LINES = 3;
SOF_LINES = 15;
TOTAL_FRAMES = 4;
break;
case HDMI_576i50:
case HDMI_576i50_16x9:
case HDMI_576i50_16x9_rpt:
INTERLACE_MODE = 1;
PIXEL_REPEAT_VENC = 1;
PIXEL_REPEAT_HDMI = 1;
ACTIVE_PIXELS = (720*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (576/(1+INTERLACE_MODE));
LINES_F0 = 312;
LINES_F1 = 313;
FRONT_PORCH = 24;
HSYNC_PIXELS = 126;
BACK_PORCH = 138;
EOF_LINES = 2;
VSYNC_LINES = 3;
SOF_LINES = 19;
TOTAL_FRAMES = 4;
break;
default:
break;
}
TOTAL_PIXELS = (FRONT_PORCH+HSYNC_PIXELS+BACK_PORCH+ACTIVE_PIXELS);
TOTAL_LINES = (LINES_F0+(LINES_F1*INTERLACE_MODE));
total_pixels_venc = (TOTAL_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC); /* 1716 / 2 * 2 = 1716 */
active_pixels_venc = (ACTIVE_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
front_porch_venc = (FRONT_PORCH / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC); /* 38 / 2 * 2 = 38 */
hsync_pixels_venc = (HSYNC_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC); /* 124 / 2 * 2 = 124 */
de_h_begin = modulo(hd_read_reg(P_ENCI_VFIFO2VD_PIXEL_START) +
VFIFO2VD_TO_HDMI_LATENCY, total_pixels_venc);
de_h_end = modulo(de_h_begin + active_pixels_venc, total_pixels_venc);
hd_write_reg(P_ENCI_DE_H_BEGIN, de_h_begin); /* 235 */
hd_write_reg(P_ENCI_DE_H_END, de_h_end); /* 1675 */
de_v_begin_even = hd_read_reg(P_ENCI_VFIFO2VD_LINE_TOP_START);
de_v_end_even = de_v_begin_even + ACTIVE_LINES;
de_v_begin_odd = hd_read_reg(P_ENCI_VFIFO2VD_LINE_BOT_START);
de_v_end_odd = de_v_begin_odd + ACTIVE_LINES;
hd_write_reg(P_ENCI_DE_V_BEGIN_EVEN, de_v_begin_even);
hd_write_reg(P_ENCI_DE_V_END_EVEN, de_v_end_even);
hd_write_reg(P_ENCI_DE_V_BEGIN_ODD, de_v_begin_odd);
hd_write_reg(P_ENCI_DE_V_END_ODD, de_v_end_odd);
/* Program Hsync timing */
if (de_h_end + front_porch_venc >= total_pixels_venc) {
hs_begin = de_h_end + front_porch_venc - total_pixels_venc;
vs_adjust = 1;
} else {
hs_begin = de_h_end + front_porch_venc;
vs_adjust = 0;
}
hs_end = modulo(hs_begin + hsync_pixels_venc, total_pixels_venc);
hd_write_reg(P_ENCI_DVI_HSO_BEGIN, hs_begin); /* 1713 */
hd_write_reg(P_ENCI_DVI_HSO_END, hs_end); /* 121 */
/* Program Vsync timing for even field */
if (de_v_end_odd-1 + EOF_LINES + vs_adjust >= LINES_F1) {
vs_bline_evn = de_v_end_odd-1 + EOF_LINES + vs_adjust
- LINES_F1;
vs_eline_evn = vs_bline_evn + VSYNC_LINES;
hd_write_reg(P_ENCI_DVI_VSO_BLINE_EVN, vs_bline_evn);
/* vso_bline_evn_reg_wr_cnt ++; */
hd_write_reg(P_ENCI_DVI_VSO_ELINE_EVN, vs_eline_evn);
/* vso_eline_evn_reg_wr_cnt ++; */
hd_write_reg(P_ENCI_DVI_VSO_BEGIN_EVN, hs_begin);
hd_write_reg(P_ENCI_DVI_VSO_END_EVN, hs_begin);
} else {
vs_bline_odd = de_v_end_odd-1 + EOF_LINES + vs_adjust;
hd_write_reg(P_ENCI_DVI_VSO_BLINE_ODD, vs_bline_odd);
/* vso_bline_odd_reg_wr_cnt ++; */
hd_write_reg(P_ENCI_DVI_VSO_BEGIN_ODD, hs_begin);
if (vs_bline_odd + VSYNC_LINES >= LINES_F1) {
vs_eline_evn = vs_bline_odd + VSYNC_LINES - LINES_F1;
hd_write_reg(P_ENCI_DVI_VSO_ELINE_EVN, vs_eline_evn);
/* vso_eline_evn_reg_wr_cnt ++; */
hd_write_reg(P_ENCI_DVI_VSO_END_EVN, hs_begin);
} else {
vs_eline_odd = vs_bline_odd + VSYNC_LINES;
hd_write_reg(P_ENCI_DVI_VSO_ELINE_ODD, vs_eline_odd);
/* vso_eline_odd_reg_wr_cnt ++; */
hd_write_reg(P_ENCI_DVI_VSO_END_ODD, hs_begin);
}
}
/* Program Vsync timing for odd field */
if (de_v_end_even-1 + EOF_LINES + 1 >= LINES_F0) {
vs_bline_odd = de_v_end_even-1 + EOF_LINES + 1 - LINES_F0;
vs_eline_odd = vs_bline_odd + VSYNC_LINES;
hd_write_reg(P_ENCI_DVI_VSO_BLINE_ODD, vs_bline_odd);
/* vso_bline_odd_reg_wr_cnt ++; */
hd_write_reg(P_ENCI_DVI_VSO_ELINE_ODD, vs_eline_odd);
/* vso_eline_odd_reg_wr_cnt ++; */
vso_begin_odd = modulo(hs_begin + (total_pixels_venc>>1),
total_pixels_venc);
hd_write_reg(P_ENCI_DVI_VSO_BEGIN_ODD, vso_begin_odd);
hd_write_reg(P_ENCI_DVI_VSO_END_ODD, vso_begin_odd);
} else {
vs_bline_evn = de_v_end_even-1 + EOF_LINES + 1;
hd_write_reg(P_ENCI_DVI_VSO_BLINE_EVN, vs_bline_evn); /* 261 */
/* vso_bline_evn_reg_wr_cnt ++; */
vso_begin_evn = modulo(hs_begin + (total_pixels_venc>>1),
total_pixels_venc);
hd_write_reg(P_ENCI_DVI_VSO_BEGIN_EVN, vso_begin_evn);
if (vs_bline_evn + VSYNC_LINES >= LINES_F0) {
vs_eline_odd = vs_bline_evn + VSYNC_LINES - LINES_F0;
hd_write_reg(P_ENCI_DVI_VSO_ELINE_ODD, vs_eline_odd);
/* vso_eline_odd_reg_wr_cnt ++; */
hd_write_reg(P_ENCI_DVI_VSO_END_ODD, vso_begin_evn);
} else {
vs_eline_evn = vs_bline_evn + VSYNC_LINES;
hd_write_reg(P_ENCI_DVI_VSO_ELINE_EVN, vs_eline_evn);
/* vso_eline_evn_reg_wr_cnt ++; */
hd_write_reg(P_ENCI_DVI_VSO_END_EVN, vso_begin_evn);
}
}
hd_write_reg(P_VPU_HDMI_SETTING, (0 << 0) |
(0 << 1) |
(0 << 2) |
(0 << 3) |
(0 << 4) |
(4 << 5) |
(1 << 8) |
(1 << 12)
);
if ((param->VIC == HDMI_480i60_16x9_rpt) ||
(param->VIC == HDMI_576i50_16x9_rpt))
hd_set_reg_bits(P_VPU_HDMI_SETTING, 3, 12, 4);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 0, 1);
}
static void hdmi_tvenc_vesa_set(struct hdmitx_vidpara *param)
{
unsigned long VFIFO2VD_TO_HDMI_LATENCY = 2;
unsigned long TOTAL_PIXELS = 0, PIXEL_REPEAT_HDMI = 0,
PIXEL_REPEAT_VENC = 0, ACTIVE_PIXELS = 0;
unsigned int FRONT_PORCH = 0, HSYNC_PIXELS = 0, ACTIVE_LINES = 0,
INTERLACE_MODE = 0, TOTAL_LINES = 0, SOF_LINES = 0,
VSYNC_LINES = 0;
unsigned int LINES_F0 = 0, LINES_F1 = 0, BACK_PORCH = 0,
EOF_LINES = 0, TOTAL_FRAMES = 0;
unsigned long total_pixels_venc = 0;
unsigned long active_pixels_venc = 0;
unsigned long front_porch_venc = 0;
unsigned long hsync_pixels_venc = 0;
unsigned long de_h_begin = 0, de_h_end = 0;
unsigned long de_v_begin_even = 0, de_v_end_even = 0,
de_v_begin_odd = 0, de_v_end_odd = 0;
unsigned long hs_begin = 0, hs_end = 0;
unsigned long vs_adjust = 0;
unsigned long vs_bline_evn = 0, vs_eline_evn = 0,
vs_bline_odd = 0, vs_eline_odd = 0;
unsigned long vso_begin_evn = 0, vso_begin_odd = 0;
struct hdmi_format_para *vpara = NULL;
struct hdmi_cea_timing *vtiming = NULL;
vpara = hdmi_get_fmt_paras(param->VIC);
if (vpara == NULL) {
pr_info("hdmitx: don't find Paras for VESA %d\n", param->VIC);
return;
}
vtiming = &vpara->timing;
INTERLACE_MODE = 0;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = vtiming->h_active;
ACTIVE_LINES = vtiming->v_active;
LINES_F0 = vtiming->v_total;
LINES_F1 = vtiming->v_total;
FRONT_PORCH = vtiming->h_front;
HSYNC_PIXELS = vtiming->h_sync;
BACK_PORCH = vtiming->h_back;
EOF_LINES = vtiming->v_front;
VSYNC_LINES = vtiming->v_sync;
SOF_LINES = vtiming->v_back;
TOTAL_FRAMES = 4;
TOTAL_PIXELS = (FRONT_PORCH+HSYNC_PIXELS+BACK_PORCH+ACTIVE_PIXELS);
TOTAL_LINES = (LINES_F0+(LINES_F1*INTERLACE_MODE));
total_pixels_venc = (TOTAL_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
active_pixels_venc = (ACTIVE_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
front_porch_venc = (FRONT_PORCH / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
hsync_pixels_venc = (HSYNC_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
hd_write_reg(P_ENCP_VIDEO_MODE, hd_read_reg(P_ENCP_VIDEO_MODE)|(1<<14));
/* Program DE timing */
de_h_begin = modulo(hd_read_reg(P_ENCP_VIDEO_HAVON_BEGIN) +
VFIFO2VD_TO_HDMI_LATENCY, total_pixels_venc);
de_h_end = modulo(de_h_begin + active_pixels_venc, total_pixels_venc);
hd_write_reg(P_ENCP_DE_H_BEGIN, de_h_begin); /* 220 */
hd_write_reg(P_ENCP_DE_H_END, de_h_end); /* 1660 */
/* Program DE timing for even field */
de_v_begin_even = hd_read_reg(P_ENCP_VIDEO_VAVON_BLINE);
de_v_end_even = de_v_begin_even + ACTIVE_LINES;
hd_write_reg(P_ENCP_DE_V_BEGIN_EVEN, de_v_begin_even);
hd_write_reg(P_ENCP_DE_V_END_EVEN, de_v_end_even); /* 522 */
/* Program DE timing for odd field if needed */
if (INTERLACE_MODE) {
de_v_begin_odd = to_signed(
(hd_read_reg(P_ENCP_VIDEO_OFLD_VOAV_OFST)
& 0xf0)>>4) + de_v_begin_even + (TOTAL_LINES-1)/2;
de_v_end_odd = de_v_begin_odd + ACTIVE_LINES;
hd_write_reg(P_ENCP_DE_V_BEGIN_ODD, de_v_begin_odd);
hd_write_reg(P_ENCP_DE_V_END_ODD, de_v_end_odd);
}
/* Program Hsync timing */
if (de_h_end + front_porch_venc >= total_pixels_venc) {
hs_begin = de_h_end + front_porch_venc - total_pixels_venc;
vs_adjust = 1;
} else {
hs_begin = de_h_end + front_porch_venc;
vs_adjust = 0;
}
hs_end = modulo(hs_begin + hsync_pixels_venc, total_pixels_venc);
hd_write_reg(P_ENCP_DVI_HSO_BEGIN, hs_begin);
hd_write_reg(P_ENCP_DVI_HSO_END, hs_end);
/* Program Vsync timing for even field */
if (de_v_begin_even >= SOF_LINES + VSYNC_LINES + (1-vs_adjust))
vs_bline_evn = de_v_begin_even - SOF_LINES - VSYNC_LINES -
(1-vs_adjust);
else
vs_bline_evn = TOTAL_LINES + de_v_begin_even - SOF_LINES -
VSYNC_LINES - (1-vs_adjust);
vs_eline_evn = modulo(vs_bline_evn + VSYNC_LINES, TOTAL_LINES);
hd_write_reg(P_ENCP_DVI_VSO_BLINE_EVN, vs_bline_evn); /* 5 */
hd_write_reg(P_ENCP_DVI_VSO_ELINE_EVN, vs_eline_evn); /* 11 */
vso_begin_evn = hs_begin; /* 1692 */
hd_write_reg(P_ENCP_DVI_VSO_BEGIN_EVN, vso_begin_evn); /* 1692 */
hd_write_reg(P_ENCP_DVI_VSO_END_EVN, vso_begin_evn); /* 1692 */
/* Program Vsync timing for odd field if needed */
if (INTERLACE_MODE) {
vs_bline_odd = de_v_begin_odd-1 - SOF_LINES - VSYNC_LINES;
vs_eline_odd = de_v_begin_odd-1 - SOF_LINES;
vso_begin_odd = modulo(hs_begin + (total_pixels_venc>>1),
total_pixels_venc);
hd_write_reg(P_ENCP_DVI_VSO_BLINE_ODD, vs_bline_odd);
hd_write_reg(P_ENCP_DVI_VSO_ELINE_ODD, vs_eline_odd);
hd_write_reg(P_ENCP_DVI_VSO_BEGIN_ODD, vso_begin_odd);
hd_write_reg(P_ENCP_DVI_VSO_END_ODD, vso_begin_odd);
}
switch (param->VIC) {
case HDMIV_640x480p60hz:
hd_write_reg(P_VPU_HDMI_SETTING, (0 << 0) |
(0 << 1) |
(0 << 2) |
(0 << 3) |
(0 << 4) |
(4 << 5) |
(0 << 8) |
(0 << 12)
);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 1, 1);
break;
case HDMIV_600x1024p60hz:
hd_write_reg(P_VPU_HDMI_SETTING, 0x82);
break;
default:
hd_write_reg(P_VPU_HDMI_SETTING, (0 << 0) |
(0 << 1) | /* [ 1] src_sel_encp */
(HSYNC_POLARITY << 2) |
(VSYNC_POLARITY << 3) |
(0 << 4) |
(4 << 5) |
(0 << 8) |
(0 << 12)
);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 1, 1);
}
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 1, 1);
}
static void hdmi_tvenc_set(struct hdmitx_vidpara *param)
{
unsigned long VFIFO2VD_TO_HDMI_LATENCY = 2;
unsigned long TOTAL_PIXELS = 0, PIXEL_REPEAT_HDMI = 0,
PIXEL_REPEAT_VENC = 0, ACTIVE_PIXELS = 0;
unsigned int FRONT_PORCH = 0, HSYNC_PIXELS = 0, ACTIVE_LINES = 0,
INTERLACE_MODE = 0U, TOTAL_LINES = 0, SOF_LINES = 0,
VSYNC_LINES = 0;
unsigned int LINES_F0 = 0, LINES_F1 = 0, BACK_PORCH = 0,
EOF_LINES = 0, TOTAL_FRAMES = 0;
unsigned long total_pixels_venc = 0;
unsigned long active_pixels_venc = 0;
unsigned long front_porch_venc = 0;
unsigned long hsync_pixels_venc = 0;
unsigned long de_h_begin = 0, de_h_end = 0;
unsigned long de_v_begin_even = 0, de_v_end_even = 0;
unsigned long hs_begin = 0, hs_end = 0;
unsigned long vs_adjust = 0;
unsigned long vs_bline_evn = 0, vs_eline_evn = 0;
unsigned long vso_begin_evn = 0;
struct hdmi_format_para *hdmi_encp_para = NULL;
struct hdmi_cea_timing *hdmi_encp_timing = NULL;
if ((param->VIC & HDMITX_VESA_OFFSET) == HDMITX_VESA_OFFSET) {
/* VESA modes setting */
hdmi_tvenc_vesa_set(param);
return;
}
hdmi_encp_para = hdmi_get_fmt_paras(param->VIC);
if (hdmi_encp_para == NULL) {
pr_info("hdmitx: don't find Paras for VIC : %d\n", param->VIC);
} else {
hdmi_encp_timing = &hdmi_encp_para->timing;
if ((param->VIC & HDMITX_VESA_OFFSET) == HDMITX_VESA_OFFSET) {
/* VESA modes setting */
hdmi_tvenc_vesa_set(param);
return;
}
switch (param->VIC) {
case HDMI_3840x1080p120hz:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = 3840;
ACTIVE_LINES = 1080;
LINES_F0 = 1125;
LINES_F1 = 1125;
FRONT_PORCH = 176;
HSYNC_PIXELS = 88;
BACK_PORCH = 296;
EOF_LINES = 4;
VSYNC_LINES = 5;
SOF_LINES = 36;
TOTAL_FRAMES = 0;
break;
case HDMI_3840x1080p100hz:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = 3840;
ACTIVE_LINES = 1080;
LINES_F0 = 1125;
LINES_F1 = 1125;
FRONT_PORCH = 1056;
HSYNC_PIXELS = 88;
BACK_PORCH = 296;
EOF_LINES = 4;
VSYNC_LINES = 5;
SOF_LINES = 36;
TOTAL_FRAMES = 0;
break;
case HDMI_3840x540p240hz:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = 3840;
ACTIVE_LINES = 1080;
LINES_F0 = 562;
LINES_F1 = 562;
FRONT_PORCH = 176;
HSYNC_PIXELS = 88;
BACK_PORCH = 296;
EOF_LINES = 2;
VSYNC_LINES = 2;
SOF_LINES = 18;
TOTAL_FRAMES = 0;
break;
case HDMI_3840x540p200hz:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = 3840;
ACTIVE_LINES = 1080;
LINES_F0 = 562;
LINES_F1 = 562;
FRONT_PORCH = 1056;
HSYNC_PIXELS = 88;
BACK_PORCH = 296;
EOF_LINES = 2;
VSYNC_LINES = 2;
SOF_LINES = 18;
TOTAL_FRAMES = 0;
break;
case HDMI_480p60:
case HDMI_480p60_16x9:
case HDMI_480p60_16x9_rpt:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (720*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (480/(1+INTERLACE_MODE));
LINES_F0 = 525;
LINES_F1 = 525;
FRONT_PORCH = 16;
HSYNC_PIXELS = 62;
BACK_PORCH = 60;
EOF_LINES = 9;
VSYNC_LINES = 6;
SOF_LINES = 30;
TOTAL_FRAMES = 4;
break;
case HDMI_576p50:
case HDMI_576p50_16x9:
case HDMI_576p50_16x9_rpt:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (720*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (576/(1+INTERLACE_MODE));
LINES_F0 = 625;
LINES_F1 = 625;
FRONT_PORCH = 12;
HSYNC_PIXELS = 64;
BACK_PORCH = 68;
EOF_LINES = 5;
VSYNC_LINES = 5;
SOF_LINES = 39;
TOTAL_FRAMES = 4;
break;
case HDMI_720p60:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (1280*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (720/(1+INTERLACE_MODE));
LINES_F0 = 750;
LINES_F1 = 750;
FRONT_PORCH = 110;
HSYNC_PIXELS = 40;
BACK_PORCH = 220;
EOF_LINES = 5;
VSYNC_LINES = 5;
SOF_LINES = 20;
TOTAL_FRAMES = 4;
break;
case HDMI_720p50:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (1280*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (720/(1+INTERLACE_MODE));
LINES_F0 = 750;
LINES_F1 = 750;
FRONT_PORCH = 440;
HSYNC_PIXELS = 40;
BACK_PORCH = 220;
EOF_LINES = 5;
VSYNC_LINES = 5;
SOF_LINES = 20;
TOTAL_FRAMES = 4;
break;
case HDMI_1080p50:
case HDMI_1080p25:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (1920*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (1080/(1+INTERLACE_MODE));
LINES_F0 = 1125;
LINES_F1 = 1125;
FRONT_PORCH = 528;
HSYNC_PIXELS = 44;
BACK_PORCH = 148;
EOF_LINES = 4;
VSYNC_LINES = 5;
SOF_LINES = 36;
TOTAL_FRAMES = 4;
break;
case HDMI_1080p24:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (1920*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (1080/(1+INTERLACE_MODE));
LINES_F0 = 1125;
LINES_F1 = 1125;
FRONT_PORCH = 638;
HSYNC_PIXELS = 44;
BACK_PORCH = 148;
EOF_LINES = 4;
VSYNC_LINES = 5;
SOF_LINES = 36;
TOTAL_FRAMES = 4;
break;
case HDMI_1080p60:
case HDMI_1080p30:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = (1920*(1+PIXEL_REPEAT_HDMI));
ACTIVE_LINES = (1080/(1+INTERLACE_MODE));
LINES_F0 = 1125;
LINES_F1 = 1125;
FRONT_PORCH = 88;
HSYNC_PIXELS = 44;
BACK_PORCH = 148;
EOF_LINES = 4;
VSYNC_LINES = 5;
SOF_LINES = 36;
TOTAL_FRAMES = 4;
break;
case HDMI_2560x1080p50_64x27:
case HDMI_2560x1080p60_64x27:
INTERLACE_MODE = 0U;
PIXEL_REPEAT_VENC = 0;
PIXEL_REPEAT_HDMI = 0;
ACTIVE_PIXELS = hdmi_encp_timing->h_active;
ACTIVE_LINES = hdmi_encp_timing->v_active;
LINES_F0 = hdmi_encp_timing->v_total;
LINES_F1 = hdmi_encp_timing->v_total;
FRONT_PORCH = hdmi_encp_timing->h_front;
HSYNC_PIXELS = hdmi_encp_timing->h_sync;
BACK_PORCH = hdmi_encp_timing->h_back;
EOF_LINES = hdmi_encp_timing->v_front;
VSYNC_LINES = hdmi_encp_timing->v_sync;
SOF_LINES = hdmi_encp_timing->v_back;
TOTAL_FRAMES = 4;
break;
default:
break;
}
TOTAL_PIXELS = (FRONT_PORCH+HSYNC_PIXELS+BACK_PORCH+ACTIVE_PIXELS);
TOTAL_LINES = (LINES_F0+(LINES_F1*INTERLACE_MODE));
total_pixels_venc = (TOTAL_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
active_pixels_venc = (ACTIVE_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
front_porch_venc = (FRONT_PORCH / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
hsync_pixels_venc = (HSYNC_PIXELS / (1+PIXEL_REPEAT_HDMI)) *
(1+PIXEL_REPEAT_VENC);
hd_write_reg(P_ENCP_VIDEO_MODE, hd_read_reg(P_ENCP_VIDEO_MODE)|(1<<14));
/* Program DE timing */
de_h_begin = modulo(hd_read_reg(P_ENCP_VIDEO_HAVON_BEGIN) +
VFIFO2VD_TO_HDMI_LATENCY, total_pixels_venc);
de_h_end = modulo(de_h_begin + active_pixels_venc, total_pixels_venc);
hd_write_reg(P_ENCP_DE_H_BEGIN, de_h_begin); /* 220 */
hd_write_reg(P_ENCP_DE_H_END, de_h_end); /* 1660 */
/* Program DE timing for even field */
de_v_begin_even = hd_read_reg(P_ENCP_VIDEO_VAVON_BLINE);
de_v_end_even = de_v_begin_even + ACTIVE_LINES;
hd_write_reg(P_ENCP_DE_V_BEGIN_EVEN, de_v_begin_even);
hd_write_reg(P_ENCP_DE_V_END_EVEN, de_v_end_even); /* 522 */
/* Program Hsync timing */
if (de_h_end + front_porch_venc >= total_pixels_venc) {
hs_begin = de_h_end + front_porch_venc - total_pixels_venc;
vs_adjust = 1;
} else {
hs_begin = de_h_end + front_porch_venc;
vs_adjust = 0;
}
hs_end = modulo(hs_begin + hsync_pixels_venc, total_pixels_venc);
hd_write_reg(P_ENCP_DVI_HSO_BEGIN, hs_begin);
hd_write_reg(P_ENCP_DVI_HSO_END, hs_end);
/* Program Vsync timing for even field */
if (de_v_begin_even >= SOF_LINES + VSYNC_LINES + (1-vs_adjust))
vs_bline_evn = de_v_begin_even - SOF_LINES - VSYNC_LINES -
(1-vs_adjust);
else
vs_bline_evn = TOTAL_LINES + de_v_begin_even - SOF_LINES -
VSYNC_LINES - (1-vs_adjust);
vs_eline_evn = modulo(vs_bline_evn + VSYNC_LINES, TOTAL_LINES);
hd_write_reg(P_ENCP_DVI_VSO_BLINE_EVN, vs_bline_evn); /* 5 */
hd_write_reg(P_ENCP_DVI_VSO_ELINE_EVN, vs_eline_evn); /* 11 */
vso_begin_evn = hs_begin; /* 1692 */
hd_write_reg(P_ENCP_DVI_VSO_BEGIN_EVN, vso_begin_evn); /* 1692 */
hd_write_reg(P_ENCP_DVI_VSO_END_EVN, vso_begin_evn); /* 1692 */
if ((param->VIC == HDMI_3840x540p240hz) ||
(param->VIC == HDMI_3840x540p200hz))
hd_write_reg(P_ENCP_DE_V_END_EVEN, 0x230);
switch (param->VIC) {
case HDMI_3840x1080p120hz:
case HDMI_3840x1080p100hz:
case HDMI_3840x540p240hz:
case HDMI_3840x540p200hz:
hd_write_reg(P_VPU_HDMI_SETTING, 0x8e);
break;
case HDMI_480i60:
case HDMI_480i60_16x9:
case HDMI_576i50:
case HDMI_576i50_16x9:
case HDMI_480i60_16x9_rpt:
case HDMI_576i50_16x9_rpt:
hd_write_reg(P_VPU_HDMI_SETTING, (0 << 0) |
(0 << 1) |
(0 << 2) |
(0 << 3) |
(0 << 4) |
(4 << 5) |
(1 << 8) |
(1 << 12)
);
if ((param->VIC == HDMI_480i60_16x9_rpt) ||
(param->VIC == HDMI_576i50_16x9_rpt))
hd_set_reg_bits(P_VPU_HDMI_SETTING, 3, 12, 4);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 0, 1);
break;
case HDMI_1080i60:
case HDMI_1080i50:
hd_write_reg(P_VPU_HDMI_SETTING, (0 << 0) |
(0 << 1) |
(HSYNC_POLARITY << 2) |
(VSYNC_POLARITY << 3) |
(0 << 4) |
(0 << 5) |
(0 << 8) |
(0 << 12)
);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 1, 1);
break;
case HDMI_4k2k_30:
case HDMI_4k2k_25:
case HDMI_4k2k_24:
case HDMI_4k2k_smpte_24:
case HDMI_4096x2160p25_256x135:
case HDMI_4096x2160p30_256x135:
case HDMI_4096x2160p50_256x135:
case HDMI_4096x2160p60_256x135:
case HDMI_4096x2160p50_256x135_Y420:
case HDMI_4096x2160p60_256x135_Y420:
case HDMI_3840x2160p50_16x9:
case HDMI_3840x2160p60_16x9:
case HDMI_3840x2160p50_16x9_Y420:
case HDMI_3840x2160p60_16x9_Y420:
hd_write_reg(P_VPU_HDMI_SETTING, (0 << 0) |
(0 << 1) |
(HSYNC_POLARITY << 2) |
(VSYNC_POLARITY << 3) |
(0 << 4) |
(4 << 5) |
(0 << 8) |
(0 << 12)
);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 1, 1);
hd_write_reg(P_ENCP_VIDEO_EN, 1); /* Enable VENC */
break;
case HDMI_480p60_16x9_rpt:
case HDMI_576p50_16x9_rpt:
case HDMI_480p60:
case HDMI_480p60_16x9:
case HDMI_576p50:
case HDMI_576p50_16x9:
hd_write_reg(P_VPU_HDMI_SETTING, (0 << 0) |
(0 << 1) |
(0 << 2) |
(0 << 3) |
(0 << 4) |
(4 << 5) |
(0 << 8) |
(0 << 12)
);
if ((param->VIC == HDMI_480p60_16x9_rpt) ||
(param->VIC == HDMI_576p50_16x9_rpt))
hd_set_reg_bits(P_VPU_HDMI_SETTING, 3, 12, 4);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 1, 1);
break;
case HDMI_720p60:
case HDMI_720p50:
hd_write_reg(P_VPU_HDMI_SETTING, (0 << 0) |
(0 << 1) |
(HSYNC_POLARITY << 2) |
(VSYNC_POLARITY << 3) |
(0 << 4) |
(4 << 5) |
(0 << 8) |
(0 << 12)
);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 1, 1);
break;
default:
hd_write_reg(P_VPU_HDMI_SETTING, (0 << 0) |
(0 << 1) | /* [ 1] src_sel_encp */
(HSYNC_POLARITY << 2) |
(VSYNC_POLARITY << 3) |
(0 << 4) |
(4 << 5) |
(0 << 8) |
(0 << 12)
);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 1, 1);
}
if ((param->VIC == HDMI_480p60_16x9_rpt) ||
(param->VIC == HDMI_576p50_16x9_rpt))
hd_set_reg_bits(P_VPU_HDMI_SETTING, 3, 12, 4);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 1, 1);
}
}
void phy_pll_off(void)
{
hdmi_phy_suspend();
}
/************************************
* hdmitx hardware level interface
*************************************/
static void hdmitx_set_pll(struct hdmitx_dev *hdev)
{
hdmitx_set_clk(hdev);
}
static void set_phy_by_mode(unsigned int mode)
{
struct hdmitx_dev *hdev = get_hdmitx_device();
switch (hdev->chip_type) {
case MESON_CPU_ID_G12A:
case MESON_CPU_ID_G12B:
case MESON_CPU_ID_SM1:
switch (mode) {
case 1: /* 5.94/4.5/3.7Gbps */
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x37eb65c4);
if (hdev->dongle_mode)
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x37eb5584);
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
hd_write_reg(P_HHI_HDMI_PHY_CNTL5, 0x0000080b);
break;
case 2: /* 2.97Gbps */
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x33eb6262);
if (hdev->dongle_mode)
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x33eb4262);
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
hd_write_reg(P_HHI_HDMI_PHY_CNTL5, 0x00000003);
break;
case 3: /* 1.485Gbps, and below */
default:
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x33eb4242);
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
hd_write_reg(P_HHI_HDMI_PHY_CNTL5, 0x00000003);
break;
}
break;
case MESON_CPU_ID_M8B:
case MESON_CPU_ID_GXBB:
case MESON_CPU_ID_GXTVBB:
/* other than GXL */
switch (mode) {
case 1: /* 5.94Gbps, 3.7125Gbsp */
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x33353245);
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x2100115b);
break;
case 2: /* 2.97Gbps */
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x33634283);
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0xb000115b);
break;
case 3: /* 1.485Gbps, and below */
default:
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x33632122);
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x2000115b);
break;
}
break;
case MESON_CPU_ID_GXL:
case MESON_CPU_ID_GXM:
case MESON_CPU_ID_TXL:
case MESON_CPU_ID_TXLX:
case MESON_CPU_ID_AXG:
case MESON_CPU_ID_GXLX:
case MESON_CPU_ID_TXHD:
default:
switch (mode) {
case 1: /* 5.94Gbps, 3.7125Gbsp */
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x333d3282);
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x2136315b);
break;
case 2: /* 2.97Gbps */
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x33303382);
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x2036315b);
break;
case 3: /* 1.485Gbps */
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x33303042);
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x2016315b);
break;
default: /* 742.5Mbps, and below */
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x33604132);
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x0016315b);
break;
}
break;
}
}
static void hdmitx_set_phy(struct hdmitx_dev *hdev)
{
if (!hdev)
return;
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x0);
/* P_HHI_HDMI_PHY_CNTL1 bit[1]: enable clock bit[0]: soft reset */
#define RESET_HDMI_PHY() \
do { \
hd_set_reg_bits(P_HHI_HDMI_PHY_CNTL1, 0xf, 0, 4); \
mdelay(2); \
hd_set_reg_bits(P_HHI_HDMI_PHY_CNTL1, 0xe, 0, 4); \
mdelay(2); \
} while (0)
hd_set_reg_bits(P_HHI_HDMI_PHY_CNTL1, 0x0390, 16, 16);
hd_set_reg_bits(P_HHI_HDMI_PHY_CNTL1, 0x1, 17, 1);
if (hdev->chip_type >= MESON_CPU_ID_GXL)
hd_set_reg_bits(P_HHI_HDMI_PHY_CNTL1, 0x0, 17, 1);
hd_set_reg_bits(P_HHI_HDMI_PHY_CNTL1, 0x0, 0, 4);
msleep(100);
RESET_HDMI_PHY();
RESET_HDMI_PHY();
RESET_HDMI_PHY();
#undef RESET_HDMI_PHY
switch (hdev->cur_VIC) {
case HDMI_4k2k_24:
case HDMI_4k2k_25:
case HDMI_4k2k_30:
case HDMI_4k2k_smpte_24:
case HDMI_4096x2160p25_256x135:
case HDMI_4096x2160p30_256x135:
if ((hdev->para->cs == COLORSPACE_YUV422)
|| (hdev->para->cd == COLORDEPTH_24B))
set_phy_by_mode(2);
else
set_phy_by_mode(1);
break;
case HDMI_3840x2160p50_16x9:
case HDMI_3840x2160p60_16x9:
case HDMI_4096x2160p50_256x135:
case HDMI_4096x2160p60_256x135:
if (hdev->para->cs == COLORSPACE_YUV420)
set_phy_by_mode(2);
else
set_phy_by_mode(1);
break;
case HDMI_3840x2160p50_16x9_Y420:
case HDMI_3840x2160p60_16x9_Y420:
case HDMI_4096x2160p50_256x135_Y420:
case HDMI_4096x2160p60_256x135_Y420:
if (hdev->para->cd == COLORDEPTH_24B)
set_phy_by_mode(2);
else
set_phy_by_mode(1);
break;
case HDMI_1080p60:
case HDMI_1080p50:
if (hdev->flag_3dfp)
set_phy_by_mode(2);
else
set_phy_by_mode(3);
break;
default:
if (hdev->flag_3dfp)
set_phy_by_mode(3);
else
set_phy_by_mode(4);
break;
}
}
static void set_tmds_clk_div40(unsigned int div40)
{
pr_info(HW "div40: %d\n", div40);
if (div40) {
hdmitx_wr_reg(HDMITX_TOP_TMDS_CLK_PTTN_01, 0);
hdmitx_wr_reg(HDMITX_TOP_TMDS_CLK_PTTN_23, 0x03ff03ff);
} else {
hdmitx_wr_reg(HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f);
hdmitx_wr_reg(HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f);
}
hdmitx_set_reg_bits(HDMITX_DWC_FC_SCRAMBLER_CTRL, !!div40, 0, 1);
hdmitx_wr_reg(HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
msleep(20);
hdmitx_wr_reg(HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2);
}
static void hdmitx_set_scdc(struct hdmitx_dev *hdev)
{
switch (hdev->cur_video_param->VIC) {
case HDMI_3840x2160p50_16x9:
case HDMI_3840x2160p60_16x9:
case HDMI_4096x2160p50_256x135:
case HDMI_4096x2160p60_256x135:
if ((hdev->para->cs == COLORSPACE_YUV420)
&& (hdev->para->cd == COLORDEPTH_24B))
hdev->para->tmds_clk_div40 = 0;
else
hdev->para->tmds_clk_div40 = 1;
break;
case HDMI_3840x2160p50_16x9_Y420:
case HDMI_3840x2160p60_16x9_Y420:
case HDMI_4096x2160p50_256x135_Y420:
case HDMI_4096x2160p60_256x135_Y420:
case HDMI_3840x2160p50_64x27_Y420:
case HDMI_3840x2160p60_64x27_Y420:
if (hdev->para->cd == COLORDEPTH_24B)
hdev->para->tmds_clk_div40 = 0;
else
hdev->para->tmds_clk_div40 = 1;
break;
case HDMI_3840x2160p24_16x9:
case HDMI_3840x2160p24_64x27:
case HDMI_4096x2160p24_256x135:
case HDMI_3840x2160p25_16x9:
case HDMI_3840x2160p25_64x27:
case HDMI_4096x2160p25_256x135:
case HDMI_3840x2160p30_16x9:
case HDMI_3840x2160p30_64x27:
case HDMI_4096x2160p30_256x135:
if ((hdev->para->cs == COLORSPACE_YUV422)
|| (hdev->para->cd == COLORDEPTH_24B))
hdev->para->tmds_clk_div40 = 0;
else
hdev->para->tmds_clk_div40 = 1;
break;
case HDMIV_2560x1600p60hz:
hdev->para->tmds_clk_div40 = 0;
break;
default:
hdev->para->tmds_clk_div40 = 0;
break;
}
set_tmds_clk_div40(hdev->para->tmds_clk_div40);
scdc_config(hdev);
}
void hdmitx_set_enc_hw(struct hdmitx_dev *hdev)
{
if (hdev->para->hdmitx_vinfo.viu_mux == VIU_MUX_ENCI)
hdmitx_set_vclk2_enci(hdev);
set_vmode_enc_hw(hdev);
if (hdev->flag_3dfp) {
hd_write_reg(P_VPU_HDMI_SETTING, 0x8e);
} else {
switch (hdev->cur_video_param->VIC) {
case HDMI_480i60:
case HDMI_480i60_16x9:
case HDMI_576i50:
case HDMI_576i50_16x9:
case HDMI_480i60_16x9_rpt:
case HDMI_576i50_16x9_rpt:
hdmi_tvenc480i_set(hdev->cur_video_param);
break;
case HDMI_1080i60:
case HDMI_1080i50:
hdmi_tvenc1080i_set(hdev->cur_video_param);
break;
case HDMI_4k2k_30:
case HDMI_4k2k_25:
case HDMI_4k2k_24:
case HDMI_4k2k_smpte_24:
case HDMI_4096x2160p25_256x135:
case HDMI_4096x2160p30_256x135:
case HDMI_4096x2160p50_256x135:
case HDMI_4096x2160p60_256x135:
case HDMI_3840x2160p50_16x9:
case HDMI_3840x2160p60_16x9:
case HDMI_3840x2160p50_16x9_Y420:
case HDMI_3840x2160p60_16x9_Y420:
case HDMI_4096x2160p50_256x135_Y420:
case HDMI_4096x2160p60_256x135_Y420:
hdmi_tvenc4k2k_set(hdev->cur_video_param);
break;
default:
hdmi_tvenc_set(hdev->cur_video_param);
}
}
/* [ 3: 2] chroma_dnsmp. 0=use pixel 0; 1=use pixel 1; 2=use average. */
/* [ 5] hdmi_dith_md: random noise selector. */
hd_write_reg(P_VPU_HDMI_FMT_CTRL, (((TX_INPUT_COLOR_FORMAT ==
COLORSPACE_YUV420) ? 2 : 0) << 0) | (2 << 2) |
(0 << 4) | /* [4]dith_en: disable dithering */
(0 << 5) |
(0 << 6)); /* [ 9: 6] hdmi_dith10_cntl. */
if (hdev->para->cs == COLORSPACE_YUV420) {
hd_set_reg_bits(P_VPU_HDMI_FMT_CTRL, 2, 0, 2);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 0, 4, 4);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 1, 8, 1);
}
if (hdev->para->cs == COLORSPACE_YUV422) {
hd_set_reg_bits(P_VPU_HDMI_FMT_CTRL, 1, 0, 2);
hd_set_reg_bits(P_VPU_HDMI_SETTING, 0, 4, 4);
}
switch (hdev->para->cd) {
case COLORDEPTH_30B:
case COLORDEPTH_36B:
case COLORDEPTH_48B:
if (hdev->chip_type >= MESON_CPU_ID_GXM) {
unsigned int hs_flag = 0;
/* 12-10 dithering on */
hd_set_reg_bits(P_VPU_HDMI_FMT_CTRL, 0, 4, 1);
/* hsync/vsync not invert */
hs_flag = (hd_read_reg(P_VPU_HDMI_SETTING) >> 2) & 0x3;
hd_set_reg_bits(P_VPU_HDMI_SETTING, 0, 2, 2);
/* 12-10 rounding off */
hd_set_reg_bits(P_VPU_HDMI_FMT_CTRL, 0, 10, 1);
/* 10-8 dithering off (2x2 old dither) */
hd_set_reg_bits(P_VPU_HDMI_DITH_CNTL, 0, 4, 1);
/* set hsync/vsync */
hd_set_reg_bits(P_VPU_HDMI_DITH_CNTL, hs_flag, 2, 2);
} else {
hd_set_reg_bits(P_VPU_HDMI_FMT_CTRL, 0, 4, 1);
hd_set_reg_bits(P_VPU_HDMI_FMT_CTRL, 0, 10, 1);
}
break;
default:
if (hdev->chip_type >= MESON_CPU_ID_GXM) {
/* 12-10 dithering off */
hd_set_reg_bits(P_VPU_HDMI_FMT_CTRL, 0, 4, 1);
/* 12-10 rounding on */
hd_set_reg_bits(P_VPU_HDMI_FMT_CTRL, 1, 10, 1);
/* 10-8 dithering on (2x2 old dither) */
hd_set_reg_bits(P_VPU_HDMI_DITH_CNTL, 1, 4, 1);
/* set hsync/vsync as default 0 */
hd_set_reg_bits(P_VPU_HDMI_DITH_CNTL, 0, 2, 2);
} else {
hd_set_reg_bits(P_VPU_HDMI_FMT_CTRL, 0, 4, 1);
hd_set_reg_bits(P_VPU_HDMI_FMT_CTRL, 1, 10, 1);
}
break;
}
switch (hdev->cur_video_param->VIC) {
case HDMI_480i60:
case HDMI_480i60_16x9:
case HDMI_576i50:
case HDMI_576i50_16x9:
case HDMI_480i60_16x9_rpt:
case HDMI_576i50_16x9_rpt:
enc_vpu_bridge_reset(0);
break;
default:
enc_vpu_bridge_reset(1);
break;
}
}
static int hdmitx_set_dispmode(struct hdmitx_dev *hdev)
{
if (hdev->cur_video_param == NULL) /* disable HDMI */
return 0;
if (!hdmitx_edid_VIC_support(hdev->cur_video_param->VIC))
return -1;
hdev->cur_VIC = hdev->cur_video_param->VIC;
hdmitx_set_scdc(hdev);
hdmitx_set_pll(hdev);
hdmitx_set_enc_hw(hdev);
hdmitx_set_hw(hdev);
/* For 3D, enable phy by SystemControl at last step */
if ((!hdev->flag_3dfp) && (!hdev->flag_3dtb) && (!hdev->flag_3dss))
hdmitx_set_phy(hdev);
return 0;
}
static void hdmitx_set_packet(int type, unsigned char *DB, unsigned char *HB)
{
int i;
int pkt_data_len = 0;
switch (type) {
case HDMI_PACKET_AVI:
break;
case HDMI_PACKET_VEND:
if ((!DB) || (!HB)) {
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO0, 0, 3, 1);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDSIZE, 0x0);
return;
}
hdmitx_wr_reg(HDMITX_DWC_FC_VSDIEEEID0, DB[0]);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDIEEEID1, DB[1]);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDIEEEID2, DB[2]);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD0, DB[3]);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDSIZE, HB[2]);
if (DB[3] == 0x20) { /* set HDMI VIC */
hdmitx_wr_reg(HDMITX_DWC_FC_AVIVID, 0);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD1, DB[4]);
}
if (DB[3] == 0x40) { /* 3D VSI */
hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD1, DB[4]);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD2, DB[5]);
if ((DB[4] >> 4) == T3D_FRAME_PACKING)
hdmitx_wr_reg(HDMITX_DWC_FC_VSDSIZE, 5);
else
hdmitx_wr_reg(HDMITX_DWC_FC_VSDSIZE, 6);
}
if (HB[2] == 0x1b) {/*set dolby vsif data information*/
hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD1, DB[4]);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD2, DB[5]);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD3, DB[6]);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD4, DB[7]);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD5, DB[8]);
}
/*set hdr 10+ vsif data information*/
if ((DB[0] == 0x8b) && (DB[1] == 0x84) && (DB[2] == 0x90)) {
for (i = 0; i < 23; i++)
hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD1 + i,
DB[4 + i]);
}
/* Enable VSI packet */
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO0, 1, 3, 1);
hdmitx_wr_reg(HDMITX_DWC_FC_DATAUTO1, 0);
hdmitx_wr_reg(HDMITX_DWC_FC_DATAUTO2, 0x10);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 4, 1);
break;
case HDMI_PACKET_DRM:
pkt_data_len = 26;
if ((!DB) || (!HB)) {
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO3, 0, 6, 1);
hdmitx_set_reg_bits(
HDMITX_DWC_FC_PACKET_TX_EN, 0, 7, 1);
return;
}
/* Ignore HB[0] */
hdmitx_wr_reg(HDMITX_DWC_FC_DRM_HB01, HB[1]);
hdmitx_wr_reg(HDMITX_DWC_FC_DRM_HB02, HB[2]);
for (i = 0; i < pkt_data_len; i++)
hdmitx_wr_reg(HDMITX_DWC_FC_DRM_PB00 + i, DB[i]);
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO3, 1, 6, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 7, 1);
break;
case HDMI_AUDIO_INFO:
pkt_data_len = 9;
break;
case HDMI_SOURCE_DESCRIPTION:
pkt_data_len = 25;
for (i = 0; i < 25; i++)
hdmitx_wr_reg(HDMITX_DWC_FC_SPDVENDORNAME0 + i, DB[i]);
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO0, 1, 4, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO2, 0x1, 4, 4);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 4, 1);
break;
default:
break;
}
}
static void hdmitx_set_datapacket(int type, unsigned char *DB,
unsigned char *HB)
{
int i;
#if 0
pr_info("HB: %02x %02x %02x\nDB:", HB[0], HB[1], HB[2]);
for (i = 0; (i < 24) && (i < HB[2]); i++)
pr_info(" %02x", DB[i]);
pr_info("\n");
#endif
switch (type) {
case HDMI_PACKET_VEND:
if ((!DB) || (!HB)) {
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO0, 0, 3, 1);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDSIZE, 0x0);
return;
}
hdmitx_wr_reg(HDMITX_DWC_FC_VSDSIZE, HB[2]);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDIEEEID0, DB[0]);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDIEEEID1, DB[1]);
hdmitx_wr_reg(HDMITX_DWC_FC_VSDIEEEID2, DB[2]);
for (i = 0; (i < 24) && (i < HB[2]); i++)
hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD0 + i, DB[3 + i]);
/* Enable VSI packet */
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO0, 1, 3, 1);
hdmitx_wr_reg(HDMITX_DWC_FC_DATAUTO1, 0);
hdmitx_wr_reg(HDMITX_DWC_FC_DATAUTO2, 0x10);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 4, 1);
break;
default:
break;
}
}
static void hdmitx_setaudioinfoframe(unsigned char *AUD_DB,
unsigned char *CHAN_STAT_BUF)
{
}
/* set_hdmi_audio_source(unsigned int src) */
/* Description: */
/* Select HDMI audio clock source, and I2S input data source. */
/* Parameters: */
/* src -- 0=no audio clock to HDMI; 1=pcmout to HDMI; 2=Aiu I2S out to HDMI. */
static void set_hdmi_audio_source(unsigned int src)
{
unsigned long data32;
/* Disable HDMI audio clock input and its I2S input */
data32 = 0;
data32 |= (0 << 4);
data32 |= (0 << 0);
hd_write_reg(P_AIU_HDMI_CLK_DATA_CTRL, data32);
/* Enable HDMI I2S input from the selected source */
data32 = 0;
data32 |= (src << 4);
data32 |= (src << 0);
hd_write_reg(P_AIU_HDMI_CLK_DATA_CTRL, data32);
} /* set_hdmi_audio_source */
/* 60958-3 bit 27-24 */
static unsigned char aud_csb_sampfreq[FS_MAX + 1] = {
[FS_REFER_TO_STREAM] = 0x1, /* not indicated */
[FS_32K] = 0x3, /* FS_32K */
[FS_44K1] = 0x0, /* FS_44K1 */
[FS_48K] = 0x2, /* FS_48K */
[FS_88K2] = 0x8, /* FS_88K2 */
[FS_96K] = 0xa, /* FS_96K */
[FS_176K4] = 0xc, /* FS_176K4 */
[FS_192K] = 0xe, /* FS_192K */
[FS_768K] = 0x9, /* FS_768K */
};
/* 60958-3 bit 39:36 */
static unsigned char aud_csb_ori_sampfreq[FS_MAX + 1] = {
[FS_REFER_TO_STREAM] = 0x0, /* not indicated */
[FS_32K] = 0xc, /* FS_32K */
[FS_44K1] = 0xf, /* FS_44K1 */
[FS_48K] = 0xd, /* FS_48K */
[FS_88K2] = 0x7, /* FS_88K2 */
[FS_96K] = 0xa, /* FS_96K */
[FS_176K4] = 0x3, /* FS_176K4 */
[FS_192K] = 0x1, /* FS_192K */
};
static void set_aud_chnls(struct hdmitx_dev *hdev,
struct hdmitx_audpara *audio_param)
{
int i;
pr_info(HW "set channel status\n");
for (i = 0; i < 9; i++)
/* First, set all status to 0 */
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS0+i, 0x00);
/* set default 48k 2ch pcm */
if ((audio_param->type == CT_PCM) &&
(audio_param->channel_num == (2 - 1))) {
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSV, 0x11);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS7, 0x02);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS8, 0xd2);
} else {
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSV, 0xff);
}
switch (audio_param->type) {
case CT_AC_3:
case CT_DOLBY_D:
case CT_DST:
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS3, 0x01); /* CSB 20 */
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS5, 0x02); /* CSB 21 */
break;
default:
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS3, 0x00);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS5, 0x00);
break;
}
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS7,
aud_csb_sampfreq[audio_param->sample_rate], 0, 4); /*CSB 27:24*/
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS7, 0x0, 6, 2); /*CSB 31:30*/
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS7, 0x0, 4, 2); /*CSB 29:28*/
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS8, 0x2, 0, 4); /*CSB 35:32*/
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS8, /* CSB 39:36 */
aud_csb_ori_sampfreq[audio_param->sample_rate], 4, 4);
}
#define GET_OUTCHN_NO(a) (((a) >> 4) & 0xf)
#define GET_OUTCHN_MSK(a) ((a) & 0xf)
static void set_aud_info_pkt(struct hdmitx_dev *hdev,
struct hdmitx_audpara *audio_param)
{
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF0, 0, 0, 4); /* CT */
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF0, audio_param->channel_num,
4, 3); /* CC */
if (GET_OUTCHN_NO(hdev->aud_output_ch))
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF0,
GET_OUTCHN_NO(hdev->aud_output_ch) - 1, 4, 3);
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF1, 0, 0, 3); /* SF */
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF1, 0, 4, 2); /* SS */
switch (audio_param->type) {
case CT_MAT:
case CT_DTS_HD_MA:
/* CC: 8ch */
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF0, 7, 4, 3);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF2, 0x13);
break;
case CT_PCM:
if (!hdev->aud_output_ch)
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF0,
audio_param->channel_num, 4, 3);
if ((audio_param->channel_num == 0x7) && (!hdev->aud_output_ch))
hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF2, 0x13);
else
hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF2, 0x00);
/* Refer to CEA861-D P90 */
switch (GET_OUTCHN_NO(hdev->aud_output_ch)) {
case 2:
hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF2, 0x00);
break;
case 4:
hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF2, 0x03);
break;
case 6:
hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF2, 0x0b);
break;
case 8:
hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF2, 0x13);
break;
default:
break;
}
break;
case CT_DTS:
case CT_DTS_HD:
default:
/* CC: 2ch */
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF0, 1, 4, 3);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF2, 0x0);
break;
}
hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF3, 0);
}
static void set_aud_acr_pkt(struct hdmitx_dev *hdev,
struct hdmitx_audpara *audio_param)
{
unsigned int data32;
unsigned int aud_n_para;
unsigned int char_rate;
/* audio packetizer config */
hdmitx_wr_reg(HDMITX_DWC_AUD_INPUTCLKFS, hdev->tx_aud_src ? 4 : 0);
if ((audio_param->type == CT_MAT)
|| (audio_param->type == CT_DTS_HD_MA))
hdmitx_wr_reg(HDMITX_DWC_AUD_INPUTCLKFS, 2);
if ((hdev->frac_rate_policy) && (hdev->para->timing.frac_freq))
char_rate = hdev->para->timing.frac_freq;
else
char_rate = hdev->para->timing.pixel_freq;
if (hdev->para->cs == COLORSPACE_YUV422)
aud_n_para = hdmi_get_aud_n_paras(audio_param->sample_rate,
COLORDEPTH_24B, char_rate);
else
aud_n_para = hdmi_get_aud_n_paras(audio_param->sample_rate,
hdev->para->cd, char_rate);
/* N must mutiples 4 for DD+ */
switch (audio_param->type) {
case CT_DOLBY_D:
aud_n_para *= 4;
break;
default:
break;
}
pr_info(HW "aud_n_para = %d\n", aud_n_para);
/* ACR packet configuration */
data32 = 0;
data32 |= (1 << 7); /* [ 7] ncts_atomic_write */
data32 |= (0 << 0); /* [3:0] AudN[19:16] */
hdmitx_wr_reg(HDMITX_DWC_AUD_N3, data32);
data32 = 0;
data32 |= (0 << 7); /* [7:5] N_shift */
data32 |= (0 << 4); /* [ 4] CTS_manual */
data32 |= (0 << 0); /* [3:0] manual AudCTS[19:16] */
hdmitx_wr_reg(HDMITX_DWC_AUD_CTS3, data32);
hdmitx_wr_reg(HDMITX_DWC_AUD_CTS2, 0); /* manual AudCTS[15:8] */
hdmitx_wr_reg(HDMITX_DWC_AUD_CTS1, 0); /* manual AudCTS[7:0] */
data32 = 0;
data32 |= (1 << 7); /* [ 7] ncts_atomic_write */
data32 |= (((aud_n_para>>16)&0xf) << 0); /* [3:0] AudN[19:16] */
hdmitx_wr_reg(HDMITX_DWC_AUD_N3, data32);
hdmitx_wr_reg(HDMITX_DWC_AUD_N2, (aud_n_para>>8)&0xff); /* AudN[15:8] */
hdmitx_wr_reg(HDMITX_DWC_AUD_N1, aud_n_para&0xff); /* AudN[7:0] */
}
static void set_aud_fifo_rst(void)
{
/* reset audio fifo */
hdmitx_set_reg_bits(HDMITX_DWC_AUD_CONF0, 1, 7, 1);
hdmitx_set_reg_bits(HDMITX_DWC_AUD_CONF0, 0, 7, 1);
hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF0, 1, 7, 1);
hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF0, 0, 7, 1);
hdmitx_wr_reg(HDMITX_DWC_MC_SWRSTZREQ, 0xe7);
/* need reset again */
hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF0, 1, 7, 1);
hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF0, 0, 7, 1);
}
static void set_aud_samp_pkt(struct hdmitx_dev *hdev,
struct hdmitx_audpara *audio_param)
{
switch (audio_param->type) {
case CT_MAT: /* HBR */
case CT_DTS_HD_MA:
hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF1, 1, 7, 1);
hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF1, 1, 6, 1);
hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF1, 24, 0, 5);
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCONF, 1, 0, 1);
break;
case CT_PCM: /* AudSamp */
hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF1, 0, 7, 1);
hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF1, 0, 6, 1);
hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF1, 24, 0, 5);
if ((audio_param->channel_num == 0x7) && (!hdev->aud_output_ch))
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCONF, 1, 0, 1);
else
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCONF, 0, 0, 1);
switch (GET_OUTCHN_NO(hdev->aud_output_ch)) {
case 2:
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCONF, 0, 0, 1);
break;
case 4:
case 6:
case 8:
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCONF, 1, 0, 1);
break;
default:
break;
}
break;
case CT_AC_3:
case CT_DOLBY_D:
case CT_DTS:
case CT_DTS_HD:
default:
hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF1, 0, 7, 1);
hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF1, 0, 6, 1);
hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF1, 24, 0, 5);
hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCONF, 0, 0, 1);
break;
}
}
static int amute_flag = -1;
static void audio_mute_op(bool flag)
{
if (amute_flag != flag)
amute_flag = flag;
else
return;
if (flag == 0) {
hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 0, 2, 2);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 0, 0, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 0, 3, 1);
} else {
hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 3, 2, 2);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 0, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 3, 1);
}
}
static int hdmitx_set_audmode(struct hdmitx_dev *hdev,
struct hdmitx_audpara *audio_param)
{
unsigned int data32;
if (!hdev)
return 0;
if (!audio_param)
return 0;
pr_info(HW "set audio\n");
audio_mute_op(hdev->tx_aud_cfg);
/* PCM & 8 ch */
if ((audio_param->type == CT_PCM) &&
(audio_param->channel_num == (8 - 1)))
hdev->tx_aud_src = 1;
else
hdev->tx_aud_src = 0;
/* if hdev->aud_output_ch is true, select I2S as 8ch in, 2ch out */
if (hdev->aud_output_ch)
hdev->tx_aud_src = 1;
pr_info(HW "hdmitx tx_aud_src = %d\n", hdev->tx_aud_src);
/* set_hdmi_audio_source(tx_aud_src ? 1 : 2); */
set_hdmi_audio_source(2);
/* config IP */
/* Configure audio */
/* I2S Sampler config */
data32 = 0;
/* [ 3] fifo_empty_mask: 0=enable int; 1=mask int. */
data32 |= (1 << 3);
/* [ 2] fifo_full_mask: 0=enable int; 1=mask int. */
data32 |= (1 << 2);
hdmitx_wr_reg(HDMITX_DWC_AUD_INT, data32);
data32 = 0;
/* [ 4] fifo_overrun_mask: 0=enable int; 1=mask int.
* Enable it later when audio starts.
*/
data32 |= (1 << 4);
hdmitx_wr_reg(HDMITX_DWC_AUD_INT1, data32);
/* [ 5] 0=select SPDIF; 1=select I2S. */
data32 = 0;
data32 |= (0 << 7); /* [ 7] sw_audio_fifo_rst */
data32 |= (hdev->tx_aud_src << 5);
data32 |= (0 << 0); /* [3:0] i2s_in_en: enable it later in test.c */
/* if enable it now, fifo_overrun will happen, because packet don't get sent
* out until initial DE detected.
*/
hdmitx_wr_reg(HDMITX_DWC_AUD_CONF0, data32);
data32 = 0;
data32 |= (0 << 5); /* [7:5] i2s_mode: 0=standard I2S mode */
data32 |= (24 << 0); /* [4:0] i2s_width */
hdmitx_wr_reg(HDMITX_DWC_AUD_CONF1, data32);
data32 = 0;
data32 |= (0 << 1); /* [ 1] NLPCM */
data32 |= (0 << 0); /* [ 0] HBR */
hdmitx_wr_reg(HDMITX_DWC_AUD_CONF2, data32);
/* spdif sampler config */
/* [ 2] SPDIF fifo_full_mask: 0=enable int; 1=mask int. */
/* [ 3] SPDIF fifo_empty_mask: 0=enable int; 1=mask int. */
data32 = 0;
data32 |= (1 << 3);
data32 |= (1 << 2);
hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIFINT, data32);
/* [ 4] SPDIF fifo_overrun_mask: 0=enable int; 1=mask int. */
data32 = 0;
data32 |= (0 << 4);
hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIFINT1, data32);
data32 = 0;
data32 |= (0 << 7); /* [ 7] sw_audio_fifo_rst */
hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIF0, data32);
set_aud_info_pkt(hdev, audio_param);
set_aud_acr_pkt(hdev, audio_param);
set_aud_samp_pkt(hdev, audio_param);
set_aud_chnls(hdev, audio_param);
hdmitx_set_reg_bits(HDMITX_DWC_AUD_CONF0, hdev->tx_aud_src, 5, 1);
if (hdev->tx_aud_src == 1) {
if (GET_OUTCHN_MSK(hdev->aud_output_ch))
hdmitx_set_reg_bits(HDMITX_DWC_AUD_CONF0,
GET_OUTCHN_MSK(hdev->aud_output_ch), 0, 4);
else
hdmitx_set_reg_bits(HDMITX_DWC_AUD_CONF0, 0xf, 0, 4);
/* Enable audi2s_fifo_overrun interrupt */
hdmitx_wr_reg(HDMITX_DWC_AUD_INT1,
hdmitx_rd_reg(HDMITX_DWC_AUD_INT1) & (~(1<<4)));
/* Wait for 40 us for TX I2S decoder to settle */
msleep(20);
}
set_aud_fifo_rst();
udelay(10);
hdmitx_wr_reg(HDMITX_DWC_AUD_N1, hdmitx_rd_reg(HDMITX_DWC_AUD_N1));
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO3, 1, 0, 1);
return 1;
}
static void hdmitx_setupirq(struct hdmitx_dev *phdev)
{
int r;
hdmitx_wr_reg(HDMITX_TOP_INTR_STAT_CLR, 0x7);
r = request_irq(phdev->irq_hpd, &intr_handler,
IRQF_SHARED, "hdmitx",
(void *)phdev);
}
static void hdmitx_uninit(struct hdmitx_dev *phdev)
{
free_irq(phdev->irq_hpd, (void *)phdev);
pr_info(HW "power off hdmi, unmux hpd\n");
phy_pll_off();
hdmitx_hpd_hw_op(HPD_UNMUX_HPD);
}
static void hw_reset_dbg(void)
{
uint32_t val1 = hdmitx_rd_reg(HDMITX_DWC_MC_CLKDIS);
uint32_t val2 = hdmitx_rd_reg(HDMITX_DWC_FC_INVIDCONF);
uint32_t val3 = hdmitx_rd_reg(HDMITX_DWC_FC_VSYNCINWIDTH);
hdmitx_wr_reg(HDMITX_DWC_MC_CLKDIS, 0xff);
udelay(10);
hdmitx_wr_reg(HDMITX_DWC_MC_CLKDIS, val1);
udelay(10);
hdmitx_wr_reg(HDMITX_DWC_MC_SWRSTZREQ, 0);
udelay(10);
hdmitx_wr_reg(HDMITX_DWC_FC_INVIDCONF, 0);
udelay(10);
hdmitx_wr_reg(HDMITX_DWC_FC_INVIDCONF, val2);
udelay(10);
hdmitx_wr_reg(HDMITX_DWC_FC_VSYNCINWIDTH, val3);
}
static int hdmitx_cntl(struct hdmitx_dev *hdev, unsigned int cmd,
unsigned int argv)
{
if (cmd == HDMITX_AVMUTE_CNTL) {
return 0;
} else if (cmd == HDMITX_EARLY_SUSPEND_RESUME_CNTL) {
if (argv == HDMITX_EARLY_SUSPEND) {
/* RESET set as 1, delay 50us, Enable set as 0 */
/* G12A reset/enable bit position is different */
switch (hdev->chip_type) {
case MESON_CPU_ID_G12A:
case MESON_CPU_ID_G12B:
case MESON_CPU_ID_SM1:
hd_set_reg_bits(P_HHI_HDMI_PLL_CNTL, 1, 29, 1);
udelay(50);
hd_set_reg_bits(P_HHI_HDMI_PLL_CNTL, 0, 28, 1);
break;
default:
hd_set_reg_bits(P_HHI_HDMI_PLL_CNTL, 1, 28, 1);
udelay(50);
hd_set_reg_bits(P_HHI_HDMI_PLL_CNTL, 0, 30, 1);
break;
}
hdmi_phy_suspend();
}
if (argv == HDMITX_LATE_RESUME) {
/* No need below, will be set at set_disp_mode_auto() */
/* hd_set_reg_bits(P_HHI_HDMI_PLL_CNTL, 1, 30, 1); */
hw_reset_dbg();
pr_info(HW "swrstzreq\n");
}
return 0;
} else if (cmd == HDMITX_HWCMD_MUX_HPD_IF_PIN_HIGH) {
/* turnon digital module if gpio is high */
if (hdmitx_hpd_hw_op(HPD_IS_HPD_MUXED) == 0) {
if (hdmitx_hpd_hw_op(HPD_READ_HPD_GPIO)) {
msleep(500);
if (hdmitx_hpd_hw_op(HPD_READ_HPD_GPIO)) {
pr_info(HPD "mux hpd\n");
hdmitx_set_sys_clk(hdev, 4);
mdelay(100);
hdmitx_hpd_hw_op(HPD_MUX_HPD);
}
}
}
} else if (cmd == HDMITX_HWCMD_MUX_HPD)
hdmitx_hpd_hw_op(HPD_MUX_HPD);
/* For test only. */
else if (cmd == HDMITX_HWCMD_TURNOFF_HDMIHW) {
int unmux_hpd_flag = argv;
if (unmux_hpd_flag) {
pr_info(HW "power off hdmi, unmux hpd\n");
phy_pll_off();
hdmitx_hpd_hw_op(HPD_UNMUX_HPD);
} else {
pr_info(HW "power off hdmi\n");
hdmitx_set_sys_clk(hdev, 6);
phy_pll_off();
}
}
return 0;
}
static void hdmitx_print_info(struct hdmitx_dev *hdev, int pr_info_flag)
{
pr_info(HW "------------------\nHdmitx driver version: ");
pr_info(HW "%s\n", HDMITX_VER);
pr_info(HW "%spowerdown when unplug\n",
hdev->unplug_powerdown?"":"do not ");
pr_info("------------------\n");
}
struct aud_cts_log {
unsigned int val:20;
};
static inline unsigned int get_msr_cts(void)
{
unsigned int ret = 0;
ret = hdmitx_rd_reg(HDMITX_DWC_AUD_CTS1);
ret += (hdmitx_rd_reg(HDMITX_DWC_AUD_CTS2) << 8);
ret += ((hdmitx_rd_reg(HDMITX_DWC_AUD_CTS3) & 0xf) << 16);
return ret;
}
#define AUD_CTS_LOG_NUM 1000
struct aud_cts_log cts_buf[AUD_CTS_LOG_NUM];
static void cts_test(struct hdmitx_dev *hdev)
{
int i;
unsigned int min = 0, max = 0, total = 0;
pr_info("\nhdmitx: audio: cts test\n");
memset(cts_buf, 0, sizeof(cts_buf));
for (i = 0; i < AUD_CTS_LOG_NUM; i++) {
cts_buf[i].val = get_msr_cts();
mdelay(1);
}
pr_info("\ncts change:\n");
for (i = 1; i < AUD_CTS_LOG_NUM; i++) {
if (cts_buf[i].val > cts_buf[i-1].val)
pr_info("dis: +%d [%d] %d [%d] %d\n",
cts_buf[i].val - cts_buf[i-1].val, i,
cts_buf[i].val, i - 1, cts_buf[i - 1].val);
if (cts_buf[i].val < cts_buf[i-1].val)
pr_info("dis: %d [%d] %d [%d] %d\n",
cts_buf[i].val - cts_buf[i-1].val, i,
cts_buf[i].val, i - 1, cts_buf[i - 1].val);
}
for (i = 0, min = max = cts_buf[0].val; i < AUD_CTS_LOG_NUM; i++) {
total += cts_buf[i].val;
if (min > cts_buf[i].val)
min = cts_buf[i].val;
if (max < cts_buf[i].val)
max = cts_buf[i].val;
}
pr_info("\nCTS Min: %d Max: %d Avg: %d/1000\n\n", min, max, total);
}
void hdmitx_dump_inter_timing(void)
{
unsigned int tmp = 0;
#define CONNECT2REG(reg) ((hdmitx_rd_reg(reg)) + (hdmitx_rd_reg(reg + 1) << 8))
tmp = CONNECT2REG(HDMITX_DWC_FC_INHACTV0);
pr_info("Hactive = %d\n", tmp);
tmp = CONNECT2REG(HDMITX_DWC_FC_INHBLANK0);
pr_info("Hblank = %d\n", tmp);
tmp = CONNECT2REG(HDMITX_DWC_FC_INVACTV0);
pr_info("Vactive = %d\n", tmp);
tmp = hdmitx_rd_reg(HDMITX_DWC_FC_INVBLANK);
pr_info("Vblank = %d\n", tmp);
tmp = CONNECT2REG(HDMITX_DWC_FC_HSYNCINDELAY0);
pr_info("Hfront = %d\n", tmp);
tmp = CONNECT2REG(HDMITX_DWC_FC_HSYNCINWIDTH0);
pr_info("Hsync = %d\n", tmp);
tmp = hdmitx_rd_reg(HDMITX_DWC_FC_VSYNCINDELAY);
pr_info("Vfront = %d\n", tmp);
tmp = hdmitx_rd_reg(HDMITX_DWC_FC_VSYNCINWIDTH);
pr_info("Vsync = %d\n", tmp);
/* HDMITX_DWC_FC_INFREQ0 ??? */
}
#define DUMP_CVREG_SECTION(start, end) \
do { \
if (start > end) { \
pr_info("Error start = 0x%x > end = 0x%x\n", \
((start & 0xffff) >> 2), ((end & 0xffff) >> 2)); \
break; \
} \
pr_info("Start = 0x%x[0x%x] End = 0x%x[0x%x]\n", \
start, ((start & 0xffff) >> 2), end, ((end & 0xffff) >> 2)); \
for (addr = start; addr < end + 1; addr += 4) { \
val = hd_read_reg(addr); \
if (val) \
pr_info("0x%08x[0x%04x]: 0x%08x\n", addr, \
((addr & 0xffff) >> 2), val); \
} \
} while (0)
#define DUMP_HDMITXREG_SECTION(start, end) \
do { \
if (start > end) { \
pr_info("Error start = 0x%lx > end = 0x%lx\n", start, end); \
break; \
} \
pr_info("Start = 0x%lx End = 0x%lx\n", start, end); \
for (addr = start; addr < end + 1; addr++) { \
val = hdmitx_rd_reg(addr); \
if (val) \
pr_info("[0x%08x]: 0x%08x\n", addr, val); \
} \
} while (0)
static void hdmitx_dump_intr(void)
{
unsigned int addr = 0, val = 0;
DUMP_HDMITXREG_SECTION(HDMITX_DWC_IH_FC_STAT0, HDMITX_DWC_IH_MUTE);
}
static void mode420_half_horizontal_para(void)
{
unsigned int hactive = 0;
unsigned int hblank = 0;
unsigned int hfront = 0;
unsigned int hsync = 0;
hactive = hdmitx_rd_reg(HDMITX_DWC_FC_INHACTV0);
hactive += (hdmitx_rd_reg(HDMITX_DWC_FC_INHACTV1) & 0x3f) << 8;
hblank = hdmitx_rd_reg(HDMITX_DWC_FC_INHBLANK0);
hblank += (hdmitx_rd_reg(HDMITX_DWC_FC_INHBLANK1) & 0x1f) << 8;
hfront = hdmitx_rd_reg(HDMITX_DWC_FC_HSYNCINDELAY0);
hfront += (hdmitx_rd_reg(HDMITX_DWC_FC_HSYNCINDELAY1) & 0x1f) << 8;
hsync = hdmitx_rd_reg(HDMITX_DWC_FC_HSYNCINWIDTH0);
hsync += (hdmitx_rd_reg(HDMITX_DWC_FC_HSYNCINWIDTH1) & 0x3) << 8;
hactive = hactive / 2;
hblank = hblank / 2;
hfront = hfront / 2;
hsync = hsync / 2;
hdmitx_wr_reg(HDMITX_DWC_FC_INHACTV0, (hactive & 0xff));
hdmitx_wr_reg(HDMITX_DWC_FC_INHACTV1, ((hactive >> 8) & 0x3f));
hdmitx_wr_reg(HDMITX_DWC_FC_INHBLANK0, (hblank & 0xff));
hdmitx_wr_reg(HDMITX_DWC_FC_INHBLANK1, ((hblank >> 8) & 0x1f));
hdmitx_wr_reg(HDMITX_DWC_FC_HSYNCINDELAY0, (hfront & 0xff));
hdmitx_wr_reg(HDMITX_DWC_FC_HSYNCINDELAY1, ((hfront >> 8) & 0x1f));
hdmitx_wr_reg(HDMITX_DWC_FC_HSYNCINWIDTH0, (hsync & 0xff));
hdmitx_wr_reg(HDMITX_DWC_FC_HSYNCINWIDTH1, ((hsync >> 8) & 0x3));
}
static void hdmitx_set_fake_vic(struct hdmitx_dev *hdev)
{
hdev->para->cs = COLORSPACE_YUV444;
hdev->cur_VIC = HDMI_VIC_FAKE;
set_vmode_clk(hdev);
}
static void hdmitx_dump_drm_reg(void)
{
unsigned int reg_val;
unsigned int reg_addr;
unsigned char *conf;
pr_info("hdmitx drm info reg config\n");
reg_addr = HDMITX_DWC_FC_DRM_HB01;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("DRM.version: %d\n", reg_val);
reg_addr = HDMITX_DWC_FC_DRM_HB02;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("DRM.size: %d\n", reg_val);
reg_addr = HDMITX_DWC_FC_DRM_PB00;
reg_val = hdmitx_rd_reg(reg_addr);
switch (reg_val) {
case 0:
conf = "sdr";
break;
case 1:
conf = "hdr";
break;
case 2:
conf = "ST 2084";
break;
case 3:
conf = "HLG";
break;
default:
conf = "sdr";
}
pr_info("DRM.eotf: %s\n", conf);
reg_addr = HDMITX_DWC_FC_DRM_PB01;
reg_val = hdmitx_rd_reg(reg_addr);
switch (reg_val) {
case 0:
conf = "static metadata";
break;
default:
conf = "reserved";
}
pr_info("DRM.metadata_id: %s\n", conf);
for (reg_addr = HDMITX_DWC_FC_DRM_PB02;
reg_addr <= HDMITX_DWC_FC_DRM_PB26; reg_addr++) {
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("[0x%x]: 0x%x\n", reg_addr, reg_val);
}
reg_addr = HDMITX_DWC_FC_DATAUTO3;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0x40) >> 6) {
case 0:
conf = "RDRB";
break;
case 1:
default:
conf = "auto";
}
pr_info("DRM.mode : %s\n", conf);
reg_addr = HDMITX_DWC_FC_PACKET_TX_EN;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0x80) >> 7) {
case 0:
conf = "disable";
break;
case 1:
default:
conf = "enable";
}
pr_info("DRM.enable : %s\n", conf);
}
static void hdmitx_dump_vsif_reg(void)
{
unsigned int reg_val;
unsigned int reg_addr;
unsigned char *conf;
pr_info("hdmitx vsif info reg config\n");
reg_addr = HDMITX_DWC_FC_VSDSIZE;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("VSIF.size: %d\n", reg_val);
reg_addr = HDMITX_DWC_FC_VSDIEEEID0;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("VSIF.IEEEID0: 0x%x\n", reg_val);
reg_addr = HDMITX_DWC_FC_VSDIEEEID1;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("VSIF.IEEEID1: 0x%x\n", reg_val);
reg_addr = HDMITX_DWC_FC_VSDIEEEID2;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("VSIF.IEEEID2: 0x%x\n", reg_val);
for (reg_addr = HDMITX_DWC_FC_VSDPAYLOAD0;
reg_addr <= HDMITX_DWC_FC_VSDPAYLOAD23; reg_addr++) {
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("[0x%x]: 0x%x\n", reg_addr, reg_val);
}
reg_addr = HDMITX_DWC_FC_DATAUTO0;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0x8) >> 3) {
case 0:
conf = "manual";
break;
case 1:
default:
conf = "RDRB";
}
pr_info("VSIF.mode : %s\n", conf);
reg_addr = HDMITX_DWC_FC_DATAUTO1;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("VSIF.rdrb_interpolation : %d\n", reg_val & 0xf);
reg_addr = HDMITX_DWC_FC_DATAUTO2;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("VSIF.rdrb_perframe : %d\n", (reg_val & 0xf0) >> 4);
pr_info("VSIF.rdrb_linespace : %d\n", reg_val & 0xf);
reg_addr = HDMITX_DWC_FC_PACKET_TX_EN;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0x10) >> 4) {
case 0:
conf = "disable";
break;
case 1:
default:
conf = "enable";
}
pr_info("VSIF.enable : %s\n", conf);
}
static void hdmitx_dump_avi_reg(void)
{
unsigned int reg_val;
unsigned int reg_addr;
unsigned char *conf;
pr_info("hdmitx avi info reg config\n");
reg_addr = HDMITX_DWC_FC_AVICONF0;
reg_val = hdmitx_rd_reg(reg_addr);
switch (reg_val & 0x3) {
case 0:
conf = "RGB";
break;
case 1:
conf = "422";
break;
case 2:
conf = "444";
break;
case 3:
conf = "420";
}
pr_info("AVI.colorspace: %s\n", conf);
switch ((reg_val & 0x40) >> 6) {
case 0:
conf = "disable";
break;
case 1:
conf = "enable";
}
pr_info("AVI.active_aspect: %s\n", conf);
switch ((reg_val & 0x0c) >> 2) {
case 0:
conf = "disable";
break;
case 1:
conf = "vert bar";
break;
case 2:
conf = "horiz bar";
break;
case 3:
conf = "vert and horiz bar";
}
pr_info("AVI.bar: %s\n", conf);
switch ((reg_val & 0x30) >> 4) {
case 0:
conf = "disable";
break;
case 1:
conf = "overscan";
break;
case 2:
conf = "underscan";
break;
default:
conf = "disable";
}
pr_info("AVI.scan: %s\n", conf);
reg_addr = HDMITX_DWC_FC_AVICONF1;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0xc0) >> 6) {
case 0:
conf = "disable";
break;
case 1:
conf = "BT.601";
break;
case 2:
conf = "BT.709";
break;
case 3:
conf = "Extended";
}
pr_info("AVI.colorimetry: %s\n", conf);
switch ((reg_val & 0x30) >> 4) {
case 0:
conf = "disable";
break;
case 1:
conf = "4:3";
break;
case 2:
conf = "16:9";
break;
default:
conf = "disable";
}
pr_info("AVI.picture_aspect: %s\n", conf);
switch (reg_val & 0xf) {
case 8:
conf = "Same as picture_aspect";
break;
case 9:
conf = "4:3";
break;
case 10:
conf = "16:9";
break;
case 11:
conf = "14:9";
break;
default:
conf = "Same as picture_aspect";
}
pr_info("AVI.active_aspect: %s\n", conf);
reg_addr = HDMITX_DWC_FC_AVICONF2;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0x80) >> 7) {
case 0:
conf = "disable";
break;
case 1:
conf = "enable";
}
pr_info("AVI.itc: %s\n", conf);
switch ((reg_val & 0x70) >> 4) {
case 0:
conf = "xvYCC601";
break;
case 1:
conf = "xvYCC709";
break;
case 2:
conf = "sYCC601";
break;
case 3:
conf = "Adobe_YCC601";
break;
case 4:
conf = "Adobe_RGB";
break;
case 5:
case 6:
conf = "BT.2020";
break;
default:
conf = "xvYCC601";
}
pr_info("AVI.extended_colorimetriy: %s\n", conf);
switch ((reg_val & 0xc) >> 2) {
case 0:
conf = "default";
break;
case 1:
conf = "limited";
break;
case 2:
conf = "full";
break;
default:
conf = "default";
}
pr_info("AVI.quantization_range: %s\n", conf);
switch (reg_val & 0x3) {
case 0:
conf = "unknown";
break;
case 1:
conf = "horiz";
break;
case 2:
conf = "vert";
break;
case 3:
conf = "horiz and vert";
}
pr_info("AVI.nups: %s\n", conf);
reg_addr = HDMITX_DWC_FC_AVIVID;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("AVI.video_code: %d\n", reg_val);
reg_addr = HDMITX_DWC_FC_AVICONF3;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0xc) >> 2) {
case 0:
default:
conf = "limited";
break;
case 1:
conf = "full";
}
pr_info("AVI.ycc_quantization_range: %s\n", conf);
switch (reg_val & 0x3) {
case 0:
conf = "graphics";
break;
case 1:
conf = "photo";
break;
case 2:
conf = "cinema";
break;
case 3:
conf = "game";
}
pr_info("AVI.content_type: %s\n", conf);
reg_addr = HDMITX_DWC_FC_PRCONF;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0xf0) >> 4) {
case 0:
case 1:
default:
conf = "no";
break;
case 2:
conf = "2 times";
}
pr_info("AVI.pixel_repetition: %s\n", conf);
reg_addr = HDMITX_DWC_FC_DATAUTO3;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0x8) >> 3) {
case 0:
conf = "RDRB";
break;
case 1:
conf = "auto";
}
pr_info("AVI.mode : %s\n", conf);
reg_addr = HDMITX_DWC_FC_RDRB6;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("AVI.rdrb_interpolation : %d\n", reg_val & 0xf);
reg_addr = HDMITX_DWC_FC_RDRB7;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("AVI.rdrb_perframe : %d\n", (reg_val & 0xf0) >> 4);
pr_info("AVI.rdrb_linespace : %d\n", reg_val & 0xf);
reg_addr = HDMITX_DWC_FC_PACKET_TX_EN;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0x4) >> 2) {
case 0:
conf = "disable";
break;
case 1:
conf = "enable";
}
pr_info("AVI.enable : %s\n", conf);
}
static void hdmitx_dump_gcp(void)
{
unsigned int reg_val;
unsigned int reg_addr;
unsigned char *conf;
pr_info("hdmitx gcp reg config\n");
reg_addr = HDMITX_DWC_FC_GCP;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("GCP.clear_avmute: %d\n", reg_val & 0x1);
pr_info("GCP.set_avmute: %d\n", (reg_val & 0x2) >> 1);
pr_info("GCP.default_phase: %d\n", (reg_val & 0x4) >> 2);
reg_addr = HDMITX_DWC_VP_STATUS;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("GCP.packing_phase: %d\n", reg_val & 0xf);
reg_addr = HDMITX_DWC_VP_PR_CD;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0xf0) >> 4) {
case 0:
case 4:
conf = "24bit";
break;
case 5:
conf = "30bit";
break;
case 6:
conf = "36bit";
break;
case 7:
conf = "48bit";
break;
default:
conf = "reserved";
}
pr_info("GCP.color_depth: %s\n", conf);
reg_addr = HDMITX_DWC_VP_REMAP;
reg_val = hdmitx_rd_reg(reg_addr);
switch (reg_val & 0x3) {
case 0:
conf = "16bit";
break;
case 1:
conf = "20bit";
break;
case 2:
conf = "24bit";
break;
default:
conf = "reserved";
}
pr_info("YCC 422 size: %s\n", conf);
reg_addr = HDMITX_DWC_VP_CONF;
reg_val = hdmitx_rd_reg(reg_addr);
switch (reg_val & 0x3) {
case 0:
conf = "pixel_packing";
break;
case 1:
conf = "YCC 422";
break;
case 2:
case 3:
conf = "8bit bypass";
}
pr_info("output selector: %s\n", conf);
pr_info("bypass select: %d\n", (reg_val & 0x4) >> 2);
pr_info("YCC 422 enable: %d\n", (reg_val & 0x8) >> 3);
pr_info("pixel repeater enable: %d\n", (reg_val & 0x10) >> 4);
pr_info("pixel packing enable: %d\n", (reg_val & 0x20) >> 5);
pr_info("bypass enable: %d\n", (reg_val & 0x40) >> 6);
reg_addr = HDMITX_DWC_FC_DATAUTO3;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0x4) >> 2) {
case 0:
conf = "RDRB";
break;
case 1:
conf = "auto";
}
pr_info("GCP.mode : %s\n", conf);
reg_addr = HDMITX_DWC_FC_PACKET_TX_EN;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0x2) >> 1) {
case 0:
conf = "disable";
break;
case 1:
conf = "enable";
}
pr_info("GCP.enable : %s\n", conf);
}
static void hdmitx_dump_audio_info(void)
{
unsigned int reg_val;
unsigned int reg_addr;
unsigned char *conf;
pr_info("hdmitx audio info reg config\n");
reg_addr = HDMITX_DWC_FC_AUDICONF0;
reg_val = hdmitx_rd_reg(reg_addr);
switch (reg_val & 0xf) {
case CT_REFER_TO_STREAM:
conf = "refer to stream header";
break;
case CT_PCM:
conf = "L-PCM";
break;
case CT_AC_3:
conf = "AC-3";
break;
case CT_MPEG1:
conf = "MPEG1";
break;
case CT_MP3:
conf = "MP3";
break;
case CT_MPEG2:
conf = "MPEG2";
break;
case CT_AAC:
conf = "AAC";
break;
case CT_DTS:
conf = "DTS";
break;
case CT_ATRAC:
conf = "ATRAC";
break;
case CT_ONE_BIT_AUDIO:
conf = "One Bit Audio";
break;
case CT_DOLBY_D:
conf = "Dobly Digital+";
break;
case CT_DTS_HD:
conf = "DTS_HD";
break;
case CT_MAT:
conf = "MAT";
break;
case CT_DST:
conf = "DST";
break;
case CT_WMA:
conf = "WMA";
break;
default:
conf = "MAX";
}
pr_info("AUDI.coding_type: %s\n", conf);
switch ((reg_val & 0x70) >> 4) {
case CC_REFER_TO_STREAM:
conf = "refer to stream header";
break;
case CC_2CH:
conf = "2 channels";
break;
case CC_3CH:
conf = "3 channels";
break;
case CC_4CH:
conf = "4 channels";
break;
case CC_5CH:
conf = "5 channels";
break;
case CC_6CH:
conf = "6 channels";
break;
case CC_7CH:
conf = "7 channels";
break;
case CC_8CH:
conf = "8 channels";
break;
default:
conf = "MAX";
}
pr_info("AUDI.channel_count: %s\n", conf);
reg_addr = HDMITX_DWC_FC_AUDICONF1;
reg_val = hdmitx_rd_reg(reg_addr);
switch (reg_val & 0x7) {
case FS_REFER_TO_STREAM:
conf = "refer to stream header";
break;
case FS_32K:
conf = "32kHz";
break;
case FS_44K1:
conf = "44.1kHz";
break;
case FS_48K:
conf = "48kHz";
break;
case FS_88K2:
conf = "88.2kHz";
break;
case FS_96K:
conf = "96kHz";
break;
case FS_176K4:
conf = "176.4kHz";
break;
case FS_192K:
conf = "192kHz";
}
pr_info("AUDI.sample_frequency: %s\n", conf);
switch ((reg_val & 0x30) >> 4) {
case SS_REFER_TO_STREAM:
conf = "refer to stream header";
break;
case SS_16BITS:
conf = "16bit";
break;
case SS_20BITS:
conf = "20bit";
break;
case SS_24BITS:
conf = "24bit";
break;
default:
conf = "MAX";
}
pr_info("AUDI.sample_size: %s\n", conf);
reg_addr = HDMITX_DWC_FC_AUDICONF2;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("AUDI.channel_allocation: %d\n", reg_val);
reg_addr = HDMITX_DWC_FC_AUDICONF3;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("AUDI.level_shift_value: %d\n", reg_val & 0xf);
pr_info("AUDI.down_mix_enable: %d\n", (reg_val & 0x10) >> 4);
pr_info("AUDI.LFE_playback_info: %d\n", (reg_val & 0x60) >> 5);
reg_addr = HDMITX_DWC_FC_DATAUTO3;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0x2) >> 1) {
case 0:
conf = "RDRB";
break;
case 1:
conf = "auto";
}
pr_info("AUDI.mode : %s\n", conf);
reg_addr = HDMITX_DWC_FC_PACKET_TX_EN;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0x8) >> 3) {
case 0:
conf = "disable";
break;
case 1:
conf = "enable";
}
pr_info("AUDI.enable : %s\n", conf);
}
static void hdmitx_dump_acr_info(void)
{
unsigned int reg_val;
unsigned int reg_addr;
unsigned char *conf;
pr_info("hdmitx audio acr info reg config\n");
reg_addr = HDMITX_DWC_AUD_INPUTCLKFS;
reg_val = hdmitx_rd_reg(reg_addr);
switch (reg_val & 0x7) {
case 0:
conf = "128XFs";
break;
case 1:
conf = "512XFs";
break;
case 4:
conf = "64XFs";
break;
default:
conf = "reserved";
}
pr_info("ACR.ifsfactor: %s\n", conf);
reg_addr = HDMITX_DWC_AUD_N1;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("ACR.N[7:0]: 0x%x\n", reg_val);
reg_addr = HDMITX_DWC_AUD_N2;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("ACR.N[15:8]: 0x%x\n", reg_val);
reg_addr = HDMITX_DWC_AUD_N3;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("ACR.N[19:16]: 0x%x\n", reg_val & 0xf);
pr_info("ACR.ncts_atomic_write: %d\n", (reg_val & 0x80) >> 7);
reg_addr = HDMITX_DWC_AUD_CTS1;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("ACR.CTS[7:0]: 0x%x\n", reg_val);
reg_addr = HDMITX_DWC_AUD_CTS2;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("ACR.CTS[15:8]: 0x%x\n", reg_val);
reg_addr = HDMITX_DWC_AUD_CTS3;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("ACR.CTS[19:16]: 0x%x\n", reg_val & 0xf);
pr_info("ACR.CTS_manual: %d\n", (reg_val & 0x10) >> 4);
switch ((reg_val & 0xe0) >> 5) {
case 0:
conf = "1";
break;
case 1:
conf = "16";
break;
case 2:
conf = "32";
break;
case 3:
conf = "64";
break;
case 4:
conf = "128";
break;
case 5:
conf = "256";
break;
default:
conf = "128";
}
pr_info("ACR.N_shift: %s\n", conf);
pr_info("actual N = audN[19:0]/N_shift\n");
reg_addr = HDMITX_DWC_FC_DATAUTO3;
reg_val = hdmitx_rd_reg(reg_addr);
switch (reg_val & 0x1) {
case 0:
conf = "RDRB";
break;
case 1:
conf = "auto";
}
pr_info("ACR.mode : %s\n", conf);
reg_addr = HDMITX_DWC_FC_PACKET_TX_EN;
reg_val = hdmitx_rd_reg(reg_addr);
switch (reg_val & 0x1) {
case 0:
conf = "disable";
break;
case 1:
conf = "enable";
}
pr_info("ACR.enable : %s\n", conf);
}
static void hdmitx_dump_audio_sample(void)
{
unsigned int reg_val;
unsigned int reg_addr;
unsigned char *conf;
pr_info("hdmitx audio sample reg config\n");
reg_addr = HDMITX_DWC_AUD_CONF0;
reg_val = hdmitx_rd_reg(reg_addr);
switch ((reg_val & 0x20) >> 5) {
case 0:
default:
conf = "SPDIF/GPA";
break;
case 1:
conf = "I2S";
}
pr_info("i2s_select : %s\n", conf);
pr_info("I2S_in_en: %d\n", reg_val & 0xf);
reg_addr = HDMITX_DWC_AUD_CONF1;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("I2S_width: %d bit\n", reg_val & 0x1f);
switch ((reg_val & 0xe0) >> 5) {
case 0:
conf = "standard";
break;
case 1:
conf = "Right-justified";
break;
case 2:
conf = "Left-justified";
break;
case 3:
conf = "Burst 1 mode";
break;
case 4:
conf = "Burst 2 mode";
break;
default:
conf = "standard";
}
pr_info("I2S_mode: %s\n", conf);
reg_addr = HDMITX_DWC_AUD_CONF2;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("HBR mode enable: %d\n", reg_val & 0x1);
pr_info("NLPCM mode enable: %d\n", (reg_val & 0x2) >> 1);
reg_addr = HDMITX_DWC_AUD_SPDIF1;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("SPDIF_width: %d bit\n", reg_val & 0x1f);
pr_info("SPDIF_HBR_MODE: %d\n", (reg_val & 0x40) >> 6);
pr_info("SPDIF_NLPCM_MODE: %d\n", (reg_val & 0x80) >> 7);
reg_addr = HDMITX_DWC_FC_AUDSCONF;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("layout : %d\n", reg_val & 0x1);
pr_info("sample flat: %d\n", (reg_val & 0xf0) >> 4);
reg_addr = HDMITX_DWC_FC_AUDSSTAT;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("sample present : %d\n", reg_val & 0xf);
reg_addr = HDMITX_DWC_FC_AUDSV;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("audio sample validity flag\n");
pr_info("channel 0, Left : %d\n", reg_val & 0x1);
pr_info("channel 1, Left : %d\n", (reg_val & 0x2) >> 1);
pr_info("channel 2, Left : %d\n", (reg_val & 0x4) >> 2);
pr_info("channel 3, Left : %d\n", (reg_val & 0x8) >> 3);
pr_info("channel 0, Right : %d\n", (reg_val & 0x10) >> 4);
pr_info("channel 1, Right : %d\n", (reg_val & 0x20) >> 5);
pr_info("channel 2, Right : %d\n", (reg_val & 0x40) >> 6);
pr_info("channel 3, Right : %d\n", (reg_val & 0x80) >> 7);
reg_addr = HDMITX_DWC_FC_AUDSU;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("audio sample user flag\n");
pr_info("channel 0, Left : %d\n", reg_val & 0x1);
pr_info("channel 1, Left : %d\n", (reg_val & 0x2) >> 1);
pr_info("channel 2, Left : %d\n", (reg_val & 0x4) >> 2);
pr_info("channel 3, Left : %d\n", (reg_val & 0x8) >> 3);
pr_info("channel 0, Right : %d\n", (reg_val & 0x10) >> 4);
pr_info("channel 1, Right : %d\n", (reg_val & 0x20) >> 5);
pr_info("channel 2, Right : %d\n", (reg_val & 0x40) >> 6);
pr_info("channel 3, Right : %d\n", (reg_val & 0x80) >> 7);
}
static void hdmitx_dump_audio_channel_status(void)
{
unsigned int reg_val;
unsigned int reg_addr;
unsigned char *conf;
pr_info("hdmitx audio channel status reg config\n");
reg_addr = HDMITX_DWC_FC_AUDSCHNLS0;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("iec_copyright: %d\n", reg_val & 0x1);
pr_info("iec_cgmsa: %d\n", (reg_val & 0x30) >> 4);
reg_addr = HDMITX_DWC_FC_AUDSCHNLS1;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("iec_categorycode: %d\n", reg_val);
reg_addr = HDMITX_DWC_FC_AUDSCHNLS2;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("iec_sourcenumber: %d\n", reg_val & 0xf);
pr_info("iec_pcmaudiomode: %d\n", (reg_val & 0x30) >> 4);
reg_addr = HDMITX_DWC_FC_AUDSCHNLS3;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("iec_channelnumcr0: %d\n", reg_val & 0xf);
pr_info("iec_channelnumcr1: %d\n", (reg_val & 0xf0) >> 4);
reg_addr = HDMITX_DWC_FC_AUDSCHNLS4;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("iec_channelnumcr2: %d\n", reg_val & 0xf);
pr_info("iec_channelnumcr3: %d\n", (reg_val & 0xf0) >> 4);
reg_addr = HDMITX_DWC_FC_AUDSCHNLS5;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("iec_channelnumcl0: %d\n", reg_val & 0xf);
pr_info("iec_channelnumcl1: %d\n", (reg_val & 0xf0) >> 4);
reg_addr = HDMITX_DWC_FC_AUDSCHNLS6;
reg_val = hdmitx_rd_reg(reg_addr);
pr_info("iec_channelnumcl2: %d\n", reg_val & 0xf);
pr_info("iec_channelnumcl3: %d\n", (reg_val & 0xf0) >> 4);
reg_addr = HDMITX_DWC_FC_AUDSCHNLS7;
reg_val = hdmitx_rd_reg(reg_addr);
switch (reg_val & 0xf) {
case 0:
conf = "44.1kHz";
break;
case 1:
conf = "not indicated";
break;
case 2:
conf = "48kHz";
break;
case 3:
conf = "32kHz";
break;
case 8:
conf = "88.2kHz";
break;
case 9:
conf = "768kHz";
break;
case 10:
conf = "96kHz";
break;
case 12:
conf = "176.4kHz";
break;
case 14:
conf = "192kHz";
break;
default:
conf = "not indicated";
}
pr_info("iec_sampfreq: %s\n", conf);
pr_info("iec_clk: %d\n", (reg_val & 0x30) >> 4);
pr_info("iec_sampfreq_ext: %d\n", (reg_val & 0xc0) >> 6);
reg_addr = HDMITX_DWC_FC_AUDSCHNLS8;
reg_val = hdmitx_rd_reg(reg_addr);
switch (reg_val & 0xf) {
case 0:
case 1:
conf = "not indicated";
break;
case 2:
conf = "16bit";
break;
case 4:
conf = "18bit";
break;
case 8:
conf = "19bit";
break;
case 10:
conf = "20bit";
break;
case 12:
conf = "17bit";
break;
case 3:
conf = "20bit";
break;
case 5:
conf = "22bit";
break;
case 9:
conf = "23bit";
break;
case 11:
conf = "24bit";
break;
case 13:
conf = "21bit";
break;
default:
conf = "not indicated";
}
pr_info("iec_worldlength: %s\n", conf);
switch ((reg_val & 0xf0) >> 4) {
case 0:
conf = "not indicated";
break;
case 1:
conf = "192kHz";
break;
case 3:
conf = "176.4kHz";
break;
case 5:
conf = "96kHz";
break;
case 7:
conf = "88.2kHz";
break;
case 13:
conf = "48kHz";
break;
case 15:
conf = "44.1kHz";
break;
default:
conf = "not indicated";
}
pr_info("iec_origsamplefreq: %s\n", conf);
}
static void hdmitx_debug(struct hdmitx_dev *hdev, const char *buf)
{
char tmpbuf[128];
int i = 0;
int ret;
unsigned long adr = 0;
unsigned long value = 0;
while ((buf[i]) && (buf[i] != ',') && (buf[i] != ' ')) {
tmpbuf[i] = buf[i];
i++;
}
tmpbuf[i] = 0;
if (strncmp(tmpbuf, "testhpll", 8) == 0) {
ret = kstrtoul(tmpbuf + 8, 10, &value);
hdev->cur_VIC = value;
set_vmode_clk(hdev);
return;
} else if (strncmp(tmpbuf, "testedid", 8) == 0) {
hdev->HWOp.CntlDDC(hdev, DDC_RESET_EDID, 0);
hdev->HWOp.CntlDDC(hdev, DDC_EDID_READ_DATA, 0);
return;
} else if (strncmp(tmpbuf, "bist", 4) == 0) {
if (strncmp(tmpbuf + 4, "off", 3) == 0) {
hd_set_reg_bits(P_ENCP_VIDEO_MODE_ADV, 1, 3, 1);
hd_write_reg(P_VENC_VIDEO_TST_EN, 0);
return;
}
hd_set_reg_bits(P_HHI_GCLK_OTHER, 1, 3, 1);
hd_set_reg_bits(P_ENCP_VIDEO_MODE_ADV, 0, 3, 1);
hd_write_reg(P_VENC_VIDEO_TST_EN, 1);
if (strncmp(tmpbuf+4, "line", 4) == 0) {
hd_write_reg(P_VENC_VIDEO_TST_MDSEL, 2);
return;
}
if (strncmp(tmpbuf+4, "dot", 3) == 0) {
hd_write_reg(P_VENC_VIDEO_TST_MDSEL, 3);
return;
}
if (strncmp(tmpbuf+4, "start", 5) == 0) {
ret = kstrtoul(tmpbuf + 9, 10, &value);
hd_write_reg(P_VENC_VIDEO_TST_CLRBAR_STRT, value);
return;
}
if (strncmp(tmpbuf+4, "shift", 5) == 0) {
ret = kstrtoul(tmpbuf + 9, 10, &value);
hd_write_reg(P_VENC_VIDEO_TST_VDCNT_STSET, value);
return;
}
hd_write_reg(P_VENC_VIDEO_TST_MDSEL, 1);
value = 1920;
ret = kstrtoul(tmpbuf + 4, 10, &value);
hd_write_reg(P_VENC_VIDEO_TST_CLRBAR_WIDTH, value / 8);
return;
} else if (strncmp(tmpbuf, "dumptiming", 10) == 0) {
hdmitx_dump_inter_timing();
return;
} else if (strncmp(tmpbuf, "testaudio", 9) == 0) {
hdmitx_set_audmode(hdev, NULL);
} else if (strncmp(tmpbuf, "dumpintr", 8) == 0) {
hdmitx_dump_intr();
} else if (strncmp(tmpbuf, "testhdcp", 8) == 0) {
int i;
i = tmpbuf[8] - '0';
if (i == 2)
pr_info("hdcp rslt = %d", hdmitx_hdcp_opr(2));
if (i == 1)
hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP, HDCP14_ON);
return;
} else if (strncmp(tmpbuf, "chkfmt", 6) == 0) {
check_detail_fmt();
return;
} else if (strncmp(tmpbuf, "testcts", 7) == 0) {
cts_test(hdev);
return;
} else if (strncmp(tmpbuf, "ss", 2) == 0) {
pr_info("hdev->output_blank_flag: 0x%x\n",
hdev->output_blank_flag);
pr_info("hdev->hpd_state: 0x%x\n", hdev->hpd_state);
pr_info("hdev->cur_VIC: 0x%x\n", hdev->cur_VIC);
} else if (strncmp(tmpbuf, "hpd_lock", 8) == 0) {
if (tmpbuf[8] == '1') {
hdev->hpd_lock = 1;
pr_info(HPD "hdmitx: lock hpd\n");
} else {
hdev->hpd_lock = 0;
pr_info(HPD "hdmitx: unlock hpd\n");
}
return;
} else if (strncmp(tmpbuf, "hpd_stick", 9) == 0) {
if (tmpbuf[9] == '1')
hdev->hdcp_hpd_stick = 1;
else
hdev->hdcp_hpd_stick = 0;
pr_info(HPD "hdmitx: %sstick hpd\n",
(hdev->hdcp_hpd_stick) ? "" : "un");
} else if (strncmp(tmpbuf, "vic", 3) == 0) {
pr_info(HW "hdmi vic count = %d\n", hdev->vic_count);
if ((tmpbuf[3] >= '0') && (tmpbuf[3] <= '9')) {
hdev->vic_count = tmpbuf[3] - '0';
pr_info(HW "set hdmi vic count = %d\n",
hdev->vic_count);
}
} else if (strncmp(tmpbuf, "topo", 4) == 0) {
pr_info("topo: %d\n", hdmitx_hdcp_opr(0xe));
return;
} else if (strncmp(tmpbuf, "dumphdmireg", 11) == 0) {
unsigned char reg_val = 0;
unsigned int reg_adr = 0;
#define DUMP_HDMITX_SECTION(a, b) \
for (reg_adr = a; reg_adr < b+1; reg_adr++) { \
reg_val = hdmitx_rd_reg(reg_adr); \
if (reg_val) \
pr_info("[0x%x]: 0x%x\n", reg_adr, reg_val); \
}
#define DUMP_HDMITX_HDCP_SECTION(a, b) \
for (reg_adr = a; reg_adr < b+1; reg_adr++) { \
hdmitx_wr_reg(HDMITX_DWC_A_KSVMEMCTRL, 0x1); \
hdmitx_poll_reg(HDMITX_DWC_A_KSVMEMCTRL, (1<<1), 2 * HZ); \
reg_val = hdmitx_rd_reg(reg_adr); \
if (reg_val) \
pr_info("[0x%x]: 0x%x\n", reg_adr, reg_val); \
}
DUMP_HDMITX_SECTION(HDMITX_TOP_SW_RESET,
HDMITX_TOP_DONT_TOUCH1);
DUMP_HDMITX_SECTION(HDMITX_TOP_SKP_CNTL_STAT,
HDMITX_TOP_SEC_SCRATCH);
DUMP_HDMITX_SECTION(HDMITX_DWC_DESIGN_ID,
HDMITX_DWC_A_KSVMEMCTRL);
DUMP_HDMITX_HDCP_SECTION(HDMITX_DWC_HDCP_BSTATUS_0,
HDMITX_DWC_HDCP_REVOC_LIST_END);
DUMP_HDMITX_HDCP_SECTION(HDMITX_DWC_HDCPREG_BKSV0,
HDMITX_DWC_HDCPREG_BKSV4);
DUMP_HDMITX_SECTION(HDMITX_DWC_HDCPREG_ANCONF,
HDMITX_DWC_HDCP22REG_MUTE);
DUMP_HDMITX_SECTION(HDMITX_DWC_A_HDCPCFG0,
HDMITX_DWC_A_HDCPCFG1);
DUMP_HDMITX_SECTION(HDMITX_DWC_HDCPREG_SEED0,
HDMITX_DWC_HDCPREG_DPK6);
DUMP_HDMITX_SECTION(HDMITX_DWC_HDCP22REG_CTRL,
HDMITX_DWC_HDCP22REG_CTRL);
return;
} else if (strncmp(tmpbuf, "dumpcecreg", 10) == 0) {
unsigned char cec_val = 0;
unsigned int cec_adr = 0;
/* HDMI CEC Regs address range:0xc000~0xc01c;0xc080~0xc094 */
for (cec_adr = 0xc000; cec_adr < 0xc01d; cec_adr++) {
cec_val = hdmitx_rd_reg(cec_adr);
pr_info(CEC "HDMI CEC Regs[0x%x]: 0x%x\n",
cec_adr, cec_val);
}
for (cec_adr = 0xc080; cec_adr < 0xc095; cec_adr++) {
cec_val = hdmitx_rd_reg(cec_adr);
pr_info(CEC "HDMI CEC Regs[0x%x]: 0x%x\n",
cec_adr, cec_val);
}
return;
} else if (strncmp(tmpbuf, "dumpcbusreg", 11) == 0) {
unsigned int i, val;
for (i = 0; i < 0x3000; i++) {
val = hd_read_reg(CBUS_REG_ADDR(i));
if (val)
pr_info("CBUS[0x%x]: 0x%x\n", i, val);
}
return;
} else if (strncmp(tmpbuf, "dumpvcbusreg", 12) == 0) {
unsigned int i, val;
for (i = 0; i < 0x3000; i++) {
val = hd_read_reg(VCBUS_REG_ADDR(i));
if (val)
pr_info("VCBUS[0x%x]: 0x%x\n", i, val);
}
return;
} else if (strncmp(tmpbuf, "log", 3) == 0) {
if (strncmp(tmpbuf+3, "hdcp", 4) == 0) {
static unsigned int i = 1;
if (i & 1)
hdev->log |= HDMI_LOG_HDCP;
else
hdev->log &= ~HDMI_LOG_HDCP;
i++;
}
return;
} else if (strncmp(tmpbuf, "hdmiaudio", 9) == 0) {
ret = kstrtoul(tmpbuf+9, 16, &value);
if (value == 1)
hdev->hdmi_audio_off_flag = 0;
else if (value == 0)
;
return;
} else if (strncmp(tmpbuf, "cfgreg", 6) == 0) {
ret = kstrtoul(tmpbuf+6, 16, &adr);
ret = kstrtoul(buf+i+1, 16, &value);
return;
} else if (tmpbuf[0] == 'v') {
hdmitx_print_info(hdev, 1);
return;
} else if (tmpbuf[0] == 'w') {
unsigned long int read_back = 0;
ret = kstrtoul(tmpbuf+2, 16, &adr);
ret = kstrtoul(buf+i+1, 16, &value);
if (buf[1] == 'h') {
hdmitx_wr_reg((unsigned int)adr, (unsigned int)value);
read_back = hdmitx_rd_reg(adr);
}
pr_info(HW "write %lx to %s reg[%lx]\n", value, "HDMI", adr);
/* read back in order to check writing is OK or NG. */
pr_info(HW "Read Back %s reg[%lx]=%lx\n", "HDMI",
adr, read_back);
} else if (tmpbuf[0] == 'r') {
ret = kstrtoul(tmpbuf+2, 16, &adr);
if (buf[1] == 'h')
value = hdmitx_rd_reg(adr);
pr_info(HW "%s reg[%lx]=%lx\n", "HDMI", adr, value);
} else if (strncmp(tmpbuf, "prbs", 4) == 0) {
switch (hdev->chip_type) {
case MESON_CPU_ID_G12A:
case MESON_CPU_ID_G12B:
case MESON_CPU_ID_SM1:
for (i = 0; i < 4; i++) {
hd_write_reg(P_HHI_HDMI_PHY_CNTL1, 0x0390000f);
hd_write_reg(P_HHI_HDMI_PHY_CNTL1, 0x0390000e);
hd_write_reg(P_HHI_HDMI_PHY_CNTL1, 0x03904002);
hd_write_reg(P_HHI_HDMI_PHY_CNTL4, 0x0001efff
| (i << 20));
hd_write_reg(P_HHI_HDMI_PHY_CNTL1, 0xef904002);
mdelay(10);
if (i > 0)
pr_info("prbs D[%d]:%x\n", i - 1,
hd_read_reg
(P_HHI_HDMI_PHY_STATUS));
else
pr_info("prbs clk :%x\n", hd_read_reg
(P_HHI_HDMI_PHY_STATUS));
}
break;
default:
break;
}
} else if (strncmp(tmpbuf, "hdr_info", 8) == 0) {
pr_info("hdev->hdr_transfer_feature: 0x%x\n",
hdev->hdr_transfer_feature);
pr_info("hdev->hdr_color_feature: 0x%x\n",
hdev->hdr_color_feature);
pr_info("hdev->hdmi_current_hdr_mode: %d\n",
hdev->hdmi_current_hdr_mode);
pr_info("hdev->hdmi_last_hdr_mode: %d\n",
hdev->hdmi_last_hdr_mode);
hdmitx_dump_drm_reg();
return;
} else if (strncmp(tmpbuf, "dv_info", 7) == 0) {
pr_info("hdev->hdmi_current_eotf_type: 0x%x\n",
hdev->hdmi_current_eotf_type);
pr_info("hdev->hdmi_current_tunnel_mode: 0x%x\n",
hdev->hdmi_current_tunnel_mode);
pr_info("hdev->dv_src_feature: %d\n",
hdev->dv_src_feature);
hdmitx_dump_vsif_reg();
return;
} else if (strncmp(tmpbuf, "avi_info", 8) == 0) {
hdmitx_dump_avi_reg();
return;
} else if (strncmp(tmpbuf, "aud_info", 8) == 0) {
hdmitx_dump_audio_info();
return;
} else if (strncmp(tmpbuf, "acr_info", 8) == 0) {
hdmitx_dump_acr_info();
return;
} else if (strncmp(tmpbuf, "aud_sample", 10) == 0) {
hdmitx_dump_audio_sample();
return;
} else if (strncmp(tmpbuf, "aud_chls", 8) == 0) {
hdmitx_dump_audio_channel_status();
return;
} else if (strncmp(tmpbuf, "gcp_info", 8) == 0) {
hdmitx_dump_gcp();
return;
}
}
static void hdmitx_getediddata(unsigned char *des, unsigned char *src)
{
int i = 0;
unsigned int blk = src[126] + 1;
if (blk > 4)
blk = 4;
for (i = 0; i < 128 * blk; i++)
des[i] = src[i];
}
/*
* Note: read 8 Bytes of EDID data every time
*/
static void hdmitx_read_edid(unsigned char *rx_edid)
{
unsigned int timeout = 0;
unsigned int i;
unsigned int byte_num = 0;
unsigned char blk_no = 1;
/* Program SLAVE/ADDR */
hdmitx_wr_reg(HDMITX_DWC_I2CM_SLAVE, 0x50);
/* Read complete EDID data sequentially */
while (byte_num < 128 * blk_no) {
hdmitx_wr_reg(HDMITX_DWC_I2CM_ADDRESS, byte_num&0xff);
if ((byte_num >= 256) && (byte_num < 512) && (blk_no > 2)) {
/* Program SEGMENT/SEGPTR */
hdmitx_wr_reg(HDMITX_DWC_I2CM_SEGADDR, 0x30);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SEGPTR, 0x1);
hdmitx_wr_reg(HDMITX_DWC_I2CM_OPERATION, 1<<3);
} else
hdmitx_wr_reg(HDMITX_DWC_I2CM_OPERATION, 1<<2);
/* Wait until I2C done */
timeout = 0;
while ((!(hdmitx_rd_reg(HDMITX_DWC_IH_I2CM_STAT0) & (1 << 1)))
&& (timeout < 3)) {
mdelay(2);
timeout++;
}
if (timeout == 3)
pr_info(HW "ddc timeout\n");
hdmitx_wr_reg(HDMITX_DWC_IH_I2CM_STAT0, 1 << 1);
/* Read back 8 bytes */
for (i = 0; i < 8; i++) {
rx_edid[byte_num] =
hdmitx_rd_reg(HDMITX_DWC_I2CM_READ_BUFF0 + i);
if (byte_num == 126) {
blk_no = rx_edid[126] + 1;
if (blk_no > 4) {
pr_info(HW "edid extension block number:");
pr_info(HW " %d, reset to MAX 3\n",
blk_no - 1);
blk_no = 4; /* Max extended block */
}
}
byte_num++;
}
}
} /* hdmi20_tx_read_edid */
static int get_hdcp_depth(void)
{
int ret;
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 1, 0, 1);
hdmitx_poll_reg(HDMITX_DWC_A_KSVMEMCTRL, (1<<1), 2 * HZ);
ret = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_1) & 0x7;
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 0, 1);
return ret;
}
static bool get_hdcp_max_cascade(void)
{
bool ret;
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 1, 0, 1);
hdmitx_poll_reg(HDMITX_DWC_A_KSVMEMCTRL, (1<<1), 2 * HZ);
ret = (hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_1) >> 3) & 0x1;
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 0, 1);
return ret;
}
static bool get_hdcp_max_devs(void)
{
bool ret;
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 1, 0, 1);
hdmitx_poll_reg(HDMITX_DWC_A_KSVMEMCTRL, (1<<1), 2 * HZ);
ret = (hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0) >> 7) & 0x1;
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 0, 1);
return ret;
}
static int get_hdcp_device_count(void)
{
int ret;
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 1, 0, 1);
hdmitx_poll_reg(HDMITX_DWC_A_KSVMEMCTRL, (1<<1), 2 * HZ);
ret = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0) & 0x7f;
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 0, 1);
return ret;
}
static void get_hdcp_bstatus(int *ret1, int *ret2)
{
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 1, 0, 1);
hdmitx_poll_reg(HDMITX_DWC_A_KSVMEMCTRL, (1<<1), 2 * HZ);
*ret1 = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0);
*ret2 = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_1);
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 0, 1);
}
static void hdcp_ksv_store(struct hdcprp_topo *topo,
unsigned char *dat, int no)
{
int i;
int pos;
if (!topo)
return;
if (topo->hdcp_ver != 1)
return;
/* must check ksv num to prevent leak */
if (topo->topo.topo14.device_count >= MAX_KSV_LISTS)
return;
pos = topo->topo.topo14.device_count * 5;
for (i = 0; (i < no) && (i < MAX_KSV_LISTS * 5); i++)
topo->topo.topo14.ksv_list[pos++] = dat[i];
topo->topo.topo14.device_count += no / 5;
}
static uint8_t *hdcp_mKsvListBuf;
static int ksv_sha_matched;
static void hdcp_ksv_sha1_calc(struct hdmitx_dev *hdev)
{
size_t list = 0;
size_t size = 0;
size_t i = 0;
int valid = HDCP_NULL;
char temp[MAX_KSV_LISTS * 5];
int j = 0;
/* 0x165e: Page 95 */
memset(&tmp_ksv_lists, 0, sizeof(tmp_ksv_lists));
memset(&temp[0], 0, sizeof(temp));
hdcp_mKsvListBuf = kmalloc(0x1660, GFP_ATOMIC);
if (hdcp_mKsvListBuf) {
/* KSV_SIZE; */
list = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0) & KSV_MASK;
if (list <= MAX_KSV_LISTS) {
size = (list * KSV_SIZE) + HDCP_HEAD + SHA_MAX_SIZE;
for (i = 0; i < size; i++) {
if (i < HDCP_HEAD) { /* BSTATUS & M0 */
hdcp_mKsvListBuf[(list * KSV_SIZE) + i]
= hdmitx_rd_reg(
HDMITX_DWC_HDCP_BSTATUS_0 + i);
} else if (i < (HDCP_HEAD +
(list * KSV_SIZE))) {
/* KSV list */
hdcp_mKsvListBuf[i - HDCP_HEAD] =
hdmitx_rd_reg(
HDMITX_DWC_HDCP_BSTATUS_0 + i);
tmp_ksv_lists.lists[tmp_ksv_lists.no++]
= hdcp_mKsvListBuf[i -
HDCP_HEAD];
temp[j++] =
hdcp_mKsvListBuf[i - HDCP_HEAD];
} else { /* SHA */
hdcp_mKsvListBuf[i] = hdmitx_rd_reg(
HDMITX_DWC_HDCP_BSTATUS_0 + i);
}
}
if (calc_hdcp_ksv_valid(hdcp_mKsvListBuf, size) == TRUE)
valid = HDCP_KSVLIST_VALID;
else
valid = HDCP_KSVLIST_INVALID;
ksv_sha_matched = valid;
}
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 0, 1);
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL,
(valid == HDCP_KSVLIST_VALID) ? 0 : 1, 3, 1);
if (valid == HDCP_KSVLIST_VALID) {
tmp_ksv_lists.valid = 1;
for (i = 0; (i < j) &&
(tmp_ksv_lists.no < MAX_KSV_LISTS * 5); i++)
tmp_ksv_lists.lists[tmp_ksv_lists.no++]
= temp[i];
}
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 1, 2, 1);
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 2, 1);
kfree(hdcp_mKsvListBuf);
} else
pr_info("hdcptx14: KSV List memory not valid\n");
}
static int max_exceed = 200;
MODULE_PARM_DESC(max_exceed, "\nmax_exceed\n");
module_param(max_exceed, int, 0664);
static void hdcptx_events_handle(unsigned long arg)
{
struct hdmitx_dev *hdev = (struct hdmitx_dev *)arg;
unsigned char ksv[5] = {0};
int i;
unsigned int bcaps_6_rp;
static unsigned int bcaps_5_ksvfifoready;
static unsigned int st_flag = -1;
static unsigned int hdcpobs3_1;
unsigned int hdcpobs3_2;
struct hdcprp14_topo *topo14 = &hdev->topo_info->topo.topo14;
int bstatus0 = 0;
int bstatus1 = 0;
if (hdev->hdcp_max_exceed_cnt == 0) {
hdcpobs3_1 = 0;
bcaps_5_ksvfifoready = 0;
}
hdcpobs3_2 = hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS3);
if (hdcpobs3_1 != hdcpobs3_2)
hdcpobs3_1 = hdcpobs3_2;
bcaps_6_rp = !!(hdcpobs3_1 & (1 << 6));
bcaps_5_ksvfifoready = !!(hdcpobs3_1 & (1 << 5));
if (bcaps_6_rp && bcaps_5_ksvfifoready
&& (hdev->hdcp_max_exceed_cnt == 0))
hdev->hdcp_max_exceed_cnt++;
if (hdev->hdcp_max_exceed_cnt)
hdev->hdcp_max_exceed_cnt++;
if (bcaps_6_rp && bcaps_5_ksvfifoready) {
if ((hdev->hdcp_max_exceed_cnt > max_exceed)
&& !ksv_sha_matched) {
topo14->max_devs_exceeded = 1;
topo14->max_cascade_exceeded = 1;
hdev->hdcp_max_exceed_state = 1;
}
}
if (st_flag != hdmitx_rd_reg(HDMITX_DWC_A_APIINTSTAT)) {
st_flag = hdmitx_rd_reg(HDMITX_DWC_A_APIINTSTAT);
pr_info("hdcp14: instat: 0x%x\n", st_flag);
}
if (st_flag & (1 << 6))
hdmitx_set_reg_bits(HDMITX_DWC_A_HDCPCFG1, 1, 1, 1);
if (st_flag & (1 << 7)) {
hdmitx_wr_reg(HDMITX_DWC_A_APIINTCLR, 1 << 7);
hdmitx_hdcp_opr(3);
if (bcaps_6_rp)
get_hdcp_bstatus(&bstatus0, &bstatus1);
for (i = 0; i < 5; i++)
ksv[i] = (unsigned char)
hdmitx_rd_reg(HDMITX_DWC_HDCPREG_BKSV0 + i);
/* if downstream is only RX */
if ((hdev->repeater_tx == 1) && hdev->topo_info) {
hdcp_ksv_store(hdev->topo_info, ksv, 5);
if (tmp_ksv_lists.valid) {
int cnt = get_hdcp_device_count();
int devs = get_hdcp_max_devs();
int cascade = get_hdcp_max_cascade();
int depth = get_hdcp_depth();
hdcp_ksv_store(hdev->topo_info,
tmp_ksv_lists.lists, tmp_ksv_lists.no);
if (cnt >= 127) {
topo14->device_count = 127;
topo14->max_devs_exceeded = 1;
} else {
topo14->device_count = cnt + 1;
topo14->max_devs_exceeded = devs;
}
if (depth >= 7) {
topo14->depth = 7;
topo14->max_cascade_exceeded = 1;
} else {
topo14->depth = depth + 1;
topo14->max_cascade_exceeded = cascade;
}
} else {
topo14->device_count = 1;
topo14->max_devs_exceeded = 0;
topo14->max_cascade_exceeded = 0;
topo14->depth = 1;
}
}
}
if (st_flag & (1 << 1)) {
hdmitx_wr_reg(HDMITX_DWC_A_APIINTCLR, (1 << 1));
hdmitx_wr_reg(HDMITX_DWC_A_KSVMEMCTRL, 0x1);
hdmitx_poll_reg(HDMITX_DWC_A_KSVMEMCTRL, (1<<1), 2 * HZ);
if (hdmitx_rd_reg(HDMITX_DWC_A_KSVMEMCTRL) & (1 << 1))
hdcp_ksv_sha1_calc(hdev);
else {
pr_info("hdcptx14: KSV List memory access denied\n");
return;
}
hdmitx_wr_reg(HDMITX_DWC_A_KSVMEMCTRL, 0x4);
}
mod_timer(&hdev->hdcp_timer, jiffies + HZ / 100);
}
static void hdcp_start_timer(struct hdmitx_dev *hdev)
{
static int init_flag;
if (!init_flag) {
init_flag = 1;
init_timer(&hdev->hdcp_timer);
hdev->hdcp_timer.data = (ulong)hdev;
hdev->hdcp_timer.function = hdcptx_events_handle;
hdev->hdcp_timer.expires = jiffies + HZ / 100;
add_timer(&hdev->hdcp_timer);
return;
}
hdev->hdcp_timer.expires = jiffies + HZ / 100;
mod_timer(&hdev->hdcp_timer, jiffies + HZ / 100);
}
static void set_pkf_duk_nonce(void)
{
static int nonce_mode = 1; /* 1: use HW nonce 0: use SW nonce */
/* Configure duk/pkf */
hdmitx_hdcp_opr(0xc);
if (nonce_mode == 1)
hdmitx_wr_reg(HDMITX_TOP_SKP_CNTL_STAT, 0xf);
else {
hdmitx_wr_reg(HDMITX_TOP_SKP_CNTL_STAT, 0xe);
/* Configure nonce[127:0].
* MSB must be written the last to assert nonce_vld signal.
*/
hdmitx_wr_reg(HDMITX_TOP_NONCE_0, 0x32107654);
hdmitx_wr_reg(HDMITX_TOP_NONCE_1, 0xba98fedc);
hdmitx_wr_reg(HDMITX_TOP_NONCE_2, 0xcdef89ab);
hdmitx_wr_reg(HDMITX_TOP_NONCE_3, 0x45670123);
hdmitx_wr_reg(HDMITX_TOP_NONCE_0, 0x76543210);
hdmitx_wr_reg(HDMITX_TOP_NONCE_1, 0xfedcba98);
hdmitx_wr_reg(HDMITX_TOP_NONCE_2, 0x89abcdef);
hdmitx_wr_reg(HDMITX_TOP_NONCE_3, 0x01234567);
}
udelay(10);
}
static void check_read_ksv_list_st(void)
{
int cnt = 0;
for (cnt = 0; cnt < 5; cnt++) {
if (((hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS1) & 0x7) == 5) ||
((hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS1) & 0x7) == 6))
msleep(20);
else
return;
}
pr_info("hdcp14: FSM: A9 read ksv list\n");
}
static int hdmitx_cntl_ddc(struct hdmitx_dev *hdev, unsigned int cmd,
unsigned long argv)
{
int i = 0;
unsigned char *tmp_char = NULL;
struct hdcprp14_topo *topo14 = NULL;
unsigned int val;
if ((cmd & CMD_DDC_OFFSET) != CMD_DDC_OFFSET) {
pr_err(HW "ddc: invalid cmd 0x%x\n", cmd);
return -1;
}
switch (cmd) {
case DDC_RESET_EDID:
hdmitx_wr_reg(HDMITX_DWC_I2CM_SOFTRSTZ, 0);
memset(hdev->tmp_edid_buf, 0, ARRAY_SIZE(hdev->tmp_edid_buf));
break;
case DDC_EDID_READ_DATA:
hdmitx_read_edid(hdev->tmp_edid_buf);
break;
case DDC_EDID_GET_DATA:
if (argv == 0)
hdmitx_getediddata(hdev->EDID_buf, hdev->tmp_edid_buf);
else
hdmitx_getediddata(hdev->EDID_buf1, hdev->tmp_edid_buf);
break;
case DDC_PIN_MUX_OP:
if (argv == PIN_MUX)
hdmitx_ddc_hw_op(DDC_MUX_DDC);
if (argv == PIN_UNMUX)
hdmitx_ddc_hw_op(DDC_UNMUX_DDC);
break;
case DDC_EDID_CLEAR_RAM:
for (i = 0; i < EDID_RAM_ADDR_SIZE; i++)
hdmitx_wr_reg(HDMITX_DWC_I2CM_READ_BUFF0 + i, 0);
break;
case DDC_RESET_HDCP:
hdmitx_set_reg_bits(HDMITX_TOP_SW_RESET, 1, 5, 1);
udelay(10);
hdmitx_set_reg_bits(HDMITX_TOP_SW_RESET, 0, 5, 1);
udelay(10);
break;
case DDC_HDCP_MUX_INIT:
if (argv == 2) {
hdmitx_ddc_hw_op(DDC_MUX_DDC);
hdmitx_set_reg_bits(HDMITX_DWC_MC_CLKDIS, 1, 6, 1);
udelay(5);
hdmitx_set_reg_bits(HDMITX_DWC_HDCP22REG_CTRL, 3, 1, 2);
hdmitx_set_reg_bits(HDMITX_TOP_SW_RESET, 1, 5, 1);
udelay(10);
hdmitx_set_reg_bits(HDMITX_TOP_SW_RESET, 0, 5, 1);
udelay(10);
hdmitx_wr_reg(HDMITX_DWC_HDCP22REG_MASK, 0);
hdmitx_wr_reg(HDMITX_DWC_HDCP22REG_MUTE, 0);
set_pkf_duk_nonce();
}
if (argv == 1)
hdmitx_hdcp_opr(6);
if (argv == 3)
hdmitx_set_reg_bits(HDMITX_DWC_HDCP22REG_CTRL, 1, 2, 1);
break;
case DDC_HDCP_OP:
hdev->hdcp_max_exceed_state = 0;
hdev->hdcp_max_exceed_cnt = 0;
ksv_sha_matched = 0;
memset(&tmp_ksv_lists, 0, sizeof(tmp_ksv_lists));
del_timer(&hdev->hdcp_timer);
if (hdev->topo_info)
memset(hdev->topo_info, 0, sizeof(*hdev->topo_info));
if (argv == HDCP14_ON) {
check_read_ksv_list_st();
if (hdev->topo_info)
hdev->topo_info->hdcp_ver = HDCPVER_14;
hdmitx_ddc_hw_op(DDC_MUX_DDC);
hdmitx_set_reg_bits(HDMITX_TOP_SKP_CNTL_STAT, 0, 3, 1);
hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 1, 31, 1);
hdmitx_hdcp_opr(6);
hdmitx_hdcp_opr(1);
hdcp_start_timer(hdev);
}
if (argv == HDCP14_OFF)
hdmitx_hdcp_opr(4);
if (argv == HDCP22_ON) {
if (hdev->topo_info)
hdev->topo_info->hdcp_ver = 2;
hdmitx_ddc_hw_op(DDC_MUX_DDC);
hdmitx_hdcp_opr(5);
/* wait for start hdcp22app */
}
if (argv == HDCP22_OFF)
hdmitx_hdcp_opr(6);
break;
case DDC_IS_HDCP_ON:
/* argv = !!((hdmitx_rd_reg(TX_HDCP_MODE)) & (1 << 7)); */
break;
case DDC_HDCP_GET_BKSV:
tmp_char = (unsigned char *) argv;
for (i = 0; i < 5; i++)
tmp_char[i] = (unsigned char)
hdmitx_rd_reg(HDMITX_DWC_HDCPREG_BKSV0 + 4 - i);
break;
case DDC_HDCP_GET_AUTH:
if (hdev->hdcp_mode == 1)
return hdmitx_hdcp_opr(2);
if (hdev->hdcp_mode == 2)
return hdmitx_hdcp_opr(7);
else
return 0;
break;
case DDC_HDCP_14_LSTORE:
return hdmitx_hdcp_opr(0xa);
case DDC_HDCP_22_LSTORE:
return hdmitx_hdcp_opr(0xb);
case DDC_HDCP14_GET_TOPO_INFO:
topo14 = (struct hdcprp14_topo *)argv;
/* if rx is not repeater, directly return */
if (!(hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS3) & (1 << 6)))
return 0;
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 1, 0, 1);
hdmitx_poll_reg(HDMITX_DWC_A_KSVMEMCTRL, (1<<1), 2 * HZ);
val = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0);
topo14->device_count = val & 0x7f;
topo14->max_devs_exceeded = !!(val & 0x80);
val = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_1);
topo14->depth = val & 0x7;
topo14->max_cascade_exceeded = !!(val & 0x8);
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 0, 1);
return 1;
case DDC_HDCP_SET_TOPO_INFO:
if (hdcp_topo_st != argv) {
hdcp_topo_st = argv;
hdmitx_hdcp_opr(0xd);
}
break;
case DDC_SCDC_DIV40_SCRAMB:
if (argv == 1) {
scdc_wr_sink(TMDS_CFG, 0x3); /* TMDS 1/40 & Scramble */
scdc_wr_sink(TMDS_CFG, 0x3); /* TMDS 1/40 & Scramble */
hdmitx_wr_reg(HDMITX_DWC_FC_SCRAMBLER_CTRL, 1);
} else {
scdc_wr_sink(TMDS_CFG, 0x0); /* TMDS 1/40 & Scramble */
scdc_wr_sink(TMDS_CFG, 0x0); /* TMDS 1/40 & Scramble */
hdmitx_wr_reg(HDMITX_DWC_FC_SCRAMBLER_CTRL, 0);
}
break;
case DDC_HDCP14_GET_BCAPS_RP:
return !!(hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS3) & (1 << 6));
default:
break;
}
return 1;
}
static int hdmitx_hdmi_dvi_config(struct hdmitx_dev *hdev,
unsigned int dvi_mode)
{
if (dvi_mode == 1) {
hdmitx_csc_config(TX_INPUT_COLOR_FORMAT,
COLORSPACE_RGB444, TX_COLOR_DEPTH);
/* set dvi flag */
hdmitx_set_reg_bits(HDMITX_DWC_FC_INVIDCONF, 0, 3, 1);
} else {
/* set hdmi flag */
hdmitx_set_reg_bits(HDMITX_DWC_FC_INVIDCONF, 1, 3, 1);
}
return 0;
}
static int hdmitx_get_hdmi_dvi_config(struct hdmitx_dev *hdev)
{
int value = hdmitx_rd_reg(HDMITX_DWC_FC_INVIDCONF) & 0x8;
return (value == 0)?DVI_MODE:HDMI_MODE;
}
static int hdmitx_cntl_config(struct hdmitx_dev *hdev, unsigned int cmd,
unsigned int argv)
{
int ret = 0;
if ((cmd & CMD_CONF_OFFSET) != CMD_CONF_OFFSET) {
pr_err(HW "config: invalid cmd 0x%x\n", cmd);
return -1;
}
switch (cmd) {
case CONF_HDMI_DVI_MODE:
hdmitx_hdmi_dvi_config(hdev, (argv == DVI_MODE)?1:0);
break;
case CONF_GET_HDMI_DVI_MODE:
ret = hdmitx_get_hdmi_dvi_config(hdev);
break;
case CONF_AUDIO_MUTE_OP:
audio_mute_op(argv == AUDIO_MUTE ? 0 : 1);
break;
case CONF_VIDEO_MUTE_OP:
if (argv == VIDEO_MUTE) {
hd_set_reg_bits(P_HHI_GCLK_OTHER, 1, 3, 1);
hd_set_reg_bits(P_ENCP_VIDEO_MODE_ADV, 0, 3, 1);
hd_write_reg(P_VENC_VIDEO_TST_EN, 1);
hd_write_reg(P_VENC_VIDEO_TST_MDSEL, 0);
/*_Y/CB/CR, 10bits Unsigned/Signed/Signed */
hd_write_reg(P_VENC_VIDEO_TST_Y, 0x0);
hd_write_reg(P_VENC_VIDEO_TST_CB, 0x200);
hd_write_reg(P_VENC_VIDEO_TST_CR, 0x200);
}
if (argv == VIDEO_UNMUTE) {
hd_set_reg_bits(P_ENCP_VIDEO_MODE_ADV, 1, 3, 1);
hd_write_reg(P_VENC_VIDEO_TST_EN, 0);
}
break;
case CONF_CLR_AVI_PACKET:
hdmitx_wr_reg(HDMITX_DWC_FC_AVIVID, 0);
if (hdmitx_rd_reg(HDMITX_DWC_FC_VSDPAYLOAD0) == 0x20)
hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD1, 0);
hd_write_reg(P_ISA_DEBUG_REG0, 0);
break;
case CONF_CLR_VSDB_PACKET:
if (hdmitx_rd_reg(HDMITX_DWC_FC_VSDPAYLOAD0) == 0x20)
hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD1, 0);
break;
case CONF_VIDEO_MAPPING:
config_video_mapping(hdev->para->cs, hdev->para->cd);
break;
case CONF_CLR_AUDINFO_PACKET:
break;
case CONF_AVI_BT2020:
if (argv == SET_AVI_BT2020) {
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF1, 3, 6, 2);
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF2, 6, 4, 3);
}
if (argv == CLR_AVI_BT2020)
hdmitx_set_avi_colorimetry(hdev->para);
break;
case CONF_AVI_RGBYCC_INDIC:
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF0, argv, 0, 2);
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF0, 0, 7, 1);
break;
case CONF_AVI_Q01:
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF2, argv, 2, 2);
break;
case CONF_AVI_YQ01:
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF3, argv, 2, 2);
break;
case CONF_ALLM_MODE:
if (argv == CLEAR_ALLM_MODE) {
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF2, 0, 7, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF3, 0, 0, 2);
break;
}
if (argv == GET_ALLM_MODE) {
if (hdmitx_rd_reg(HDMITX_DWC_FC_AVICONF2) & (1 << 7))
ret = hdmitx_rd_reg(HDMITX_DWC_FC_AVICONF3) & 3;
else
ret = -1;
break;
}
/* set ALLM mode */
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF2, 1, 7, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF3, argv & 3, 0, 2);
if (argv == SET_ALLM_PHOTO) {
// TODO
// Extended colorimetry field may be
// sYcc601, AdobeYcc601 or AdobeRGB
}
break;
case CONF_EMP_NUMBER:
hdmitx_set_reg_bits(HDMITX_TOP_EMP_CNTL0, argv, 16, 16);
break;
case CONF_EMP_PHY_ADDR:
hdmitx_rd_check_reg(HDMITX_TOP_EMP_STAT0, 0, 0x3fffffff);
hdmitx_wr_reg(HDMITX_TOP_EMP_MEMADDR_START, argv);/*phys_ptr*/
hdmitx_set_reg_bits(HDMITX_TOP_EMP_CNTL1, 1, 17, 1); /*little*/
hdmitx_set_reg_bits(HDMITX_TOP_EMP_CNTL1, 120, 0, 16);
hdmitx_set_reg_bits(HDMITX_TOP_EMP_CNTL0, 1, 0, 1);/*emp_tx_en*/
break;
default:
break;
}
return ret;
}
static int hdmitx_tmds_rxsense(void)
{
unsigned int curr0, curr3;
int ret = 0;
struct hdmitx_dev *hdev = get_hdmitx_device();
switch (hdev->chip_type) {
case MESON_CPU_ID_GXBB:
curr0 = hd_read_reg(P_HHI_HDMI_PHY_CNTL0);
curr3 = hd_read_reg(P_HHI_HDMI_PHY_CNTL3);
if (curr0 == 0)
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x33632122);
hd_set_reg_bits(P_HHI_HDMI_PHY_CNTL3, 0x9a, 16, 8);
ret = hd_read_reg(P_HHI_HDMI_PHY_CNTL2) & 0x1;
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, curr3);
if (curr0 == 0)
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0);
break;
case MESON_CPU_ID_GXL:
case MESON_CPU_ID_GXM:
default:
curr0 = hd_read_reg(P_HHI_HDMI_PHY_CNTL0);
curr3 = hd_read_reg(P_HHI_HDMI_PHY_CNTL3);
if (curr0 == 0)
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x33604142);
hd_set_reg_bits(P_HHI_HDMI_PHY_CNTL3, 0x1, 4, 1);
ret = hd_read_reg(P_HHI_HDMI_PHY_CNTL2) & 0x1;
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, curr3);
if (curr0 == 0)
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0);
break;
}
return ret;
}
static int hdmitx_cntl_misc(struct hdmitx_dev *hdev, unsigned int cmd,
unsigned int argv)
{
static int st;
if ((cmd & CMD_MISC_OFFSET) != CMD_MISC_OFFSET) {
pr_err(HW "misc: w: invalid cmd 0x%x\n", cmd);
return -1;
}
switch (cmd) {
case MISC_HPD_MUX_OP:
if (argv == PIN_MUX)
argv = HPD_MUX_HPD;
else
argv = HPD_UNMUX_HPD;
return hdmitx_hpd_hw_op(argv);
case MISC_HPD_GPI_ST:
return hdmitx_hpd_hw_op(HPD_READ_HPD_GPIO);
case MISC_HPLL_FAKE:
hdmitx_set_fake_vic(hdev);
break;
case MISC_TMDS_PHY_OP:
if (argv == TMDS_PHY_ENABLE)
hdmi_phy_wakeup(hdev); /* TODO */
if (argv == TMDS_PHY_DISABLE)
hdmi_phy_suspend();
break;
case MISC_TMDS_RXSENSE:
return hdmitx_tmds_rxsense();
case MISC_ESM_RESET:
if (hdev->hdcp_hpd_stick == 1) {
pr_info(HW "hdcp: stick mode\n");
break;
}
hdmitx_hdcp_opr(6);
break;
case MISC_VIID_IS_USING:
break;
case MISC_TMDS_CLK_DIV40:
set_tmds_clk_div40(argv);
break;
case MISC_AVMUTE_OP:
config_avmute(argv);
break;
case MISC_READ_AVMUTE_OP:
return read_avmute();
case MISC_HDCP_CLKDIS:
if (st != !!argv) {
st = !!argv;
pr_info("set hdcp clkdis: %d\n", !!argv);
}
hdmitx_set_reg_bits(HDMITX_DWC_MC_CLKDIS, !!argv, 6, 1);
break;
case MISC_I2C_REACTIVE:
hdmitx_hdcp_opr(4);
hdmitx_set_reg_bits(HDMITX_DWC_A_HDCPCFG1, 0, 0, 1);
hdmitx_set_reg_bits(HDMITX_DWC_HDCP22REG_CTRL, 0, 2, 1);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_HCNT_1, 0xff);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_HCNT_0, 0xf6);
edid_read_head_8bytes();
hdmi_hwi_init(hdev);
mdelay(5);
break;
default:
break;
}
return 1;
}
static enum hdmi_vic get_vic_from_pkt(void)
{
enum hdmi_vic vic = HDMI_Unknown;
unsigned int rgb_ycc = hdmitx_rd_reg(HDMITX_DWC_FC_AVICONF0);
vic = hdmitx_rd_reg(HDMITX_DWC_FC_AVIVID);
if (vic == HDMI_Unknown) {
vic = (enum hdmi_vic)hdmitx_rd_reg(HDMITX_DWC_FC_VSDPAYLOAD1);
if (vic == 1)
vic = HDMI_3840x2160p30_16x9;
else if (vic == 2)
vic = HDMI_3840x2160p25_16x9;
else if (vic == 3)
vic = HDMI_3840x2160p24_16x9;
else if (vic == 4)
vic = HDMI_4096x2160p24_256x135;
else
vic = hd_read_reg(P_ISA_DEBUG_REG0);
}
rgb_ycc &= 0x3;
switch (vic) {
case HDMI_3840x2160p50_16x9:
if (rgb_ycc == 0x3)
vic = HDMI_3840x2160p50_16x9_Y420;
break;
case HDMI_4096x2160p50_256x135:
if (rgb_ycc == 0x3)
vic = HDMI_4096x2160p50_256x135_Y420;
break;
case HDMI_3840x2160p60_16x9:
if (rgb_ycc == 0x3)
vic = HDMI_3840x2160p60_16x9_Y420;
break;
case HDMI_4096x2160p60_256x135:
if (rgb_ycc == 0x3)
vic = HDMI_4096x2160p60_256x135_Y420;
break;
break;
default:
break;
}
return vic;
}
static int hdmitx_get_state(struct hdmitx_dev *hdev, unsigned int cmd,
unsigned int argv)
{
if ((cmd & CMD_STAT_OFFSET) != CMD_STAT_OFFSET) {
pr_err(HW "state: invalid cmd 0x%x\n", cmd);
return -1;
}
switch (cmd) {
case STAT_VIDEO_VIC:
return (int)get_vic_from_pkt();
case STAT_VIDEO_CLK:
break;
default:
break;
}
return 0;
}
static void hdmi_phy_suspend(void)
{
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x0);
/* keep PHY_CNTL3 bit[1:0] as 0b11,
* otherwise may cause HDCP22 boot failed
*/
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x3);
hd_write_reg(P_HHI_HDMI_PHY_CNTL5, 0x800);
}
static void hdmi_phy_wakeup(struct hdmitx_dev *hdev)
{
hdmitx_set_phy(hdev);
}
/* CRT_VIDEO SETTING FUNCTIONS
* input :
* vIdx: 0:V1; 1:V2; there have 2 parallel set clock generator: V1 and V2
* inSel : 0:vid_pll_clk; 1:fclk_div4; 2:flck_div3; 3:fclk_div5;
* 4:vid_pll2_clk; 5:fclk_div7; 6:vid_pll2_clk;
* DivN : clock divider for enci_clk/encp_clk/encl_clk/vda_clk
* /hdmi_tx_pixel_clk;
*/
void set_crt_video_enc(uint32_t vIdx, uint32_t inSel, uint32_t DivN)
{
if (vIdx == 0) {
hd_set_reg_bits(P_HHI_VID_CLK_CNTL, 0, 19, 1);
hd_set_reg_bits(P_HHI_VID_CLK_CNTL, inSel, 16, 3);
hd_set_reg_bits(P_HHI_VID_CLK_DIV, (DivN-1), 0, 8);
hd_set_reg_bits(P_HHI_VID_CLK_CNTL, 1, 19, 1);
} else { /* V2 */
hd_set_reg_bits(P_HHI_VIID_CLK_CNTL, 0, 19, 1);
hd_set_reg_bits(P_HHI_VIID_CLK_CNTL, inSel, 16, 3);
hd_set_reg_bits(P_HHI_VIID_CLK_DIV, (DivN-1), 0, 8);
hd_set_reg_bits(P_HHI_VIID_CLK_CNTL, 1, 19, 1);
}
}
void hdmitx_set_avi_colorimetry(struct hdmi_format_para *para)
{
struct hdmitx_dev *hdev = get_hdmitx_device();
if (!para)
return;
/* set Colorimetry in AVIInfo */
switch (para->vic) {
case HDMI_640x480p60_4x3:
case HDMI_720x480p60_4x3:
case HDMI_720x480p60_16x9:
case HDMI_720x480i60_4x3:
case HDMI_720x480i60_16x9:
case HDMI_720x240p60_4x3:
case HDMI_720x240p60_16x9:
case HDMI_2880x480i60_4x3:
case HDMI_2880x480i60_16x9:
case HDMI_2880x240p60_4x3:
case HDMI_2880x240p60_16x9:
case HDMI_1440x480p60_4x3:
case HDMI_1440x480p60_16x9:
case HDMI_720x576p50_4x3:
case HDMI_720x576p50_16x9:
case HDMI_720x576i50_4x3:
case HDMI_720x576i50_16x9:
case HDMI_720x288p_4x3:
case HDMI_720x288p_16x9:
case HDMI_2880x576i50_4x3:
case HDMI_2880x576i50_16x9:
case HDMI_2880x288p50_4x3:
case HDMI_2880x288p50_16x9:
case HDMI_1440x576p_4x3:
case HDMI_1440x576p_16x9:
case HDMI_2880x480p60_4x3:
case HDMI_2880x480p60_16x9:
case HDMI_2880x576p50_4x3:
case HDMI_2880x576p50_16x9:
case HDMI_720x576p100_4x3:
case HDMI_720x576p100_16x9:
case HDMI_720x576i100_4x3:
case HDMI_720x576i100_16x9:
case HDMI_720x480p120_4x3:
case HDMI_720x480p120_16x9:
case HDMI_720x480i120_4x3:
case HDMI_720x480i120_16x9:
case HDMI_720x576p200_4x3:
case HDMI_720x576p200_16x9:
case HDMI_720x576i200_4x3:
case HDMI_720x576i200_16x9:
case HDMI_720x480p240_4x3:
case HDMI_720x480p240_16x9:
case HDMI_720x480i240_4x3:
case HDMI_720x480i240_16x9:
/* C1C0 601 */
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF1, 1, 6, 2);
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF2, 0, 4, 3);
break;
default:
if (hdev->colormetry) {
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF1, 3, 6, 2);
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF2, 6, 4, 3);
} else {
/* C1C0 709 */
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF1, 2, 6, 2);
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF2, 0, 4, 3);
}
break;
}
}
/*
* color_depth: Pixel bit width: 4=24-bit; 5=30-bit; 6=36-bit; 7=48-bit.
* input_color_format: 0=RGB444; 1=YCbCr422; 2=YCbCr444; 3=YCbCr420.
* input_color_range: 0=limited; 1=full.
* output_color_format: 0=RGB444; 1=YCbCr422; 2=YCbCr444; 3=YCbCr420
*/
static void config_hdmi20_tx(enum hdmi_vic vic,
struct hdmitx_dev *hdev,
unsigned char color_depth,
unsigned char input_color_format,
unsigned char output_color_format)
{
struct hdmi_format_para *para = hdev->para;
struct hdmi_cea_timing *t = &para->timing;
unsigned long data32;
unsigned char vid_map;
unsigned char csc_en;
unsigned char default_phase = 0;
unsigned int tmp = 0;
#define GET_TIMING(name) (t->name)
/* Enable hdmitx_sys_clk */
hdmitx_set_cts_sys_clk(hdev);
/* Enable clk81_hdmitx_pclk */
hdmitx_set_top_pclk(hdev);
/* wire wr_enable = control[3]; */
/* wire fifo_enable = control[2]; */
/* assign phy_clk_en = control[1]; */
/* Enable tmds_clk */
/* Bring HDMITX MEM output of power down */
hd_set_reg_bits(P_HHI_MEM_PD_REG0, 0, 8, 8);
/* Bring out of reset */
hdmitx_wr_reg(HDMITX_TOP_SW_RESET, 0);
/* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */
hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 3, 0, 2);
hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 3, 4, 2);
hdmitx_wr_reg(HDMITX_DWC_MC_LOCKONCLOCK, 0xff);
/* But keep spdif_clk and i2s_clk disable
* until later enable by test.c
*/
data32 = 0;
hdmitx_wr_reg(HDMITX_DWC_MC_CLKDIS, data32);
/* Enable normal output to PHY */
data32 = 0;
data32 |= (1 << 12);
data32 |= (0 << 8);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_TOP_BIST_CNTL, data32);
/* Configure video */
if (input_color_format == COLORSPACE_RGB444) {
if (color_depth == COLORDEPTH_24B)
vid_map = 0x01;
else if (color_depth == COLORDEPTH_30B)
vid_map = 0x03;
else if (color_depth == COLORDEPTH_36B)
vid_map = 0x05;
else
vid_map = 0x07;
} else if (((input_color_format == COLORSPACE_YUV444) ||
(input_color_format == COLORSPACE_YUV420)) &&
(output_color_format != COLORSPACE_YUV422)) {
if (color_depth == COLORDEPTH_24B)
vid_map = 0x09;
else if (color_depth == COLORDEPTH_30B)
vid_map = 0x0b;
else if (color_depth == COLORDEPTH_36B)
vid_map = 0x0d;
else
vid_map = 0x0f;
} else {
if (color_depth == COLORDEPTH_24B)
vid_map = 0x16;
else if (color_depth == COLORDEPTH_30B)
vid_map = 0x14;
else
vid_map = 0x12;
}
data32 = 0;
data32 |= (0 << 7);
data32 |= (vid_map << 0);
hdmitx_wr_reg(HDMITX_DWC_TX_INVID0, data32);
data32 = 0;
data32 |= (0 << 2);
data32 |= (0 << 1);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_TX_INSTUFFING, data32);
hdmitx_wr_reg(HDMITX_DWC_TX_GYDATA0, 0x00);
hdmitx_wr_reg(HDMITX_DWC_TX_GYDATA1, 0x00);
hdmitx_wr_reg(HDMITX_DWC_TX_RCRDATA0, 0x00);
hdmitx_wr_reg(HDMITX_DWC_TX_RCRDATA1, 0x00);
hdmitx_wr_reg(HDMITX_DWC_TX_BCBDATA0, 0x00);
hdmitx_wr_reg(HDMITX_DWC_TX_BCBDATA1, 0x00);
/* Configure Color Space Converter */
csc_en = (input_color_format != output_color_format) ? 1 : 0;
data32 = 0;
data32 |= (csc_en << 0);
hdmitx_wr_reg(HDMITX_DWC_MC_FLOWCTRL, data32);
data32 = 0;
data32 |= ((((input_color_format == COLORSPACE_YUV422) &&
(output_color_format != COLORSPACE_YUV422)) ? 2 : 0) << 4);
hdmitx_wr_reg(HDMITX_DWC_CSC_CFG, data32);
hdmitx_csc_config(input_color_format, output_color_format, color_depth);
/* Configure video packetizer */
/* Video Packet color depth and pixel repetition */
data32 = 0;
data32 |= (((output_color_format == COLORSPACE_YUV422) ?
COLORDEPTH_24B : color_depth) << 4);
data32 |= (0 << 0);
if ((data32 & 0xf0) == 0x40)
data32 &= ~(0xf << 4);
hdmitx_wr_reg(HDMITX_DWC_VP_PR_CD, data32);
if (output_color_format == COLORSPACE_YUV422)
hdmitx_set_reg_bits(HDMITX_DWC_VP_PR_CD, 0x4, 4, 4);
/* Video Packet Stuffing */
data32 = 0;
data32 |= (default_phase << 5);
data32 |= (0 << 2);
data32 |= (0 << 1);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_VP_STUFF, data32);
/* Video Packet YCC color remapping */
data32 = 0;
data32 |= (((color_depth == COLORDEPTH_30B) ? 1 :
(color_depth == COLORDEPTH_36B) ? 2 : 0) << 0);
hdmitx_wr_reg(HDMITX_DWC_VP_REMAP, data32);
if (output_color_format == COLORSPACE_YUV422) {
switch (color_depth) {
case COLORDEPTH_36B:
tmp = 2;
break;
case COLORDEPTH_30B:
tmp = 1;
break;
case COLORDEPTH_24B:
tmp = 0;
break;
}
}
/* [1:0] ycc422_size */
hdmitx_set_reg_bits(HDMITX_DWC_VP_REMAP, tmp, 0, 2);
/* Video Packet configuration */
data32 = 0;
data32 |= ((((output_color_format != COLORSPACE_YUV422) &&
(color_depth == COLORDEPTH_24B)) ? 1 : 0) << 6);
data32 |= ((((output_color_format == COLORSPACE_YUV422) ||
(color_depth == COLORDEPTH_24B)) ? 0 : 1) << 5);
data32 |= (0 << 4);
data32 |= (((output_color_format == COLORSPACE_YUV422) ? 1 : 0)
<< 3);
data32 |= (1 << 2);
data32 |= (((output_color_format == COLORSPACE_YUV422) ? 1 :
(color_depth == COLORDEPTH_24B) ? 2 : 0) << 0);
hdmitx_wr_reg(HDMITX_DWC_VP_CONF, data32);
data32 = 0;
data32 |= (1 << 7);
data32 |= (1 << 6);
data32 |= (1 << 5);
data32 |= (1 << 4);
data32 |= (1 << 3);
data32 |= (1 << 2);
data32 |= (1 << 1);
data32 |= (1 << 0);
hdmitx_wr_reg(HDMITX_DWC_VP_MASK, data32);
/* Configure audio */
/* I2S Sampler config */
data32 = 0;
data32 |= (1 << 3);
data32 |= (1 << 2);
hdmitx_wr_reg(HDMITX_DWC_AUD_INT, data32);
data32 = 0;
data32 |= (1 << 4);
hdmitx_wr_reg(HDMITX_DWC_AUD_INT1, data32);
hdmitx_wr_reg(HDMITX_DWC_FC_MULTISTREAM_CTRL, 0);
/* if enable it now, fifo_overrun will happen, because packet don't get
* sent out until initial DE detected.
*/
data32 = 0;
data32 |= (0 << 7);
data32 |= (hdev->tx_aud_src << 5);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_AUD_CONF0, data32);
data32 = 0;
data32 |= (0 << 5);
data32 |= (24 << 0);
hdmitx_wr_reg(HDMITX_DWC_AUD_CONF1, data32);
data32 = 0;
data32 |= (0 << 1);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_AUD_CONF2, data32);
/* spdif sampler config */
data32 = 0;
data32 |= (1 << 3);
data32 |= (1 << 2);
hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIFINT, data32);
data32 = 0;
data32 |= (0 << 4);
hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIFINT1, data32);
data32 = 0;
data32 |= (0 << 7);
hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIF0, data32);
data32 = 0;
data32 |= (0 << 7);
data32 |= (0 << 6);
data32 |= (24 << 0);
hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIF1, data32);
/* Frame Composer configuration */
/* Video definitions, as per output video(for packet gen/schedulling) */
data32 = 0;
data32 |= (1 << 7);
data32 |= (GET_TIMING(vsync_polarity) << 6);
data32 |= (GET_TIMING(hsync_polarity) << 5);
data32 |= (1 << 4);
data32 |= (1 << 3);
data32 |= (!(para->progress_mode) << 1);
data32 |= (!(para->progress_mode) << 0);
hdmitx_wr_reg(HDMITX_DWC_FC_INVIDCONF, data32);
data32 = GET_TIMING(h_active)&0xff;
hdmitx_wr_reg(HDMITX_DWC_FC_INHACTV0, data32);
data32 = (GET_TIMING(h_active)>>8) & 0x3f;
hdmitx_wr_reg(HDMITX_DWC_FC_INHACTV1, data32);
data32 = GET_TIMING(h_blank) & 0xff;
hdmitx_wr_reg(HDMITX_DWC_FC_INHBLANK0, data32);
data32 = (GET_TIMING(h_blank)>>8)&0x1f;
hdmitx_wr_reg(HDMITX_DWC_FC_INHBLANK1, data32);
if (hdev->flag_3dfp) {
data32 = (((GET_TIMING(v_active)) * 2) + (GET_TIMING(v_blank)));
hdmitx_wr_reg(HDMITX_DWC_FC_INVACTV0, data32 & 0xff);
hdmitx_wr_reg(HDMITX_DWC_FC_INVACTV1, (data32 >> 8) & 0x1f);
} else {
data32 = GET_TIMING(v_active) & 0xff;
hdmitx_wr_reg(HDMITX_DWC_FC_INVACTV0, data32);
data32 = (GET_TIMING(v_active) >> 8) & 0x1f;
hdmitx_wr_reg(HDMITX_DWC_FC_INVACTV1, data32);
}
data32 = GET_TIMING(v_blank)&0xff;
hdmitx_wr_reg(HDMITX_DWC_FC_INVBLANK, data32);
data32 = GET_TIMING(h_front)&0xff;
hdmitx_wr_reg(HDMITX_DWC_FC_HSYNCINDELAY0, data32);
data32 = (GET_TIMING(h_front)>>8)&0x1f;
hdmitx_wr_reg(HDMITX_DWC_FC_HSYNCINDELAY1, data32);
data32 = GET_TIMING(h_sync)&0xff;
hdmitx_wr_reg(HDMITX_DWC_FC_HSYNCINWIDTH0, data32);
data32 = (GET_TIMING(h_sync)>>8)&0x3;
hdmitx_wr_reg(HDMITX_DWC_FC_HSYNCINWIDTH1, data32);
data32 = GET_TIMING(v_front)&0xff;
hdmitx_wr_reg(HDMITX_DWC_FC_VSYNCINDELAY, data32);
data32 = GET_TIMING(v_sync)&0x3f;
hdmitx_wr_reg(HDMITX_DWC_FC_VSYNCINWIDTH, data32);
if (hdev->para->cs == COLORSPACE_YUV420)
mode420_half_horizontal_para();
/* control period duration (typ 12 tmds periods) */
hdmitx_wr_reg(HDMITX_DWC_FC_CTRLDUR, 12);
/* extended control period duration (typ 32 tmds periods) */
hdmitx_wr_reg(HDMITX_DWC_FC_EXCTRLDUR, 32);
/* max interval betwen extended control period duration (typ 50) */
hdmitx_wr_reg(HDMITX_DWC_FC_EXCTRLSPAC, 1);
/* preamble filler */
hdmitx_wr_reg(HDMITX_DWC_FC_CH0PREAM, 0x0b);
hdmitx_wr_reg(HDMITX_DWC_FC_CH1PREAM, 0x16);
hdmitx_wr_reg(HDMITX_DWC_FC_CH2PREAM, 0x21);
/* write GCP packet configuration */
data32 = 0;
data32 |= (default_phase << 2);
data32 |= (0 << 1);
data32 |= (0 << 0);
if (!hdev->repeater_tx)
hdmitx_wr_reg(HDMITX_DWC_FC_GCP, data32);
/* write AVI Infoframe packet configuration */
data32 = 0;
data32 |= (((output_color_format>>2)&0x1) << 7);
data32 |= (1 << 6);
data32 |= (0 << 4);
data32 |= (0 << 2);
data32 |= (0x2 << 0); /* FIXED YCBCR 444 */
hdmitx_wr_reg(HDMITX_DWC_FC_AVICONF0, data32);
switch (output_color_format) {
case COLORSPACE_RGB444:
tmp = 0;
break;
case COLORSPACE_YUV422:
tmp = 1;
break;
case COLORSPACE_YUV420:
tmp = 3;
break;
case COLORSPACE_YUV444:
default:
tmp = 2;
break;
}
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF0, tmp, 0, 2);
hdmitx_wr_reg(HDMITX_DWC_FC_AVICONF1, 0x8);
hdmitx_wr_reg(HDMITX_DWC_FC_AVICONF2, 0);
/* set Aspect Ratio in AVIInfo */
switch (para->vic) {
case HDMI_640x480p60_4x3:
case HDMI_720x480p60_4x3:
case HDMI_720x480i60_4x3:
case HDMI_720x240p60_4x3:
case HDMI_2880x480i60_4x3:
case HDMI_2880x240p60_4x3:
case HDMI_1440x480p60_4x3:
case HDMI_720x576p50_4x3:
case HDMI_720x576i50_4x3:
case HDMI_720x288p_4x3:
case HDMI_2880x576i50_4x3:
case HDMI_2880x288p50_4x3:
case HDMI_1440x576p_4x3:
case HDMI_2880x480p60_4x3:
case HDMI_2880x576p50_4x3:
case HDMI_720x576p100_4x3:
case HDMI_720x576i100_4x3:
case HDMI_720x480p120_4x3:
case HDMI_720x480i120_4x3:
case HDMI_720x576p200_4x3:
case HDMI_720x576i200_4x3:
case HDMI_720x480p240_4x3:
case HDMI_720x480i240_4x3:
/* Picture Aspect Ratio M1/M0 4:3 */
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF1, 0x1, 4, 2);
break;
default:
/* Picture Aspect Ratio M1/M0 16:9 */
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF1, 0x2, 4, 2);
break;
}
/* Active Format Aspect Ratio R3~R0 Same as picture aspect ratio */
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF1, 0x8, 0, 4);
hdmitx_set_avi_colorimetry(para);
if (hdev->hdr_color_feature == C_BT2020)
hdev->HWOp.CntlConfig(hdev, CONF_AVI_BT2020, SET_AVI_BT2020);
data32 = 0;
data32 |= (((0 == COLORRANGE_FUL) ? 1 : 0) << 2);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_FC_AVICONF3, data32);
hdmitx_wr_reg(HDMITX_DWC_FC_AVIVID, (para->vic & HDMITX_VIC_MASK));
/* For VESA modes, set VIC as 0 */
if (para->vic >= HDMITX_VESA_OFFSET) {
hdmitx_wr_reg(HDMITX_DWC_FC_AVIVID, 0);
hd_write_reg(P_ISA_DEBUG_REG0, para->vic);
}
/* For VESA modes, set VIC as 0 */
if (para->vic >= HDMITX_VESA_OFFSET) {
hdmitx_wr_reg(HDMITX_DWC_FC_AVIVID, 0);
hd_write_reg(P_ISA_DEBUG_REG0, para->vic);
}
/* write Audio Infoframe packet configuration */
data32 = 0;
data32 |= (1 << 4);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF0, data32);
data32 = 0;
data32 |= (3 << 4);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF1, data32);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF2, 0x00);
data32 = 0;
data32 |= (1 << 5);
data32 |= (0 << 4);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF3, data32);
/* write audio packet configuration */
data32 = 0;
data32 |= (0 << 4);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCONF, data32);
/* the audio setting bellow are only used for I2S audio IEC60958-3 frame
* insertion
*/
data32 = 0;
data32 |= (0 << 7);
data32 |= (0 << 6);
data32 |= (0 << 5);
data32 |= (1 << 4);
data32 |= (0 << 3);
data32 |= (0 << 2);
data32 |= (0 << 1);
data32 |= (1 << 0);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSV, data32);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSU, 0);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS0, 0x01);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS1, 0x23);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS2, 0x45);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS3, 0x67);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS4, 0x89);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS5, 0xab);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS6, 0xcd);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS7, 0x2f);
hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS8, 0xf0);
/* packet queue priority (auto mode) */
hdmitx_wr_reg(HDMITX_DWC_FC_CTRLQHIGH, 15);
hdmitx_wr_reg(HDMITX_DWC_FC_CTRLQLOW, 3);
/* packet scheduller configuration for SPD, VSD, ISRC1/2, ACP. */
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO0, 0, 0, 3);
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO0, 0, 4, 4);
hdmitx_wr_reg(HDMITX_DWC_FC_DATAUTO1, 0);
hdmitx_wr_reg(HDMITX_DWC_FC_DATMAN, 0);
/* packet scheduller configuration for AVI, GCP, AUDI, ACR. */
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO3, 0x6, 0, 6);
/* If RX support 2084 or hlg , and the hdr_src_feature is 2020
* then enable HDR send out
*/
if ((hdev->RXCap.hdr_sup_eotf_smpte_st_2084 ||
hdev->RXCap.hdr_sup_eotf_hlg) &&
(hdev->hdr_color_feature == C_BT2020)) {
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO3, 1, 6, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 7, 1);
} else {
/* If RX don't support HDR, then enable HDR send out*/
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO3, 0, 6, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 0, 7, 1);
}
/* If RX support 3D, then enable 3D send out */
if (hdev->flag_3dfp || hdev->flag_3dtb || hdev->flag_3dss) {
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO0, 1, 3, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 4, 1);
} else {
/* after changing mode, dv will call vsif function again*/
hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO0, 0, 3, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 0, 4, 1);
}
hdmitx_wr_reg(HDMITX_DWC_FC_RDRB0, 0);
hdmitx_wr_reg(HDMITX_DWC_FC_RDRB1, 0);
hdmitx_wr_reg(HDMITX_DWC_FC_RDRB2, 0);
hdmitx_wr_reg(HDMITX_DWC_FC_RDRB3, 0);
hdmitx_wr_reg(HDMITX_DWC_FC_RDRB4, 0);
hdmitx_wr_reg(HDMITX_DWC_FC_RDRB5, 0);
/* AVI info usb RDRB mode and place in line 10*/
hdmitx_wr_reg(HDMITX_DWC_FC_RDRB6, 0x0);
hdmitx_wr_reg(HDMITX_DWC_FC_RDRB7, 0x1a);
hdmitx_wr_reg(HDMITX_DWC_FC_RDRB8, 0);
hdmitx_wr_reg(HDMITX_DWC_FC_RDRB9, 0);
hdmitx_wr_reg(HDMITX_DWC_FC_RDRB10, 0);
hdmitx_wr_reg(HDMITX_DWC_FC_RDRB11, 0);
/* Packet transmission enable */
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 1, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 2, 1);
/* For 3D video */
data32 = 0;
data32 |= (0 << 1);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_FC_ACTSPC_HDLR_CFG, data32);
data32 = GET_TIMING(v_active)&0xff;
hdmitx_wr_reg(HDMITX_DWC_FC_INVACT_2D_0, data32);
data32 = (GET_TIMING(v_active)>>8)&0xf;
hdmitx_wr_reg(HDMITX_DWC_FC_INVACT_2D_1, data32);
/* Do not enable these interrupt below, we can check them at RX side. */
data32 = 0;
data32 |= (1 << 7);
data32 |= (1 << 6);
data32 |= (1 << 5);
data32 |= (1 << 2);
data32 |= (1 << 1);
data32 |= (1 << 0);
hdmitx_wr_reg(HDMITX_DWC_FC_MASK0, data32);
data32 = 0;
data32 |= (1 << 7);
data32 |= (1 << 6);
data32 |= (1 << 5);
data32 |= (1 << 4);
data32 |= (1 << 3);
data32 |= (1 << 1);
data32 |= (1 << 0);
hdmitx_wr_reg(HDMITX_DWC_FC_MASK1, data32);
data32 = 0;
data32 |= (1 << 2);
data32 |= (1 << 1);
data32 |= (1 << 0);
hdmitx_wr_reg(HDMITX_DWC_FC_MASK2, data32);
/* Pixel repetition ratio the input and output video */
data32 = 0;
data32 |= ((para->pixel_repetition_factor+1) << 4);
data32 |= (para->pixel_repetition_factor << 0);
hdmitx_wr_reg(HDMITX_DWC_FC_PRCONF, data32);
/* Configure HDCP */
data32 = 0;
data32 |= (0 << 7);
data32 |= (0 << 6);
data32 |= (0 << 4);
data32 |= (0 << 3);
data32 |= (0 << 2);
data32 |= (0 << 1);
data32 |= (1 << 0);
hdmitx_wr_reg(HDMITX_DWC_A_APIINTMSK, data32);
data32 = 0;
data32 |= (0 << 5);
data32 |= (1 << 4);
data32 |= (1 << 3);
data32 |= (1 << 1);
hdmitx_wr_reg(HDMITX_DWC_A_VIDPOLCFG, data32);
hdmitx_wr_reg(HDMITX_DWC_A_OESSWCFG, 0x40);
if (hdmitx_hdcp_opr(0xa))
hdmitx_hdcp_opr(0);
/* Interrupts */
/* Clear interrupts */
hdmitx_wr_reg(HDMITX_DWC_IH_FC_STAT0, 0xff);
hdmitx_wr_reg(HDMITX_DWC_IH_FC_STAT1, 0xff);
hdmitx_wr_reg(HDMITX_DWC_IH_FC_STAT2, 0xff);
hdmitx_wr_reg(HDMITX_DWC_IH_AS_STAT0, 0xff);
hdmitx_wr_reg(HDMITX_DWC_IH_PHY_STAT0, 0xff);
hdmitx_wr_reg(HDMITX_DWC_IH_I2CM_STAT0, 0xff);
hdmitx_wr_reg(HDMITX_DWC_IH_CEC_STAT0, 0xff);
hdmitx_wr_reg(HDMITX_DWC_IH_VP_STAT0, 0xff);
hdmitx_wr_reg(HDMITX_DWC_IH_I2CMPHY_STAT0, 0xff);
hdmitx_wr_reg(HDMITX_DWC_A_APIINTCLR, 0xff);
hdmitx_wr_reg(HDMITX_DWC_HDCP22REG_STAT, 0xff);
hdmitx_wr_reg(HDMITX_TOP_INTR_STAT_CLR, 0x0000001f);
/* Selectively enable/mute interrupt sources */
data32 = 0;
data32 |= (1 << 7);
data32 |= (1 << 6);
data32 |= (1 << 5);
data32 |= (1 << 4);
data32 |= (1 << 3);
data32 |= (1 << 2);
data32 |= (1 << 1);
data32 |= (1 << 0);
hdmitx_wr_reg(HDMITX_DWC_IH_MUTE_FC_STAT0, data32);
data32 = 0;
data32 |= (1 << 7);
data32 |= (1 << 6);
data32 |= (1 << 5);
data32 |= (1 << 4);
data32 |= (1 << 3);
data32 |= (1 << 2);
data32 |= (1 << 1);
data32 |= (1 << 0);
hdmitx_wr_reg(HDMITX_DWC_IH_MUTE_FC_STAT1, data32);
data32 = 0;
data32 |= (1 << 1);
data32 |= (1 << 0);
hdmitx_wr_reg(HDMITX_DWC_IH_MUTE_FC_STAT2, data32);
data32 = 0;
data32 |= (0 << 4);
data32 |= (0 << 3);
data32 |= (1 << 2);
data32 |= (1 << 1);
data32 |= (1 << 0);
hdmitx_wr_reg(HDMITX_DWC_IH_MUTE_AS_STAT0, data32);
hdmitx_wr_reg(HDMITX_DWC_IH_MUTE_PHY_STAT0, 0x3f);
data32 = 0;
data32 |= (0 << 2);
data32 |= (1 << 1);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_IH_MUTE_I2CM_STAT0, data32);
data32 = 0;
data32 |= (0 << 6);
data32 |= (0 << 5);
data32 |= (0 << 4);
data32 |= (0 << 3);
data32 |= (0 << 2);
data32 |= (0 << 1);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_IH_MUTE_CEC_STAT0, data32);
hdmitx_wr_reg(HDMITX_DWC_IH_MUTE_VP_STAT0, 0xff);
hdmitx_wr_reg(HDMITX_DWC_IH_MUTE_I2CMPHY_STAT0, 0x03);
data32 = 0;
data32 |= (0 << 1);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_IH_MUTE, data32);
data32 = 0;
data32 |= (1 << 4);
data32 |= (1 << 3);
data32 |= (1 << 2);
data32 |= (1 << 1);
data32 |= (1 << 0);
hdmitx_wr_reg(HDMITX_TOP_INTR_MASKN, data32);
/* Reset pulse */
hdmitx_rd_check_reg(HDMITX_DWC_MC_LOCKONCLOCK, 0xff, 0x9f);
hd_write_reg(P_ENCP_VIDEO_EN, 0);
hdmitx_wr_reg(HDMITX_DWC_MC_CLKDIS, 0xdf);
hdmitx_wr_reg(HDMITX_DWC_MC_SWRSTZREQ, 0);
mdelay(10);
data32 = 0;
data32 |= (1 << 7);
data32 |= (1 << 6);
data32 |= (1 << 4);
data32 |= (1 << 3);
data32 |= (1 << 2);
data32 |= (0 << 1);
data32 |= (1 << 0);
hdmitx_wr_reg(HDMITX_DWC_MC_SWRSTZREQ, data32);
hdmitx_wr_reg(HDMITX_DWC_FC_VSYNCINWIDTH,
hdmitx_rd_reg(HDMITX_DWC_FC_VSYNCINWIDTH));
hdmitx_wr_reg(HDMITX_DWC_MC_CLKDIS, 0);
hd_write_reg(P_ENCP_VIDEO_EN, 0xff);
hdmitx_set_reg_bits(HDMITX_DWC_FC_INVIDCONF, 0, 3, 1);
mdelay(1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_INVIDCONF, 1, 3, 1);
} /* config_hdmi20_tx */
static void hdmitx_csc_config(unsigned char input_color_format,
unsigned char output_color_format,
unsigned char color_depth)
{
unsigned char conv_en;
unsigned char csc_scale;
unsigned char rgb_ycc_indicator;
unsigned long csc_coeff_a1, csc_coeff_a2, csc_coeff_a3, csc_coeff_a4;
unsigned long csc_coeff_b1, csc_coeff_b2, csc_coeff_b3, csc_coeff_b4;
unsigned long csc_coeff_c1, csc_coeff_c2, csc_coeff_c3, csc_coeff_c4;
unsigned long data32;
conv_en = (((input_color_format == COLORSPACE_RGB444) ||
(output_color_format == COLORSPACE_RGB444)) &&
(input_color_format != output_color_format)) ? 1 : 0;
if (conv_en) {
if (output_color_format == COLORSPACE_RGB444) {
csc_coeff_a1 = 0x2000;
csc_coeff_a2 = 0x6926;
csc_coeff_a3 = 0x74fd;
csc_coeff_a4 = (color_depth == COLORDEPTH_24B) ?
0x010e :
(color_depth == COLORDEPTH_30B) ? 0x043b :
(color_depth == COLORDEPTH_36B) ? 0x10ee :
(color_depth == COLORDEPTH_48B) ? 0x10ee : 0x010e;
csc_coeff_b1 = 0x2000;
csc_coeff_b2 = 0x2cdd;
csc_coeff_b3 = 0x0000;
csc_coeff_b4 = (color_depth == COLORDEPTH_24B) ? 0x7e9a :
(color_depth == COLORDEPTH_30B) ? 0x7a65 :
(color_depth == COLORDEPTH_36B) ? 0x6992 :
(color_depth == COLORDEPTH_48B) ? 0x6992 : 0x7e9a;
csc_coeff_c1 = 0x2000;
csc_coeff_c2 = 0x0000;
csc_coeff_c3 = 0x38b4;
csc_coeff_c4 = (color_depth == COLORDEPTH_24B) ? 0x7e3b :
(color_depth == COLORDEPTH_30B) ? 0x78ea :
(color_depth == COLORDEPTH_36B) ? 0x63a6 :
(color_depth == COLORDEPTH_48B) ? 0x63a6 : 0x7e3b;
csc_scale = 1;
} else { /* input_color_format == COLORSPACE_RGB444 */
csc_coeff_a1 = 0x2591;
csc_coeff_a2 = 0x1322;
csc_coeff_a3 = 0x074b;
csc_coeff_a4 = 0x0000;
csc_coeff_b1 = 0x6535;
csc_coeff_b2 = 0x2000;
csc_coeff_b3 = 0x7acc;
csc_coeff_b4 = (color_depth == COLORDEPTH_24B) ? 0x0200 :
(color_depth == COLORDEPTH_30B) ? 0x0800 :
(color_depth == COLORDEPTH_36B) ? 0x2000 :
(color_depth == COLORDEPTH_48B) ? 0x2000 : 0x0200;
csc_coeff_c1 = 0x6acd;
csc_coeff_c2 = 0x7534;
csc_coeff_c3 = 0x2000;
csc_coeff_c4 = (color_depth == COLORDEPTH_24B) ? 0x0200 :
(color_depth == COLORDEPTH_30B) ? 0x0800 :
(color_depth == COLORDEPTH_36B) ? 0x2000 :
(color_depth == COLORDEPTH_48B) ? 0x2000 : 0x0200;
csc_scale = 0;
}
} else {
csc_coeff_a1 = 0x2000;
csc_coeff_a2 = 0x0000;
csc_coeff_a3 = 0x0000;
csc_coeff_a4 = 0x0000;
csc_coeff_b1 = 0x0000;
csc_coeff_b2 = 0x2000;
csc_coeff_b3 = 0x0000;
csc_coeff_b4 = 0x0000;
csc_coeff_c1 = 0x0000;
csc_coeff_c2 = 0x0000;
csc_coeff_c3 = 0x2000;
csc_coeff_c4 = 0x0000;
csc_scale = 1;
}
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_A1_MSB, (csc_coeff_a1>>8)&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_A1_LSB, csc_coeff_a1&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_A2_MSB, (csc_coeff_a2>>8)&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_A2_LSB, csc_coeff_a2&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_A3_MSB, (csc_coeff_a3>>8)&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_A3_LSB, csc_coeff_a3&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_A4_MSB, (csc_coeff_a4>>8)&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_A4_LSB, csc_coeff_a4&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_B1_MSB, (csc_coeff_b1>>8)&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_B1_LSB, csc_coeff_b1&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_B2_MSB, (csc_coeff_b2>>8)&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_B2_LSB, csc_coeff_b2&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_B3_MSB, (csc_coeff_b3>>8)&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_B3_LSB, csc_coeff_b3&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_B4_MSB, (csc_coeff_b4>>8)&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_B4_LSB, csc_coeff_b4&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_C1_MSB, (csc_coeff_c1>>8)&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_C1_LSB, csc_coeff_c1&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_C2_MSB, (csc_coeff_c2>>8)&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_C2_LSB, csc_coeff_c2&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_C3_MSB, (csc_coeff_c3>>8)&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_C3_LSB, csc_coeff_c3&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_C4_MSB, (csc_coeff_c4>>8)&0xff);
hdmitx_wr_reg(HDMITX_DWC_CSC_COEF_C4_LSB, csc_coeff_c4&0xff);
data32 = 0;
data32 |= (color_depth << 4); /* [7:4] csc_color_depth */
data32 |= (csc_scale << 0); /* [1:0] cscscale */
hdmitx_wr_reg(HDMITX_DWC_CSC_SCALE, data32);
/* set csc in video path */
hdmitx_wr_reg(HDMITX_DWC_MC_FLOWCTRL, (conv_en == 1)?0x1:0x0);
/* set rgb_ycc indicator */
switch (output_color_format) {
case COLORSPACE_RGB444:
rgb_ycc_indicator = 0x0;
break;
case COLORSPACE_YUV422:
rgb_ycc_indicator = 0x1;
break;
case COLORSPACE_YUV420:
rgb_ycc_indicator = 0x3;
break;
case COLORSPACE_YUV444:
default:
rgb_ycc_indicator = 0x2;
break;
}
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF0,
((rgb_ycc_indicator & 0x4) >> 2), 7, 1);
hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF0,
(rgb_ycc_indicator & 0x3), 0, 2);
} /* hdmitx_csc_config */
static void hdmitx_set_hw(struct hdmitx_dev *hdev)
{
enum hdmi_vic vic = HDMI_Unknown;
struct hdmi_format_para *para = NULL;
if (hdev->cur_video_param == NULL) {
pr_info("error at null vidpara!\n");
return;
}
vic = (enum hdmi_vic)hdev->cur_video_param->VIC;
para = hdmi_get_fmt_paras(vic);
if (para == NULL) {
pr_info("error at %s[%d] vic = %d\n", __func__, __LINE__, vic);
return;
}
pr_info(HW " config hdmitx IP vic = %d cd:%d cs: %d\n", vic,
hdev->para->cd, hdev->para->cs);
config_hdmi20_tx(vic, hdev,
hdev->para->cd,
TX_INPUT_COLOR_FORMAT,
hdev->para->cs);
}