Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 34 additions & 13 deletions drivers/media/vout/hdmitx21/hdmi_tx_video.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/mutex.h>
#include <linux/cdev.h>
#include "hdmi_tx_module.h"
#include "hdmi_tx.h"
#include "hw/common.h"

#define to_hdmitx21_dev(x) container_of(x, struct hdmitx_dev, tx_comm)
Expand Down Expand Up @@ -159,28 +160,48 @@ int hdmitx21_set_display(struct hdmitx_dev *hdev, enum hdmi_vic videocode)
return ret;
}

/*
* HDMI 1.4a/1.4b 3D signaling (HDMI Vendor Specific InfoFrame, PacketType
* 0x81, IEEE OUI 0x000C03, HDMI_Video_Format = 3'b010) as required by
* "High-Definition Multimedia Interface Specification Version 1.4a,
* Extraction of 3D Signaling Portion", section 8.2.3 / Table 8-10..8-13.
*
* NOTE: this must NOT be routed through hdmi_vend_infoframe_rawset().
* That helper decides between the HDMI_INFOFRAME_TYPE_VENDOR (classic
* VSIF, packet buffer sel=5) and HDMI_INFOFRAME_TYPE_VENDOR2 (HF-VSIF,
* packet buffer sel=8, see hw/hdmi_tx_pktmgmt.c) buffers purely based on
* rxcap.ifdb_present / additional_vsif_num, i.e. it implements the Dolby
* Vision CTS coexistence rules for *simultaneous* classic-VSIF + HF-VSIF
* transmission (see the "dolby cts case89/92/93" comments in
* hdmi_tx_infoframe.c). The InfoFrame Data Block (IFDB) that
* ifdb_present is derived from is a CTA-861-G / HDMI 2.1 EDID data
* block; legacy HDMI 1.4a 3D sinks (the class of device this packet is
* actually for) never expose it, so rxcap.ifdb_present is always false
* for them and every call used to fall into the "!ifdb_present" branch,
* which places the packet into the HF-VSIF buffer instead of the
* classic VSIF buffer that 3D-only sinks actually parse. Send the
* legacy 3D VSIF unconditionally on the classic VSIF buffer instead,
* exactly as hdmitx20/hdmi_tx_video.c::hdmi_set_3d() always does.
*/
int hdmi21_set_3d(struct hdmitx_dev *hdev, int type, u32 param)
{
u8 db[28] = {0};
u8 *ven_db = &db[1];
u8 ven_hb[3];
struct hdmi_vendor_infoframe *info;
u8 body[31] = {0};
u8 *ven_db = &body[4]; /* body[3] = PB0 (checksum), body[4] = PB1 */

info = &hdev->infoframes.vend.vendor.hdmi;
body[0] = 0x81; /* HB0: Packet Type */
body[1] = 0x01; /* HB1: Version */
body[2] = 0x6; /* HB2: Length (Nv) */

ven_hb[0] = 0x81;
ven_hb[1] = 0x01;
ven_hb[2] = 0x6;
if (type == T3D_DISABLE) {
hdmi_vend_infoframe_rawset(ven_hb, db);
hdmitx_infoframe_send(HDMI_INFOFRAME_TYPE_VENDOR, NULL);
} else {
ven_db[0] = GET_OUI_BYTE0(HDMI_IEEE_OUI);
ven_db[1] = GET_OUI_BYTE1(HDMI_IEEE_OUI);
ven_db[2] = GET_OUI_BYTE2(HDMI_IEEE_OUI);
ven_db[3] = 0x40;
ven_db[4] = type << 4;
ven_db[5] = param << 4;
hdmi_vend_infoframe_rawset(ven_hb, db);
ven_db[3] = 0x40; /* PB4: HDMI_Video_Format = 3'b010 */
ven_db[4] = type << 4; /* PB5: 3D_Structure */
ven_db[5] = param << 4; /* PB6: 3D_Ext_Data */
hdmitx_infoframe_send(HDMI_INFOFRAME_TYPE_VENDOR, body);
}
return 0;
}
Expand Down
120 changes: 120 additions & 0 deletions drivers/media/vout/hdmitx21/hw/enc_cfg_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,130 @@
/* note, venc setting will be override on dsc encoder side
* so this function is optional when dsc_en = 1
*/

/*
* 3D Frame Packing ENCP timing, ported verbatim from the hdmitx20 (G12B)
* driver's tvregstab_3dfp[] (hdmitx20/hw/enc_cfg_hw.c). The generic
* v_total/v_active doubling formula used below for 2D modes does not
* reproduce these hardware-validated values exactly (verified to be off
* by a few lines/pixels on the DE window for 1080p24), which is precise
* enough to matter for the tight 3D FP active-space timing but not for
* ordinary 2D video. Amlogic's 1080p24/50/60 3D FP tables are identical,
* so a single 1080p entry covers all three; 720p50/60 get their own.
*/
struct enc_cfg_3dfp_reg {
u32 reg;
u32 val;
};

