diff --git a/drivers/media/vout/hdmitx21/hdmi_tx_video.c b/drivers/media/vout/hdmitx21/hdmi_tx_video.c index 10f1f82185..c50c126a8a 100644 --- a/drivers/media/vout/hdmitx21/hdmi_tx_video.c +++ b/drivers/media/vout/hdmitx21/hdmi_tx_video.c @@ -17,6 +17,7 @@ #include #include #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) @@ -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; } diff --git a/drivers/media/vout/hdmitx21/hw/enc_cfg_hw.c b/drivers/media/vout/hdmitx21/hw/enc_cfg_hw.c index b1b4eef5e4..2071a0c843 100644 --- a/drivers/media/vout/hdmitx21/hw/enc_cfg_hw.c +++ b/drivers/media/vout/hdmitx21/hw/enc_cfg_hw.c @@ -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 diff --git a/drivers/media/vout/hdmitx21/hw/hdmi_tx_hw.c b/drivers/media/vout/hdmitx21/hw/hdmi_tx_hw.c index e76443d1cb..f62ae062d6 100644 --- a/drivers/media/vout/hdmitx21/hw/hdmi_tx_hw.c +++ b/drivers/media/vout/hdmitx21/hw/hdmi_tx_hw.c @@ -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); diff --git a/drivers/media/vout/hdmitx21/hw/hw_clk.c b/drivers/media/vout/hdmitx21/hw/hw_clk.c index 4b91b09b9e..4eb5f99bec 100644 --- a/drivers/media/vout/hdmitx21/hw/hw_clk.c +++ b/drivers/media/vout/hdmitx21/hw/hw_clk.c @@ -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",