297 lines
8.3 KiB
C
297 lines
8.3 KiB
C
/*
|
|
* Copyright 2018 NXP
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <command.h>
|
|
#include <asm/mach-imx/video.h>
|
|
#include <asm/arch/video_common.h>
|
|
#include <imx8_hdmi.h>
|
|
|
|
#include "API_General.h"
|
|
#include "vic_table.h"
|
|
#include "API_HDMITX.h"
|
|
#include "apb_cfg.h"
|
|
#include "externs.h"
|
|
#include "API_AVI.h"
|
|
#include "address.h"
|
|
#include "source_car.h"
|
|
#include "source_phy.h"
|
|
#include "API_AFE.h"
|
|
#include "source_vif.h"
|
|
#include "general_handler.h"
|
|
#include "mhl_hdtx_top.h"
|
|
|
|
|
|
#ifdef CONFIG_IMX8QM
|
|
#include "API_AFE_mcu1_dp.h"
|
|
#include "API_AFE_ss28fdsoi_kiran_hdmitx.h"
|
|
#endif
|
|
|
|
#ifdef CONFIG_IMX8M
|
|
#include "API_AFE_t28hpc_hdmitx.h"
|
|
#endif
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
#define ON 1
|
|
#define OFF 0
|
|
|
|
unsigned long g_encoding = 1; /* 1 RGB, 2 YUV 444, 4 YUV 422, 8 YUV 420 */
|
|
unsigned long g_color_depth = 8; /* 8 pits per color */
|
|
|
|
static int imx8_hdmi_set_vic_mode(int vic,
|
|
struct video_mode_settings *vms)
|
|
{
|
|
/*struct video_mode_settings *vms = &vm_settings[VM_USER]; */
|
|
uint32_t pixel_clock_kHz;
|
|
uint32_t frame_rate_Hz;
|
|
uint32_t frame_rate_frac_Hz;
|
|
uint32_t cea_vic;
|
|
char iflag;
|
|
|
|
if (vic >= VIC_MODE_COUNT) {
|
|
debug("%s(): unsupported VIC\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
|
|
vms->hfp = vic_table[vic][FRONT_PORCH];
|
|
vms->hbp = vic_table[vic][BACK_PORCH];
|
|
vms->hsync = vic_table[vic][HSYNC];
|
|
vms->vfp = vic_table[vic][TYPE_EOF];
|
|
vms->vbp = vic_table[vic][SOF];
|
|
vms->vsync = vic_table[vic][VSYNC];
|
|
vms->xres = vic_table[vic][H_ACTIVE];
|
|
vms->yres = vic_table[vic][V_ACTIVE];
|
|
|
|
vms->hpol = vic_table[vic][HSYNC_POL] != 0;
|
|
vms->vpol = vic_table[vic][VSYNC_POL] != 0;
|
|
|
|
cea_vic = vic_table[vic][VIC];
|
|
if (vic_table[vic][I_P] != 0)
|
|
iflag = 'i';
|
|
else
|
|
iflag = 'p';
|
|
pixel_clock_kHz = vic_table[vic][PIXEL_FREQ_KHZ];
|
|
frame_rate_Hz = vic_table[vic][V_FREQ_HZ] * 1000;
|
|
frame_rate_frac_Hz = frame_rate_Hz % 1000;
|
|
frame_rate_Hz /= 1000;
|
|
|
|
vms->pixelclock = pixel_clock_kHz;
|
|
|
|
debug("Cadence VIC %3d, CEA VIC %3d: %4d x %4d %c @ %3d.%03d [%6d kHz] Vpol=%d Hpol=%d\n",
|
|
vic, cea_vic, vms->xres, vms->yres, iflag, frame_rate_Hz,
|
|
frame_rate_frac_Hz, pixel_clock_kHz, vms->vpol, vms->hpol);
|
|
|
|
debug(" mode timing fp sync bp h:%3d %3d %3d v:%3d %3d %3d\n",
|
|
vms->hfp, vms->hsync, vms->hbp, vms->vfp, vms->vsync, vms->vbp);
|
|
|
|
return 0;
|
|
/*debug("leaving %s() ...\n", __func__); */
|
|
}
|
|
|
|
static int imx8_hdmi_init(int vic,
|
|
int encoding,
|
|
int color_depth,
|
|
bool pixel_clk_from_phy)
|
|
{
|
|
int ret;
|
|
#ifdef CONFIG_IMX8QM
|
|
sc_ipc_t ipcHndl = gd->arch.ipc_channel_handle;
|
|
void __iomem *hdmi_csr_base = (void __iomem *)0x56261000;
|
|
#endif
|
|
/*GENERAL_Read_Register_response regresp; */
|
|
/*uint8_t sts; */
|
|
uint32_t character_freq_khz;
|
|
|
|
uint8_t echo_msg[] = "echo test";
|
|
uint8_t echo_resp[sizeof(echo_msg) + 1];
|
|
/*uint8_t response; */
|
|
/*uint8_t dpcd_resp; */
|
|
/*uint8_t hdcp_resp; */
|
|
/*uint8_t capb_resp; */
|
|
/*uint32_t temp; */
|
|
|
|
/*================================================================== */
|
|
/* Parameterization: */
|
|
/*================================================================== */
|
|
|
|
/* VIC Mode - index from vic_table (see API_SRC/vic_table.c) */
|
|
VIC_MODES vic_mode = vic;
|
|
|
|
/* Pixel Encodeing Format */
|
|
/* PXL_RGB = 0x1, */
|
|
/* YCBCR_4_4_4 = 0x2, */
|
|
/* YCBCR_4_2_2 = 0x4, */
|
|
/* YCBCR_4_2_0 = 0x8, */
|
|
/* Y_ONLY = 0x10, */
|
|
VIC_PXL_ENCODING_FORMAT format = encoding;
|
|
/*VIC_PXL_ENCODING_FORMAT format = 1; */
|
|
|
|
/* B/W Balance Type: 0 no data, 1 IT601, 2 ITU709 */
|
|
BT_TYPE bw_type = 0;
|
|
|
|
/* bpp (bits per subpixel) - 8 24bpp, 10 30bpp, 12 36bpp, 16 48bpp */
|
|
uint8_t bps = color_depth;
|
|
|
|
/* Set HDMI TX Mode */
|
|
/* Mode = 0 - DVI, 1 - HDMI1.4, 2 HDMI 2.0 */
|
|
HDMI_TX_MAIL_HANDLER_PROTOCOL_TYPE ptype = 1;
|
|
|
|
if (vic_mode == VIC_MODE_97_60Hz)
|
|
ptype = 2;
|
|
|
|
/*================================================================== */
|
|
/* Parameterization done */
|
|
/*================================================================== */
|
|
#ifdef CONFIG_IMX8QM
|
|
/* set the pixel link mode and pixel type */
|
|
SC_MISC_SET_CONTROL(ipcHndl, SC_R_HDMI, SC_C_PHY_RESET, 0);
|
|
#if 1
|
|
SC_MISC_SET_CONTROL(ipcHndl, SC_R_DC_0, SC_C_PXL_LINK_MST1_ADDR, 1);
|
|
/*SC_MISC_SET_CONTROL(ipcHndl, SC_R_DC_0, SC_C_PXL_LINK_MST1_ADDR, 0);*/
|
|
if (g_clock_mode == CLOCK_MODES_HDMI_DUAL) {
|
|
SC_MISC_SET_CONTROL(ipcHndl, SC_R_DC_0,
|
|
SC_C_PXL_LINK_MST2_ADDR, 2);
|
|
/*SC_MISC_SET_CONTROL(ipcHndl, SC_R_DC_0,
|
|
SC_C_PXL_LINK_MST2_ADDR, 0); */
|
|
__raw_writel(0x6, hdmi_csr_base);
|
|
} else
|
|
#endif
|
|
__raw_writel(0x34, hdmi_csr_base);
|
|
#endif
|
|
cdn_api_init();
|
|
debug("CDN_API_Init completed\n");
|
|
|
|
ret = cdn_api_checkalive();
|
|
debug("CDN_API_CheckAlive returned ret = %d\n", ret);
|
|
|
|
if (ret)
|
|
return -EPERM;
|
|
|
|
ret = cdn_api_general_test_echo_ext_blocking(echo_msg,
|
|
echo_resp,
|
|
sizeof(echo_msg),
|
|
CDN_BUS_TYPE_APB);
|
|
debug("_General_Test_Echo_Ext_blocking - (ret = %d echo_resp = %s)\n",
|
|
ret, echo_resp);
|
|
|
|
/* Configure PHY */
|
|
character_freq_khz = phy_cfg_t28hpc(4, vic_mode, bps,
|
|
format, pixel_clk_from_phy);
|
|
debug("phy_cfg_t28hpc (character_freq_mhz = %d)\n",
|
|
character_freq_khz);
|
|
|
|
/*phy_reset(1); */
|
|
|
|
#ifdef CONFIG_IMX8QM
|
|
SC_MISC_SET_CONTROL(ipcHndl, SC_R_HDMI, SC_C_PHY_RESET, 1);
|
|
#endif
|
|
hdmi_tx_t28hpc_power_config_seq(4);
|
|
#ifdef CONFIG_IMX8QM
|
|
/* Set the lane swapping */
|
|
ret = cdn_api_general_write_register_blocking
|
|
(ADDR_SOURCD_PHY + (LANES_CONFIG << 2),
|
|
F_SOURCE_PHY_LANE0_SWAP(3) | F_SOURCE_PHY_LANE1_SWAP(0) |
|
|
F_SOURCE_PHY_LANE2_SWAP(1) | F_SOURCE_PHY_LANE3_SWAP(2) |
|
|
F_SOURCE_PHY_COMB_BYPASS(0) | F_SOURCE_PHY_20_10(1));
|
|
#else
|
|
/* Set the lane swapping */
|
|
ret = cdn_api_general_write_register_blocking
|
|
(ADDR_SOURCD_PHY + (LANES_CONFIG << 2),
|
|
F_SOURCE_PHY_LANE0_SWAP(0) | F_SOURCE_PHY_LANE1_SWAP(1) |
|
|
F_SOURCE_PHY_LANE2_SWAP(2) | F_SOURCE_PHY_LANE3_SWAP(3) |
|
|
F_SOURCE_PHY_COMB_BYPASS(0) | F_SOURCE_PHY_20_10(1));
|
|
#endif
|
|
debug("_General_Write_Register_blocking LANES_CONFIG ret = %d\n", ret);
|
|
|
|
ret = CDN_API_HDMITX_Init_blocking();
|
|
debug("CDN_API_STATUS CDN_API_HDMITX_Init_blocking ret = %d\n", ret);
|
|
|
|
ret = CDN_API_HDMITX_Init_blocking();
|
|
debug("CDN_API_STATUS CDN_API_HDMITX_Init_blocking ret = %d\n", ret);
|
|
|
|
ret = CDN_API_HDMITX_Set_Mode_blocking(ptype, character_freq_khz);
|
|
debug("CDN_API_HDMITX_Set_Mode_blocking ret = %d\n", ret);
|
|
|
|
ret = cdn_api_set_avi(vic_mode, format, bw_type);
|
|
debug("cdn_api_set_avi ret = %d\n", ret);
|
|
|
|
ret = CDN_API_HDMITX_SetVic_blocking(vic_mode, bps, format);
|
|
debug("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
|
|
|
|
#ifdef CONFIG_IMX8QM
|
|
{
|
|
GENERAL_Read_Register_response regresp;
|
|
/* adjust the vsync/hsync polarity */
|
|
cdn_api_general_read_register_blocking(ADDR_SOURCE_VIF +
|
|
(HSYNC2VSYNC_POL_CTRL
|
|
<< 2),
|
|
®resp);
|
|
debug("Initial HSYNC2VSYNC_POL_CTRL: 0x%x\n", regresp.val);
|
|
if ((regresp.val & 0x3) != 0)
|
|
__raw_writel(0x4, hdmi_csr_base);
|
|
}
|
|
#endif
|
|
/*regresp.val &= ~0x03; // clear HSP and VSP bits */
|
|
/*debug("Final HSYNC2VSYNC_POL_CTRL: 0x%x\n",regresp.val); */
|
|
/*CDN_API_General_Write_Register_blocking(ADDR_DPTX_FRAMER +
|
|
(DP_FRAMER_SP << 2),
|
|
regresp.val); */
|
|
|
|
udelay(20000);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int imx8_hdmi_enable(int encoding,
|
|
struct video_mode_settings *vms)
|
|
{
|
|
int vic = 0;
|
|
const int use_phy_pixel_clk = 1;
|
|
|
|
/* map the resolution to a VIC index in the vic table*/
|
|
if ((vms->xres == 1280) && (vms->yres == 720))
|
|
vic = 1; /* 720p60 */
|
|
else if ((vms->xres == 1920) && (vms->yres == 1080))
|
|
vic = 2; /* 1080p60 */
|
|
else if ((vms->xres == 3840) && (vms->yres == 2160))
|
|
vic = 3; /* 2160p60 */
|
|
else /* if ((vms->xres == 720) && (vms->yres == 480)) */
|
|
vic = 0; /* 480p60 */
|
|
|
|
imx8_hdmi_set_vic_mode(vic, vms);
|
|
return imx8_hdmi_init(vic, encoding, g_color_depth, use_phy_pixel_clk);
|
|
}
|
|
|
|
void imx8_hdmi_disable(void)
|
|
{
|
|
int ret;
|
|
GENERAL_READ_REGISTER_RESPONSE resp;
|
|
|
|
resp.val = 0;
|
|
ret = cdn_api_general_read_register_blocking(ADDR_SOURCE_MHL_HD +
|
|
(HDTX_CONTROLLER << 2),
|
|
&resp);
|
|
if (ret != CDN_OK) {
|
|
printf("%s(): dn_api_general_read_register_blocking failed\n",
|
|
__func__);
|
|
/*return;*/
|
|
}
|
|
|
|
resp.val &= ~F_DATA_EN(1); /* disable HDMI */
|
|
/*resp.val |= F_SET_AVMUTE( 1);*/
|
|
|
|
ret = cdn_api_general_write_register_blocking(ADDR_SOURCE_MHL_HD +
|
|
(HDTX_CONTROLLER << 2),
|
|
resp.val);
|
|
if (ret != CDN_OK) {
|
|
printf("%s(): dn_api_general_write_register_blocking failed\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
}
|