static const struct enc_cfg_3dfp_reg enc_cfg_3dfp_1080p[] = {
{ENCP_VIDEO_MODE, 0x4040},
{ENCP_VIDEO_MODE_ADV, 0x18},
{ENCP_VIDEO_MAX_PXCNT, 0xABD},
{ENCP_VIDEO_MAX_LNCNT, 0x8C9},
{ENCP_VIDEO_HAVON_BEGIN, 0xC0},
{ENCP_VIDEO_HAVON_END, 0x83F},
{ENCP_VIDEO_VAVON_BLINE, 0x29},
{ENCP_VIDEO_VAVON_ELINE, 0x8C5},
{ENCP_VIDEO_HSO_BEGIN, 0x0},
{ENCP_VIDEO_HSO_END, 0x2C},
{ENCP_VIDEO_VSO_BEGIN, 0x1E},
{ENCP_VIDEO_VSO_END, 0x32},
{ENCP_VIDEO_VSO_BLINE, 0x0},
{ENCP_VIDEO_VSO_ELINE, 0x5},
{ENCP_DVI_HSO_BEGIN, 0x2},
{ENCP_DVI_HSO_END, 0x2E},
{ENCP_DVI_VSO_BLINE_EVN, 0x0},
{ENCP_DVI_VSO_BLINE_ODD, 0x0},
{ENCP_DVI_VSO_ELINE_EVN, 0x5},
{ENCP_DVI_VSO_ELINE_ODD, 0x0},
{ENCP_DVI_VSO_BEGIN_EVN, 0x2},
{ENCP_DVI_VSO_BEGIN_ODD, 0x0},
{ENCP_DVI_VSO_END_EVN, 0x2},
{ENCP_DVI_VSO_END_ODD, 0x0},
{ENCP_DE_H_BEGIN, 0xC2},
{ENCP_DE_H_END, 0x842},
{ENCP_DE_V_BEGIN_EVEN, 0x29},
{ENCP_DE_V_END_EVEN, 0x8C6},
{ENCP_DE_V_BEGIN_ODD, 0x0},
{ENCP_DE_V_END_ODD, 0x0},
};

static const struct enc_cfg_3dfp_reg enc_cfg_3dfp_720p[] = {
{ENCP_VIDEO_MODE, 0x4040},
{ENCP_VIDEO_MODE_ADV, 0x18},
{ENCP_VIDEO_MAX_PXCNT, 0x7BB},
{ENCP_VIDEO_MAX_LNCNT, 0x5DB},
{ENCP_VIDEO_HAVON_BEGIN, 0x104},
{ENCP_VIDEO_HAVON_END, 0x603},
{ENCP_VIDEO_VAVON_BLINE, 0x19},
{ENCP_VIDEO_VAVON_ELINE, 0x5D6},
{ENCP_VIDEO_HSO_BEGIN, 0x0},
{ENCP_VIDEO_HSO_END, 0x28},
{ENCP_VIDEO_VSO_BEGIN, 0x1E},
{ENCP_VIDEO_VSO_END, 0x32},
{ENCP_VIDEO_VSO_BLINE, 0x0},
{ENCP_VIDEO_VSO_ELINE, 0x5},
{ENCP_DVI_HSO_BEGIN, 0x2},
{ENCP_DVI_HSO_END, 0x2A},
{ENCP_DVI_VSO_BLINE_EVN, 0x0},
{ENCP_DVI_VSO_BLINE_ODD, 0x0},
{ENCP_DVI_VSO_ELINE_EVN, 0x5},
{ENCP_DVI_VSO_ELINE_ODD, 0x0},
{ENCP_DVI_VSO_BEGIN_EVN, 0x2},
{ENCP_DVI_VSO_BEGIN_ODD, 0x0},
{ENCP_DVI_VSO_END_EVN, 0x2},
{ENCP_DVI_VSO_END_ODD, 0x0},
{ENCP_DE_H_BEGIN, 0x106},
{ENCP_DE_H_END, 0x606},
{ENCP_DE_V_BEGIN_EVEN, 0x19},
{ENCP_DE_V_END_EVEN, 0x5D7},
{ENCP_DE_V_BEGIN_ODD, 0x0},
{ENCP_DE_V_END_ODD, 0x0},
};

static bool config_tv_enc_3dfp_fixed(struct hdmitx_dev *hdev, enum hdmi_vic vic)
{
const struct enc_cfg_3dfp_reg *regs;
u32 count;
u32 i;

switch (vic) {
case HDMI_32_1920x1080p24_16x9:
case HDMI_33_1920x1080p25_16x9:
case HDMI_34_1920x1080p30_16x9:
case HDMI_16_1920x1080p60_16x9:
case HDMI_31_1920x1080p50_16x9:
regs = enc_cfg_3dfp_1080p;
count = ARRAY_SIZE(enc_cfg_3dfp_1080p);
break;
case HDMI_4_1280x720p60_16x9:
case HDMI_19_1280x720p50_16x9:
regs = enc_cfg_3dfp_720p;
count = ARRAY_SIZE(enc_cfg_3dfp_720p);
break;
default:
return false;
}

hd21_write_reg(ENCP_VIDEO_EN, 0);
hd21_write_reg(ENCI_VIDEO_EN, 0);
for (i = 0; i < count; i++)
hd21_write_reg(regs[i].reg, regs[i].val);
hd21_write_reg(ENCI_VIDEO_EN, 0);
hd21_write_reg(VPU_HDMI_SETTING, 0x8c);

return true;
}

static void config_tv_enc_calc(struct hdmitx_dev *hdev, enum hdmi_vic vic)
{
const struct hdmi_timing *tp = NULL;
struct hdmi_timing timing = {0};

if (hdev->tx_comm.flag_3dfp && config_tv_enc_3dfp_fixed(hdev, vic))
return;

/* adjust to align upsample and video enable */
u32 hsync_st = 5; // hsync start pixel count
u32 vsync_st = 1; // vsync start line count
Expand Down
23 changes: 23 additions & 0 deletions drivers/media/vout/hdmitx21/hw/hdmi_tx_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1568,7 +1568,30 @@ static int hdmitx_set_dispmode(struct hdmitx_hw_common *tx_hw)
}
}

/* 3D Frame Packing/TAB/SBS: give ENCP/VPU time to settle into the
* new timing before starting PHY training, or some displays' HDMI
* receivers lock onto the still-transitioning signal and never
* re-train once it stabilizes. hdmitx20 handles this by deferring
* PHY enable to a separate later step triggered from userspace
* (hdmitx_set_enc_hw(), "enable phy by SystemControl at last step");
* here we just wait out one frame in place instead, so this stays
* self-contained regardless of which caller triggered the mode set.
*/
if (hdev->tx_comm.flag_3dfp || hdev->tx_comm.flag_3dtb || hdev->tx_comm.flag_3dss)
usleep_range(20000, 20500);
hdmitx_set_phy(hdev);
/*
* Frame Packing VSIF was sent (from config_store(), see
* hdmi_tx_video.c::hdmi21_set_3d()) before this modeset ran, i.e.
* against the old, now-superseded timing. Re-send it now that ENCP
* has been reprogrammed for the final 2x-height FP timing, so the
* packet scheduler's auto blanking-relative position (PKT_AUTO_0)
* gets recomputed against the timing that is actually still active
* once the sink samples it. TAB/SBS need no such re-send: they never
* change v_total/pixel clock, so their original send stays valid.
*/
if (hdev->tx_comm.flag_3dfp)
hdmi21_set_3d(hdev, T3D_FRAME_PACKING, 0);
if (hdev->tx_hw.chip_data->chip_type == MESON_CPU_ID_S5) {
#ifndef CONFIG_AMLOGIC_ZAPPER_CUT
hdmitx_dfm_cfg(0, 0);
Expand Down
12 changes: 12 additions & 0 deletions drivers/media/vout/hdmitx21/hw/hw_clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,18 @@ void set_hdmitx_s6_htx_pll(struct hdmitx_dev *hdev)
base_pixel_clk = base_pixel_clk * 10; /* for tmds modes, here should multi 10 */
if (cs == HDMI_COLORSPACE_YUV420)
base_pixel_clk /= 2;
/*
* 3D Frame Packing: config_tv_enc_calc() already doubles v_active/
* v_total for the ENCP timing generator (see enc_cfg_hw.c), so the
* TMDS pixel clock must be doubled here as well or the encoder scans
* out twice the line count at half the intended frame rate, causing
* a growing sync offset (V-Sync errors / tearing, worst towards the
* end of the frame, i.e. the dependent/right-eye view).
* This mirrors the dedicated setting_3dfp_enc_clk_val PLL table used
* by the legacy hdmitx20 driver for the same purpose.
*/
if (hdev->tx_comm.flag_3dfp)
base_pixel_clk *= 2;
pr_info("%s[%d] calculate pixel_clk to %d\n", __func__, __LINE__, base_pixel_clk);
if (base_pixel_clk > MAX_HTXPLL_VCO) {
pr_err("%s[%d] base_pixel_clk %d over MAX_HTXPLL_VCO %d\n",
Expand Down