Re: [PATCH 09/13] video: mediatek: add new hdmi driver

David Lechner <[email protected]>
Newsgroups gmane.comp.boot-loaders.u-boot
Message-ID <[email protected]>
On 7/28/26 7:29 AM, Julien Stephan wrote:
> Add a UCLASS_VIDEO driver for the HDMI TX v2 IP found on the MT8188.
> 
> On probe, the driver waits for a plugged and powered display, reads
> its EDID through the DDC bus to select the preferred mode, configures
> the HDMI controller and PHY accordingly, and then programs all the
> components of the vdosys1 pipeline (MDP RDMA, padding, VPP merge,
> ETHDR mixer, mutex, DPI1) to scan out the framebuffer. The
> framebuffer lives in a dedicated reserved-memory region referenced by
> the "memory-region" property of the hdmi node.
> 
> Signed-off-by: Pavlo Yadvychuk <[email protected]>
> Signed-off-by: Julien Stephan <[email protected]>
> ---
>  drivers/video/Kconfig                         |   1 +
>  drivers/video/Makefile                        |   1 +
>  drivers/video/mediatek/Kconfig                |  21 +
>  drivers/video/mediatek/Makefile               |  16 +
>  drivers/video/mediatek/mtk_hdmi.c             | 919 ++++++++++++++++++++++++++
>  drivers/video/mediatek/mtk_mt8188_hdmi_regs.h | 103 +++
>  6 files changed, 1061 insertions(+)
> 
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 15000e21840..cb3ba6a6f63 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -770,6 +770,7 @@ config VIDEO_LCD_SPI_MISO
>  	  option takes a string in the format understood by 'sunxi_name_to_gpio'
>  	  function, e.g. PH1 for pin 1 of port H.
>  
> +source "drivers/video/mediatek/Kconfig"
>  source "drivers/video/meson/Kconfig"
>  
>  config VIDEO_MVEBU
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 082b8967982..a20011b9b17 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -92,5 +92,6 @@ obj-$(CONFIG_VIDEO_SEPS525) += seps525.o
>  obj-$(CONFIG_VIDEO_ZYNQMP_DPSUB) += zynqmp/
>  
>  obj-y += bridge/
> +obj-y += mediatek/
>  obj-y += sunxi/
>  obj-y += tegra/
> diff --git a/drivers/video/mediatek/Kconfig b/drivers/video/mediatek/Kconfig
> new file mode 100644
> index 00000000000..427d7e36b90
> --- /dev/null
> +++ b/drivers/video/mediatek/Kconfig
> @@ -0,0 +1,21 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# Copyright (C) 2022 BayLibre, SAS
> +#
> +# Author: Julien Stephan <[email protected]>
> +
> +config VIDEO_MEDIATEK_HDMI
> +	bool "Video HDMI Support for Mediatek SoCs"
> +	depends on VIDEO && ARCH_MEDIATEK
> +	depends on DM_I2C && PHY && POWER_DOMAIN
> +	select I2C_EDID
> +	select MISC
> +	select PHY_MTK_HDMI
> +	select MTK_POWER_DOMAIN
> +	select SYS_I2C_DDC_MTK
> +	help
> +	  Enable support for the HDMI TX output found on recent MediaTek
> +	  SoCs such as the MT8188. The driver reads the EDID of the
> +	  connected display, selects its preferred mode and drives the
> +	  vdosys1 display pipeline (MDP RDMA, padding, merge, ETHDR
> +	  mixer, DPI) to scan out the U-Boot framebuffer over HDMI.
> diff --git a/drivers/video/mediatek/Makefile b/drivers/video/mediatek/Makefile
> new file mode 100644
> index 00000000000..af54450a836
> --- /dev/null
> +++ b/drivers/video/mediatek/Makefile
> @@ -0,0 +1,16 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Copyright (c) 2023 MediaTek Inc.
> +#
> +# Author: Julien Stephan <[email protected]>
> +
> +obj-$(CONFIG_VIDEO_MEDIATEK_HDMI) += \

Similar to other comment, if this is for just mt8188, then the
config option should also be CONFIG_VIDEO_MEDIATEK_HDMI_MT8188.
Othweriwse, _mt8188 should be removed from all of the file names.

> +	mtk_hdmi.o \
> +	mtk_disp_comp.o \
> +	mtk_dpi_mt8188.o \
> +	mtk_mdp_rdma_mt8188.o \
> +	mtk_disp_merge_mt8188.o \
> +	mtk_disp_mixer_mt8188.o \
> +	mtk_disp_mutex_mt8188.o \
> +	mtk_disp_padding_mt8188.o \
> +	mtk_vdosys1_mt8188.o
> diff --git a/drivers/video/mediatek/mtk_hdmi.c b/drivers/video/mediatek/mtk_hdmi.c
> new file mode 100644
> index 00000000000..e174585fcbb
> --- /dev/null
> +++ b/drivers/video/mediatek/mtk_hdmi.c
> @@ -0,0 +1,919 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2025 BayLibre, SAS
> + * Author: Julien Stephan <[email protected]>
> + */
> +
> +#include <asm/io.h>
> +#include <asm/system.h>
> +#include <clk.h>
> +#include <dm.h>
> +#include <dm/device_compat.h>
> +#include <edid.h>
> +#include <errno.h>
> +#include <generic-phy.h>
> +#include <i2c.h>
> +#include <linux/delay.h>
> +#include <video.h>
> +
> +#include "mtk_disp_comp.h"
> +#include "mtk_disp_merge_mt8188.h"
> +#include "mtk_disp_mixer_mt8188.h"
> +#include "mtk_disp_mutex_mt8188.h"
> +#include "mtk_disp_padding_mt8188.h"
> +#include "mtk_dpi_mt8188.h"
> +#include "mtk_mdp_rdma_mt8188.h"
> +#include "mtk_mt8188_hdmi_regs.h"
> +#include "mtk_vdosys1_mt8188.h"
> +
> +#define MTK_HDMI_MAX_WIDTH			3840
> +#define MTK_HDMI_MAX_HEIGHT			2160
> +
> +#define MTK_HDMI_HPD_TIMEOUT_MS			100
> +
> +/* 4 byte header + 13 byte payload */
> +#define HDMI_AVI_INFOFRAME_SIZE			17
> +/* 4 byte header + 25 byte payload */
> +#define HDMI_SPD_INFOFRAME_SIZE			29
> +
> +#define RGB444_8bit				BIT(0)
> +#define RGB444_10bit				BIT(1)
> +#define RGB444_12bit				BIT(2)
> +#define RGB444_16bit				BIT(3)
> +#define YCBCR444_8bit				BIT(4)
> +#define YCBCR444_10bit				BIT(5)
> +#define YCBCR444_12bit				BIT(6)
> +#define YCBCR444_16bit				BIT(7)
> +
> +#define YCBCR422_8bit_NO_SUPPORT		BIT(8)
> +#define YCBCR422_10bit_NO_SUPPORT		BIT(9)
> +#define YCBCR422_12bit				BIT(10)
> +#define YCBCR422_16bit_NO_SUPPORT		BIT(11)
> +
> +#define YCBCR420_8bit				BIT(12)
> +#define YCBCR420_10bit				BIT(13)
> +#define YCBCR420_12bit				BIT(14)
> +#define YCBCR420_16bit				BIT(15)
> +
> +#define BYTES_TO_UINT32(msb, b1, b2, lsb)	\
> +	((((msb) & 0xff) << 24) + (((b1) & 0xff) << 16) + (((b2) & 0xff) << 8) + \
> +	 (((lsb) & 0xff)))

Looks like we could replace this with get_unaligned_le32() and get_unaligned_le24().
The latter would need to be ported from Linux.

> +
> +enum hdmi_color_depth {
> +	HDMI_8_BIT,
> +	HDMI_10_BIT,
> +	HDMI_12_BIT,
> +	HDMI_16_BIT,
> +};
> +
> +enum hdmi_colorspace {
> +	HDMI_COLORSPACE_RGB,
> +	HDMI_COLORSPACE_YUV422,
> +	HDMI_COLORSPACE_YUV444,
> +	HDMI_COLORSPACE_YUV420,
> +	HDMI_COLORSPACE_RESERVED4,
> +	HDMI_COLORSPACE_RESERVED5,
> +	HDMI_COLORSPACE_RESERVED6,
> +	HDMI_COLORSPACE_IDO_DEFINED,
> +};
> +
> +enum hdmi_colorimetry {
> +	HDMI_COLORIMETRY_NONE,
> +	HDMI_COLORIMETRY_ITU_601,
> +	HDMI_COLORIMETRY_ITU_709,
> +	HDMI_COLORIMETRY_EXTENDED,
> +};

Should some of these be moved to a generic header? I assume they
are the same everywhere (e.g. as seen in linux/hdmi.h).

> +
> +struct mtk_hdmi {
> +	struct udevice *dev;
> +	struct udevice *ddc_bus;
> +	struct udevice *dpi1;
> +	struct udevice *vdosys1;
> +	struct udevice *merge3;
> +	struct udevice *merge5;
> +	struct udevice *mixer;
> +	struct udevice *mutex;
> +	struct udevice *padding4;
> +	struct udevice *padding5;
> +	struct udevice *rdma4;
> +	struct udevice *rdma5;
> +	struct phy phy;
> +	fdt_addr_t regs;
> +	struct clk_bulk clk_bulk;
> +	u64 support_csp_depth;
> +	u64 set_csp_depth;
> +	enum hdmi_colorspace csp;
> +	enum hdmi_color_depth color_depth;
> +	enum hdmi_colorimetry colorimetry;
> +	struct display_timing mode;
> +};
> +
> +enum hdmi_hpd_state {
> +	HDMI_PLUG_OUT = 0,
> +	HDMI_PLUG_IN_AND_SINK_POWER_ON,
> +	HDMI_PLUG_IN_ONLY,
> +};
> +
> +static u32 mtk_hdmi_read(struct mtk_hdmi *hdmi, u32 offset)
> +{
> +	return readl(hdmi->regs + offset);
> +}
> +
> +static void mtk_hdmi_write(struct mtk_hdmi *hdmi, u32 offset, u32 val)
> +{
> +	writel(val, hdmi->regs + offset);
> +}
> +
> +static void mtk_hdmi_mask(struct mtk_hdmi *hdmi, u32 offset, u32 val, u32 mask)

mtk_hdmi_update() is better name?

> +{
> +	fdt_addr_t reg = hdmi->regs + offset;
> +	u32 tmp;
> +
> +	tmp = readl(reg);
> +	tmp = (tmp & ~mask) | (val & mask);
> +	writel(tmp, reg);
> +}
> +
> +static void mtk_hdmi_enable_hdmi_mode(struct mtk_hdmi *hdmi, bool enable)
> +{
> +	if (enable)
> +		mtk_hdmi_mask(hdmi, TOP_CFG00, HDMI_MODE_HDMI, HDMI_MODE_HDMI);
> +	else
> +		mtk_hdmi_mask(hdmi, TOP_CFG00, HDMI_MODE_DVI, HDMI_MODE_HDMI);

Would be a bit easier to see what is different like:

	u32 value = enable : HDMI_MODE_HDMI : HDMI_MODE_DVI;

	mtk_hdmi_mask(hdmi, TOP_CFG00, value, HDMI_MODE_HDMI);

Same applies below.

> +}
> +
> +static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdmi, bool black)
> +{
> +	if (black)
> +		mtk_hdmi_mask(hdmi, TOP_VMUTE_CFG1, REG_VMUTE_EN, REG_VMUTE_EN);
> +	else
> +		mtk_hdmi_mask(hdmi, TOP_VMUTE_CFG1, 0, REG_VMUTE_EN);
> +}
> +
> +static void mtk_hdmi_hw_reset(struct mtk_hdmi *hdmi)
> +{
> +	mtk_hdmi_mask(hdmi, HDMI_CONFIG, 0x0 << HDMITX_SW_RSTB_SHIFT,

So just 0 to make it shorter?

> +		      HDMITX_SW_RSTB);
> +	udelay(5);
> +	mtk_hdmi_mask(hdmi, HDMI_CONFIG, 0x1 << HDMITX_SW_RSTB_SHIFT,

We already have HDMITX_SW_RSTB macro.

> +		      HDMITX_SW_RSTB);
> +}
> +
> +static inline void mtk_hdmi_set_sw_hpd(struct mtk_hdmi *hdmi, bool high)
> +{
> +	if (high)
> +		mtk_hdmi_mask(hdmi, HDMI_CONFIG, 0x1 << HDMITX_SW_HPD_SHIFT,

HDMITX_SW_HPD

> +			      HDMITX_SW_HPD);
> +	else
> +		mtk_hdmi_mask(hdmi, HDMI_CONFIG, 0x0 << HDMITX_SW_HPD_SHIFT,
> +			      HDMITX_SW_HPD);
> +}
> +
> +static void mtk_hdmi_set_deep_color(struct mtk_hdmi *hdmi, bool is_hdmi_sink)
> +{
> +	unsigned int deep_color = 0;

I assume 0 is DEEPCOLOR_MODE_8BIT? Would make more sense to put this
in the default case if it is meant as a fallback.

> +
> +	/* ycbcr422 12bit no deep color */
> +	if (hdmi->csp == HDMI_COLORSPACE_YUV422) {
> +		deep_color = DEEPCOLOR_MODE_8BIT;
> +	} else {
> +		switch (hdmi->color_depth) {
> +		case HDMI_8_BIT:
> +			deep_color = DEEPCOLOR_MODE_8BIT;
> +			break;
> +		case HDMI_10_BIT:
> +			deep_color = DEEPCOLOR_MODE_10BIT;
> +			break;
> +		case HDMI_12_BIT:
> +			deep_color = DEEPCOLOR_MODE_12BIT;
> +			break;
> +		case HDMI_16_BIT:
> +			deep_color = DEEPCOLOR_MODE_16BIT;
> +			break;
> +		default:
> +			dev_warn(hdmi->dev, "Unsupported color depth %d\n",
> +				 hdmi->color_depth);

Missing break. Or should it return?

> +		}
> +	}
> +
> +	mtk_hdmi_mask(hdmi, TOP_CFG00, deep_color, DEEPCOLOR_MODE_MASKBIT);
> +
> +	/* GCP */
> +	mtk_hdmi_mask(hdmi, TOP_CFG00, 0, DEEPCOLOR_PAT_EN);
> +	if (is_hdmi_sink && deep_color != DEEPCOLOR_MODE_8BIT)
> +		mtk_hdmi_mask(hdmi, TOP_MISC_CTLR, DEEP_COLOR_ADD,
> +			      DEEP_COLOR_ADD);
> +	else
> +		mtk_hdmi_mask(hdmi, TOP_MISC_CTLR, 0, DEEP_COLOR_ADD);
> +}
> +
> +static void mtk_hdmi_yuv420_downsample(struct mtk_hdmi *hdmi, bool enable)

This could just be 2 different functions since nothing is shared between
the two branches.

> +{
> +	if (enable) {
> +		mtk_hdmi_mask(hdmi, HDMI_CONFIG,
> +			      HDMI_YUV420_MODE | HDMITX_SW_HPD,
> +			      HDMI_YUV420_MODE | HDMITX_SW_HPD);
> +		mtk_hdmi_mask(hdmi, VID_DOWNSAMPLE_CONFIG,
> +			      C444_C422_CONFIG_ENABLE, C444_C422_CONFIG_ENABLE);
> +		mtk_hdmi_mask(hdmi, VID_DOWNSAMPLE_CONFIG,
> +			      C422_C420_CONFIG_ENABLE, C422_C420_CONFIG_ENABLE);
> +		mtk_hdmi_mask(hdmi, VID_DOWNSAMPLE_CONFIG, 0,
> +			      C422_C420_CONFIG_BYPASS);
> +		mtk_hdmi_mask(hdmi, VID_DOWNSAMPLE_CONFIG,
> +			      C422_C420_CONFIG_OUT_CB_OR_CR,
> +			      C422_C420_CONFIG_OUT_CB_OR_CR);
> +		mtk_hdmi_mask(hdmi, VID_OUT_FORMAT,
> +			      OUTPUT_FORMAT_DEMUX_420_ENABLE,
> +			      OUTPUT_FORMAT_DEMUX_420_ENABLE);
> +	} else {
> +		mtk_hdmi_mask(hdmi, HDMI_CONFIG, 0 | HDMITX_SW_HPD,
> +			      HDMI_YUV420_MODE | HDMITX_SW_HPD);
> +		mtk_hdmi_mask(hdmi, VID_DOWNSAMPLE_CONFIG, 0,
> +			      C444_C422_CONFIG_ENABLE);
> +		mtk_hdmi_mask(hdmi, VID_DOWNSAMPLE_CONFIG, 0,
> +			      C422_C420_CONFIG_ENABLE);
> +		mtk_hdmi_mask(hdmi, VID_DOWNSAMPLE_CONFIG,
> +			      C422_C420_CONFIG_BYPASS, C422_C420_CONFIG_BYPASS);
> +		mtk_hdmi_mask(hdmi, VID_DOWNSAMPLE_CONFIG, 0,
> +			      C422_C420_CONFIG_OUT_CB_OR_CR);
> +		mtk_hdmi_mask(hdmi, VID_OUT_FORMAT, 0,
> +			      OUTPUT_FORMAT_DEMUX_420_ENABLE);
> +	}
> +}
> +
> +static bool mtk_hdmi_tmds_over_340M(struct mtk_hdmi *hdmi)
> +{
> +	unsigned long pixel_clk, tmds_clk;
> +
> +	pixel_clk = hdmi->mode.pixelclock.typ;
> +
> +	switch (hdmi->color_depth) {
> +	case HDMI_8_BIT:
> +		tmds_clk = pixel_clk;
> +		break;
> +	case HDMI_10_BIT:
> +		tmds_clk = pixel_clk * 5 / 4;
> +		break;
> +	case HDMI_12_BIT:
> +		tmds_clk = pixel_clk * 3 / 2;
> +		break;
> +	case HDMI_16_BIT:
> +		tmds_clk = pixel_clk * 2;
> +		break;
> +	default:
> +		dev_warn(hdmi->dev, "Unsupported color depth %d\n",
> +			 hdmi->color_depth);
> +		return false;
> +	}
> +
> +	return tmds_clk >= 340000000 && hdmi->csp != HDMI_COLORSPACE_YUV420;

Can we get a macro for 340000000 to explain what it is?

> +}
> +
> +static inline void mtk_hdmi_enable_scrambling(struct mtk_hdmi *hdmi,
> +					      bool enable)
> +{
> +	udelay(150);
> +
> +	if (enable)
> +		mtk_hdmi_mask(hdmi, TOP_CFG00, SCR_ON | HDMI2_ON,
> +			      SCR_ON | HDMI2_ON);
> +	else
> +		mtk_hdmi_mask(hdmi, TOP_CFG00, SCR_OFF | HDMI2_OFF,
> +			      SCR_ON | HDMI2_ON);
> +}
> +
> +static void mtk_hdmi_disable_abist(struct mtk_hdmi *hdmi)
> +{
> +	mtk_hdmi_mask(hdmi, TOP_CFG00, 0, ABIST_ENABLE);
> +}
> +
> +static void mtk_hdmi_change_video_resolution(struct mtk_hdmi *hdmi)
> +{
> +	bool is_over_340M = false;

Initializing this is dead code.

> +	bool is_hdmi_sink = true;

Making this const would make it a bit more obivous how this
is being used.

> +
> +	mtk_hdmi_hw_reset(hdmi);
> +	mtk_hdmi_set_sw_hpd(hdmi, true);
> +	udelay(5);
> +
> +	mtk_hdmi_write(hdmi, HDCP_TOP_CTRL, 0x0);
> +
> +	mtk_hdmi_set_deep_color(hdmi, is_hdmi_sink);
> +	mtk_hdmi_enable_hdmi_mode(hdmi, is_hdmi_sink);
> +
> +	udelay(10);
> +	mtk_hdmi_hw_vid_black(hdmi, true);
> +
> +	mtk_hdmi_mask(hdmi, TOP_CFG01, NULL_PKT_VSYNC_HIGH_EN,
> +		      NULL_PKT_VSYNC_HIGH_EN | NULL_PKT_EN);
> +
> +	is_over_340M = mtk_hdmi_tmds_over_340M(hdmi);
> +	dev_dbg(hdmi->dev, "is_over_340M: %d\n", is_over_340M);
> +
> +	mtk_hdmi_enable_scrambling(hdmi, is_over_340M);
> +
> +	if (hdmi->csp == HDMI_COLORSPACE_YUV420)
> +		mtk_hdmi_yuv420_downsample(hdmi, true);
> +	else
> +		mtk_hdmi_yuv420_downsample(hdmi, false);
> +}
> +
> +static void mtk_hdmi_output_set_display_mode(struct mtk_hdmi *hdmi,
> +					     struct display_timing *mode)
> +{
> +	unsigned long link_rate = mode->pixelclock.typ;
> +	int ret;
> +
> +	ret = generic_phy_configure(&hdmi->phy, &link_rate);
> +	if (ret)
> +		dev_err(hdmi->dev, "Setting clock=%u failed: %d\n",
> +			mode->pixelclock.typ, ret);
> +
> +	mtk_hdmi_change_video_resolution(hdmi);
> +}
> +
> +static void mtk_hdmi_convert_colorspace_depth(struct mtk_hdmi *hdmi)
> +{
> +	switch (hdmi->set_csp_depth) {
> +	case RGB444_8bit:
> +		hdmi->csp = HDMI_COLORSPACE_RGB;
> +		hdmi->color_depth = HDMI_8_BIT;
> +		break;
> +	case RGB444_10bit:
> +		hdmi->csp = HDMI_COLORSPACE_RGB;
> +		hdmi->color_depth = HDMI_10_BIT;
> +		break;
> +	case RGB444_12bit:
> +		hdmi->csp = HDMI_COLORSPACE_RGB;
> +		hdmi->color_depth = HDMI_12_BIT;
> +		break;
> +	case RGB444_16bit:
> +		hdmi->csp = HDMI_COLORSPACE_RGB;
> +		hdmi->color_depth = HDMI_16_BIT;
> +		break;
> +	case YCBCR444_8bit:
> +		hdmi->csp = HDMI_COLORSPACE_YUV444;
> +		hdmi->color_depth = HDMI_8_BIT;
> +		break;
> +	case YCBCR444_10bit:
> +		hdmi->csp = HDMI_COLORSPACE_YUV444;
> +		hdmi->color_depth = HDMI_10_BIT;
> +		break;
> +	case YCBCR444_12bit:
> +		hdmi->csp = HDMI_COLORSPACE_YUV444;
> +		hdmi->color_depth = HDMI_12_BIT;
> +		break;
> +	case YCBCR444_16bit:
> +		hdmi->csp = HDMI_COLORSPACE_YUV444;
> +		hdmi->color_depth = HDMI_16_BIT;
> +		break;
> +	case YCBCR422_12bit:
> +		hdmi->csp = HDMI_COLORSPACE_YUV422;
> +		hdmi->color_depth = HDMI_12_BIT;
> +		break;
> +	case YCBCR420_8bit:
> +		hdmi->csp = HDMI_COLORSPACE_YUV420;
> +		hdmi->color_depth = HDMI_8_BIT;
> +		break;
> +	case YCBCR420_10bit:
> +		hdmi->csp = HDMI_COLORSPACE_YUV420;
> +		hdmi->color_depth = HDMI_10_BIT;
> +		break;
> +	case YCBCR420_12bit:
> +		hdmi->csp = HDMI_COLORSPACE_YUV420;
> +		hdmi->color_depth = HDMI_12_BIT;
> +		break;
> +	case YCBCR420_16bit:
> +		hdmi->csp = HDMI_COLORSPACE_YUV420;
> +		hdmi->color_depth = HDMI_16_BIT;
> +		break;
> +	default:
> +		hdmi->csp = HDMI_COLORSPACE_RGB;
> +		hdmi->color_depth = HDMI_8_BIT;
> +	}
> +
> +	dev_dbg(hdmi->dev, "color space: %d, color depth: %d\n",
> +		hdmi->csp, hdmi->color_depth);
> +}
> +
> +static int mtk_hdmi_setup_spd_infoframe(struct mtk_hdmi *hdmi, u8 *buffer,
> +					size_t bufsz, const char *vendor,
> +					const char *product)
> +{
> +	u8 checksum = 0;
> +	int i;
> +
> +	if (bufsz < HDMI_SPD_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	memset(buffer, 0, HDMI_SPD_INFOFRAME_SIZE);
> +
> +	/* SPD InfoFrame header */
> +	buffer[0] = 0x83;  /* SPD InfoFrame type */
> +	buffer[1] = 0x01;  /* Version */
> +	buffer[2] = 0x19;  /* Length (25 bytes) */
> +
> +	/* Vendor name (8 bytes, padded with spaces) */
> +	strlcpy((char *)&buffer[4], vendor, 8);

Why is vendor limited to 8 if we pad with spaced up to 12?

And this only copies up to 7 chars because of strlcpy() ensuring
zero terminator, so comment is misleading.

> +	for (i = 4; i < 12; i++) {
> +		if (buffer[i] == '\0')
> +			buffer[i] = ' ';
> +	}
> +
> +	/* Product description (16 bytes, padded with spaces) */
> +	strlcpy((char *)&buffer[12], product, 16);

Similar.

> +	for (i = 12; i < 28; i++) {
> +		if (buffer[i] == '\0')
> +			buffer[i] = ' ';
> +	}
> +
> +	/* checksum over the full frame, so that the total sums to zero */
> +	for (i = 0; i < HDMI_SPD_INFOFRAME_SIZE; i++)
> +		checksum += buffer[i];
> +	buffer[3] = 0x100 - checksum;
> +
> +	return 0;
> +}
> +
> +static int mtk_hdmi_setup_avi_infoframe(struct mtk_hdmi *hdmi, u8 *buffer,
> +					size_t bufsz,
> +					struct display_timing *mode)
> +{
> +	u8 checksum = 0;
> +	int i;
> +
> +	if (bufsz < HDMI_AVI_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	memset(buffer, 0, HDMI_AVI_INFOFRAME_SIZE);
> +
> +	/* AVI InfoFrame header */
> +	buffer[0] = 0x82;  /* AVI InfoFrame type */
> +	buffer[1] = 0x02;  /* Version */
> +	buffer[2] = 0x0D;  /* Length (13 bytes) */
> +
> +	/* Data byte 1: Scan info, bar info, active format info, RGB/YCC */
> +	buffer[4] = 0x00; /* RGB by default */
> +	if (hdmi->csp == HDMI_COLORSPACE_YUV422)
> +		buffer[4] |= 0x20;  /* YCC422 */
> +	else if (hdmi->csp == HDMI_COLORSPACE_YUV444)
> +		buffer[4] |= 0x40;  /* YCC444 */
> +	else if (hdmi->csp == HDMI_COLORSPACE_YUV420)
> +		buffer[4] |= 0x60;  /* YCC420 */

Would make this a switch statemnt. Then we don't need the comments about
default or YCCxxx.

Or make an else case at the end and change all |= to =.

> +
> +	/* Data byte 4: Video Identification Code (VIC) */
> +	if (mode->hactive.typ == 1920 && mode->vactive.typ == 1080)
> +		buffer[7] = 16;  /* 1920x1080@60Hz */
> +	else if (mode->hactive.typ == 1280 && mode->vactive.typ == 720)
> +		buffer[7] = 4;   /* 1280x720@60Hz */
> +	else if (mode->hactive.typ == 720 && mode->vactive.typ == 480)
> +		buffer[7] = 2;   /* 720x480@60Hz */
> +	else
> +		buffer[7] = 0;   /* Unknown/unsupported timing */
> +
> +	/*
> +	 * Data byte 2: picture aspect ratio, active portion same as
> +	 * picture. VIC 2 is a 4:3 mode, the others are 16:9.
> +	 */
> +	buffer[5] = buffer[7] == 2 ? 0x18 : 0x28;
> +
> +	/* Data byte 3: Colorimetry, picture scaling */
> +	buffer[6] = 0x00;  /* No specific colorimetry */
> +	if (hdmi->colorimetry == HDMI_COLORIMETRY_ITU_709)
> +		buffer[6] |= 0x80;
> +	else if (hdmi->colorimetry == HDMI_COLORIMETRY_ITU_601)
> +		buffer[6] |= 0x40;

Similar.

> +
> +	/* Data byte 5: Pixel repetition */
> +	buffer[8] = 0x00;  /* No pixel repetition */
> +
> +	/* checksum over the full frame, so that the total sums to zero */
> +	for (i = 0; i < HDMI_AVI_INFOFRAME_SIZE; i++)

checksum is intialized far away. Could do it here insted.

	for (checksum = 0, i = 0; i < HDMI_AVI_INFOFRAME_SIZE; i++)

> +		checksum += buffer[i];
> +	buffer[3] = 0x100 - checksum;
> +
> +	return 0;
> +}
> +
> +static void mtk_hdmi_hw_avi_infoframe(struct mtk_hdmi *hdmi, u8 *buf, u8 len)
> +{
> +	/* Disable AVI InfoFrame first */
> +	mtk_hdmi_mask(hdmi, TOP_INFO_EN, AVI_DIS_WR | AVI_DIS,
> +		      AVI_EN_WR | AVI_EN);
> +	mtk_hdmi_mask(hdmi, TOP_INFO_RPT, AVI_RPT_DIS, AVI_RPT_EN);
> +
> +	/* Write AVI InfoFrame header */
> +	mtk_hdmi_write(hdmi, TOP_AVI_HEADER,
> +		       BYTES_TO_UINT32(0, buf[2], buf[1], buf[0]));
> +
> +	/* Write AVI InfoFrame data packets */
> +	mtk_hdmi_write(hdmi, TOP_AVI_PKT00,
> +		       BYTES_TO_UINT32(buf[6], buf[5], buf[4], buf[3]));
> +
> +	mtk_hdmi_write(hdmi, TOP_AVI_PKT01,
> +		       BYTES_TO_UINT32(0, buf[9], buf[8], buf[7]));
> +
> +	mtk_hdmi_write(hdmi, TOP_AVI_PKT02,
> +		       BYTES_TO_UINT32(buf[13], buf[12], buf[11], buf[10]));
> +
> +	mtk_hdmi_write(hdmi, TOP_AVI_PKT03,
> +		       BYTES_TO_UINT32(0, buf[16], buf[15], buf[14]));
> +
> +	/* Clear remaining packets */
> +	mtk_hdmi_write(hdmi, TOP_AVI_PKT04, 0);
> +	mtk_hdmi_write(hdmi, TOP_AVI_PKT05, 0);
> +
> +	/* Enable AVI InfoFrame */
> +	mtk_hdmi_mask(hdmi, TOP_INFO_RPT, AVI_RPT_EN, AVI_RPT_EN);
> +	mtk_hdmi_mask(hdmi, TOP_INFO_EN, AVI_EN_WR | AVI_EN,
> +		      AVI_EN_WR | AVI_EN);
> +}
> +
> +static void mtk_hdmi_hw_spd_infoframe(struct mtk_hdmi *hdmi, u8 *buf, u8 len)
> +{
> +	/* Disable SPD InfoFrame first */
> +	mtk_hdmi_mask(hdmi, TOP_INFO_EN, SPD_DIS_WR | SPD_DIS,
> +		      SPD_EN_WR | SPD_EN);
> +	mtk_hdmi_mask(hdmi, TOP_INFO_RPT, SPD_RPT_DIS, SPD_RPT_EN);
> +
> +	/* Write SPD InfoFrame header */
> +	mtk_hdmi_write(hdmi, TOP_SPDIF_HEADER,
> +		       BYTES_TO_UINT32(0, buf[2], buf[1], buf[0]));
> +
> +	/* Write SPD InfoFrame data packets */
> +	mtk_hdmi_write(hdmi, TOP_SPDIF_PKT00,
> +		       BYTES_TO_UINT32(buf[6], buf[5], buf[4], buf[3]));
> +
> +	mtk_hdmi_write(hdmi, TOP_SPDIF_PKT01,
> +		       BYTES_TO_UINT32(0, buf[9], buf[8], buf[7]));
> +
> +	mtk_hdmi_write(hdmi, TOP_SPDIF_PKT02,
> +		       BYTES_TO_UINT32(buf[13], buf[12], buf[11], buf[10]));
> +
> +	mtk_hdmi_write(hdmi, TOP_SPDIF_PKT03,
> +		       BYTES_TO_UINT32(0, buf[16], buf[15], buf[14]));
> +
> +	mtk_hdmi_write(hdmi, TOP_SPDIF_PKT04,
> +		       BYTES_TO_UINT32(buf[20], buf[19], buf[18], buf[17]));
> +
> +	mtk_hdmi_write(hdmi, TOP_SPDIF_PKT05,
> +		       BYTES_TO_UINT32(0, buf[23], buf[22], buf[21]));
> +
> +	mtk_hdmi_write(hdmi, TOP_SPDIF_PKT06,
> +		       BYTES_TO_UINT32(buf[27], buf[26], buf[25], buf[24]));
> +
> +	mtk_hdmi_write(hdmi, TOP_SPDIF_PKT07, buf[28]);
> +
> +	/* Enable SPD InfoFrame */
> +	mtk_hdmi_mask(hdmi, TOP_INFO_RPT, SPD_RPT_EN, SPD_RPT_EN);
> +	mtk_hdmi_mask(hdmi, TOP_INFO_EN, SPD_EN_WR | SPD_EN,
> +		      SPD_EN_WR | SPD_EN);
> +}
> +
> +static void mtk_hdmi_setup_infoframes(struct mtk_hdmi *hdmi,
> +				      struct display_timing *mode)
> +{
> +	u8 buffer_spd[HDMI_SPD_INFOFRAME_SIZE];
> +	u8 buffer_avi[HDMI_AVI_INFOFRAME_SIZE];
> +	int ret;
> +
> +	ret = mtk_hdmi_setup_avi_infoframe(hdmi, buffer_avi,
> +					   sizeof(buffer_avi), mode);
> +	if (ret) {
> +		dev_warn(hdmi->dev, "Failed to setup AVI infoframe: %d\n", ret);

Why warn instead of err?

> +		return;
> +	}
> +
> +	ret = mtk_hdmi_setup_spd_infoframe(hdmi, buffer_spd,
> +					   sizeof(buffer_spd),
> +					   "MediaTek", "On-chip HDMI");
> +	if (ret) {
> +		dev_warn(hdmi->dev, "Failed to setup SPD infoframe: %d\n", ret);
> +		return;
> +	}
> +
> +	/* Send the infoframes to hardware */
> +	mtk_hdmi_hw_avi_infoframe(hdmi, buffer_avi, sizeof(buffer_avi));
> +	mtk_hdmi_hw_spd_infoframe(hdmi, buffer_spd, sizeof(buffer_spd));
> +}
> +
> +static void mtk_hdmi_controller_pre_enable(struct mtk_hdmi *hdmi,
> +					   struct display_timing *mode)
> +{
> +	mtk_hdmi_convert_colorspace_depth(hdmi);
> +	mtk_hdmi_output_set_display_mode(hdmi, mode);
> +	mtk_hdmi_setup_infoframes(hdmi, mode);
> +}
> +
> +static void mtk_hdmi_controller_enable(struct mtk_hdmi *hdmi)
> +{
> +	generic_phy_power_on(&hdmi->phy);
> +	mtk_hdmi_hw_vid_black(hdmi, false);
> +}
> +
> +static inline void mtk_hdmi_disable_all_int(struct mtk_hdmi *hdmi)
> +{
> +	/* disable all tx irq */
> +	mtk_hdmi_write(hdmi, TOP_INT_MASK00, 0x00000000);
> +	mtk_hdmi_write(hdmi, TOP_INT_MASK01, 0x00000000);

Just 0 is fine.

> +}
> +
> +static int mtk_hdmi_read_edid(struct mtk_hdmi *hdmi, u8 *buf, int buf_size)
> +{
> +	struct udevice *chip;
> +	int ret;
> +
> +	if (!hdmi->ddc_bus || buf_size < EDID_SIZE)
> +		return -EINVAL;
> +
> +	ret = i2c_get_chip(hdmi->ddc_bus, EDID_ADDR, 1, &chip);
> +	if (ret)
> +		return ret;
> +
> +	ret = dm_i2c_read(chip, 0, buf, EDID_SIZE);
> +	if (ret) {
> +		dev_err(hdmi->dev, "failed to read EDID: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* read the extension block, if any */
> +	if (buf[0x7e] != 0 && buf_size >= EDID_EXT_SIZE) {
> +		ret = dm_i2c_read(chip, EDID_SIZE, buf + EDID_SIZE,
> +				  buf_size - EDID_SIZE);
> +		if (ret)
> +			dev_warn(hdmi->dev,
> +				 "error reading extended EDID block\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static enum hdmi_hpd_state mtk_hdmi_hpd_pord_status(struct mtk_hdmi *hdmi)
> +{
> +	unsigned int hpd_status;
> +
> +	hpd_status = mtk_hdmi_read(hdmi, HPD_DDC_STATUS);
> +	if ((hpd_status & (HPD_PIN_STA | PORD_PIN_STA)) ==
> +	    (HPD_PIN_STA | PORD_PIN_STA))
> +		return HDMI_PLUG_IN_AND_SINK_POWER_ON;
> +	else if ((hpd_status & (HPD_PIN_STA | PORD_PIN_STA)) == HPD_PIN_STA)
> +		return HDMI_PLUG_IN_ONLY;
> +	else
> +		return HDMI_PLUG_OUT;
> +}
> +
> +static int mtk_hdmi_wait_for_hpd(struct mtk_hdmi *hdmi)
> +{
> +	ulong start = get_timer(0);
> +
> +	do {
> +		if (mtk_hdmi_hpd_pord_status(hdmi) ==
> +		    HDMI_PLUG_IN_AND_SINK_POWER_ON)
> +			return 0;

nit: add blank line here

> +		udelay(100);
> +	} while (get_timer(start) < MTK_HDMI_HPD_TIMEOUT_MS);
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static bool mtk_hdmi_mode_valid(void *priv, const struct display_timing *timing)
> +{
> +	return timing->hactive.typ < MTK_HDMI_MAX_WIDTH &&
> +	       timing->vactive.typ < MTK_HDMI_MAX_HEIGHT;
> +}
> +
> +static int mtk_hdmi_get_display_timing(struct mtk_hdmi *hdmi,
> +				       struct display_timing *timing)
> +{
> +	u8 edid[EDID_EXT_SIZE];
> +	int panel_bits_per_colour;
> +	int ret;
> +
> +	ret = mtk_hdmi_read_edid(hdmi, edid, EDID_EXT_SIZE);
> +	if (ret)
> +		return ret;
> +
> +	ret = edid_get_timing_validate(edid, sizeof(struct edid1_info),
> +				       timing, &panel_bits_per_colour,
> +				       mtk_hdmi_mode_valid, NULL);
> +	if (ret)
> +		return ret;
> +
> +	debug("Display timing:\n clock %u Hz\n", timing->pixelclock.typ);
> +	debug(" hactive: %d,\thfront_p: %d,\thback_p: %d hsync:\t%d\n",
> +	      timing->hactive.typ, timing->hfront_porch.typ,
> +	      timing->hback_porch.typ, timing->hsync_len.typ);
> +	debug(" vactive: %d,\tvfront_p: %d,\tvback_p: %d vsync:\t%d\n",
> +	      timing->vactive.typ, timing->vfront_porch.typ,
> +	      timing->vback_porch.typ, timing->vsync_len.typ);
> +	debug(" flags: 0x%x\n", timing->flags);
> +
> +	return 0;
> +}
> +
> +static void mtk_hdmi_controller_initialize(struct mtk_hdmi *hdmi,
> +					   struct display_timing *mode)
> +{
> +	mtk_hdmi_disable_all_int(hdmi);
> +
> +	mtk_hdmi_disable_abist(hdmi);
> +
> +	mtk_hdmi_controller_pre_enable(hdmi, mode);
> +
> +	/* let the new configuration settle before unmuting the output */
> +	mdelay(50);
> +
> +	mtk_hdmi_controller_enable(hdmi);
> +}
> +
> +static void mtk_hdmi_reset_colorspace_setting(struct mtk_hdmi *hdmi)
> +{
> +	hdmi->set_csp_depth = RGB444_8bit;
> +	hdmi->csp = HDMI_COLORSPACE_RGB;
> +	hdmi->color_depth = HDMI_8_BIT;
> +	hdmi->colorimetry = HDMI_COLORIMETRY_NONE;
> +}
> +
> +static int mtk_hdmi_get_component(struct udevice *dev, const char *name,
> +				  struct udevice **compp)
> +{
> +	int ret;
> +
> +	ret = uclass_get_device_by_phandle(UCLASS_MISC, dev, name, compp);
> +	if (ret) {
> +		dev_err(dev, "cannot get %s: %d\n", name, ret);
> +		return ret;
> +	}
> +
> +	return mtk_disp_comp_enable(*compp);
> +}
> +
> +static int mtk_hdmi_probe(struct udevice *dev)
> +{
> +	struct mtk_hdmi *hdmi = dev_get_priv(dev);
> +	struct video_priv *priv = dev_get_uclass_priv(dev);
> +	struct video_uc_plat *plat = dev_get_uclass_plat(dev);
> +	struct ofnode_phandle_args args;
> +	struct display_timing timing;
> +	fdt_size_t fb_region_size;
> +	int ret;
> +
> +	hdmi->dev = dev;
> +
> +	hdmi->regs = dev_read_addr(dev);
> +	if (hdmi->regs == FDT_ADDR_T_NONE)
> +		return -EINVAL;
> +
> +	ret = clk_get_bulk(dev, &hdmi->clk_bulk);
> +	if (ret) {
> +		dev_err(dev, "failed to get clocks: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = clk_enable_bulk(&hdmi->clk_bulk);
> +	if (ret) {
> +		dev_err(dev, "failed to enable clocks: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = generic_phy_get_by_name(dev, "hdmi", &hdmi->phy);
> +	if (ret) {
> +		dev_err(dev, "failed to get HDMI PHY: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = uclass_get_device_by_ofnode(UCLASS_I2C,
> +					  dev_read_subnode(dev, "i2c"),
> +					  &hdmi->ddc_bus);
> +	if (ret) {
> +		dev_err(dev, "failed to get DDC I2C bus: %d\n", ret);
> +		return ret;
> +	}
> +
> +	mtk_hdmi_reset_colorspace_setting(hdmi);
> +
> +	ret = mtk_hdmi_wait_for_hpd(hdmi);
> +	if (ret) {
> +		dev_err(dev, "display is not connected\n");
> +		return ret;
> +	}
> +
> +	ret = mtk_hdmi_get_display_timing(hdmi, &timing);
> +	if (ret) {
> +		dev_err(dev, "failed to get display timing from EDID: %d\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	hdmi->mode = timing;
> +	/* CEA-861: SD modes use ITU-601 colorimetry, HD modes ITU-709 */
> +	hdmi->colorimetry = timing.vactive.typ >= 720 ?
> +			    HDMI_COLORIMETRY_ITU_709 : HDMI_COLORIMETRY_ITU_601;
> +
> +	mtk_hdmi_controller_initialize(hdmi, &timing);
> +
> +	/* Set up video private data based on the selected display timing */
> +	priv->bpix = VIDEO_BPP32;
> +	priv->xsize = timing.hactive.typ;
> +	priv->ysize = timing.vactive.typ;
> +	priv->line_length = priv->xsize * VNBYTES(VIDEO_BPP32);
> +
> +	plat->size = priv->ysize * priv->line_length;
> +
> +	/* the framebuffer lives in a dedicated reserved-memory region */
> +	ret = dev_read_phandle_with_args(dev, "memory-region", NULL, 0, 0,
> +					 &args);
> +	if (ret) {
> +		dev_err(dev, "no framebuffer memory-region: %d\n", ret);
> +		return ret;
> +	}
> +
> +	plat->base = ofnode_get_addr_size(args.node, "reg", &fb_region_size);
> +	if (plat->base == FDT_ADDR_T_NONE) {
> +		dev_err(dev, "failed to decode framebuffer region\n");
> +		return -EINVAL;
> +	}
> +
> +	if (fb_region_size < plat->size) {
> +		dev_err(dev, "framebuffer region too small: %llu < %u\n",
> +			(unsigned long long)fb_region_size, plat->size);
> +		return -EINVAL;
> +	}
> +
> +	ret = mtk_hdmi_get_component(dev, "mediatek,dpi1", &hdmi->dpi1);
> +	if (ret)
> +		return ret;

nit: add blank line after all of these return statements.

> +	mtk_dpi_hw_enable(hdmi->dpi1);
> +	mtk_dpi_config(hdmi->dpi1, &timing,
> +		       hdmi->csp == HDMI_COLORSPACE_RGB);
> +
> +	ret = mtk_hdmi_get_component(dev, "mediatek,rdma4", &hdmi->rdma4);
> +	if (ret)
> +		return ret;
> +	mtk_mdp_rdma_config(hdmi->rdma4, plat, &timing, false);
> +
> +	ret = mtk_hdmi_get_component(dev, "mediatek,rdma5", &hdmi->rdma5);
> +	if (ret)
> +		return ret;
> +	mtk_mdp_rdma_config(hdmi->rdma5, plat, &timing, true);
> +
> +	ret = mtk_hdmi_get_component(dev, "mediatek,vdosys1", &hdmi->vdosys1);
> +	if (ret)
> +		return ret;
> +	mtk_vdosys1_configure_hdmi(hdmi->vdosys1);
> +
> +	ret = mtk_hdmi_get_component(dev, "mediatek,merge3", &hdmi->merge3);
> +	if (ret)
> +		return ret;
> +	mtk_disp_merge_config(hdmi->merge3, priv->xsize / 2, priv->ysize,
> +			      priv->xsize / 2, priv->ysize,
> +			      priv->xsize, priv->ysize);
> +
> +	ret = mtk_hdmi_get_component(dev, "mediatek,merge5", &hdmi->merge5);
> +	if (ret)
> +		return ret;
> +	mtk_disp_merge_config(hdmi->merge5, priv->xsize, priv->ysize, 0, 0,
> +			      priv->xsize, priv->ysize);
> +
> +	ret = mtk_hdmi_get_component(dev, "mediatek,mixer", &hdmi->mixer);
> +	if (ret)
> +		return ret;
> +	mtk_disp_mixer_config(hdmi->mixer, priv->xsize, priv->ysize);
> +
> +	ret = mtk_hdmi_get_component(dev, "mediatek,mutex1", &hdmi->mutex);
> +	if (ret)
> +		return ret;
> +	mtk_disp_mutex_config(hdmi->mutex);
> +
> +	ret = mtk_hdmi_get_component(dev, "mediatek,padding4",
> +				     &hdmi->padding4);
> +	if (ret)
> +		return ret;
> +	mtk_disp_padding_config(hdmi->padding4);
> +
> +	ret = mtk_hdmi_get_component(dev, "mediatek,padding5",
> +				     &hdmi->padding5);
> +	if (ret)
> +		return ret;
> +	mtk_disp_padding_config(hdmi->padding5);
> +
> +	video_set_flush_dcache(dev, true);
> +
> +	return 0;
> +}
> +
> +static const struct udevice_id mtk_hdmi_ids[] = {
> +	{
> +		.compatible = "mediatek,mt8188-hdmi-tx",
> +	},
> +	{ }
> +};
> +
> +U_BOOT_DRIVER(mtk_hdmi) = {
> +	.name		= "mtk_hdmi",
> +	.id		= UCLASS_VIDEO,
> +	.of_match	= mtk_hdmi_ids,
> +	.probe		= mtk_hdmi_probe,
> +	.bind		= dm_scan_fdt_dev,
> +	.priv_auto	= sizeof(struct mtk_hdmi),
> +};
> diff --git a/drivers/video/mediatek/mtk_mt8188_hdmi_regs.h b/drivers/video/mediatek/mtk_mt8188_hdmi_regs.h
> new file mode 100644
> index 00000000000..bcee2d1985d
> --- /dev/null
> +++ b/drivers/video/mediatek/mtk_mt8188_hdmi_regs.h

Does this really need to be a header file if it is only included in
one file? Everything could just be in the .c file directly.

> @@ -0,0 +1,103 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2025 MediaTek Inc.
> + * Copyright (c) 2025 BayLibre, SAS
> + */
> +
> +#ifndef _MTK_MT8188_HDMI_REGS_H
> +#define _MTK_MT8188_HDMI_REGS_H
> +
> +#define AVI_DIS					(0)
> +#define AVI_DIS_WR				(0)
> +#define AVI_EN					(0x1)
> +#define AVI_EN_WR				BIT(16)
> +#define AVI_RPT_DIS				(0x0)
> +#define AVI_RPT_EN				(0x1)
> +
> +#define C422_C420_CONFIG_BYPASS			BIT(5)
> +#define C422_C420_CONFIG_ENABLE			BIT(4)
> +#define C422_C420_CONFIG_OUT_CB_OR_CR		BIT(6)
> +#define C444_C422_CONFIG_ENABLE			(0x1)
> +
> +#define DEEPCOLOR_MODE_10BIT			BIT(8)
> +#define DEEPCOLOR_MODE_12BIT			GENMASK(9, 8)
> +#define DEEPCOLOR_MODE_16BIT			GENMASK(10, 8)
> +#define DEEPCOLOR_MODE_8BIT			(0)
> +#define DEEPCOLOR_MODE_MASKBIT			GENMASK(10, 8)
> +#define DEEPCOLOR_PAT_EN			BIT(12)
> +#define DEEP_COLOR_ADD				BIT(4)
> +
> +#define HDMI2_OFF				(0)
> +#define HDMI2_ON				BIT(2)
> +
> +#define HDMITX_SW_HPD				BIT(29)
> +#define HDMITX_SW_HPD_SHIFT			(29)
> +#define HDMITX_SW_RSTB				BIT(31)
> +#define HDMITX_SW_RSTB_SHIFT			(31)
> +
> +#define HDMI_MODE_DVI				(0)
> +#define HDMI_MODE_HDMI				BIT(3)
> +
> +#define HDMI_YUV420_MODE			BIT(10)
> +#define HDMI_YUV420_MODE_SHIFT			(10)
> +
> +#define HPD_DDC_STATUS				0xC60
> +#define PORD_PIN_STA				BIT(5)
> +#define HPD_PIN_STA				BIT(4)
> +
> +#define NULL_PKT_EN				BIT(2)
> +#define NULL_PKT_VSYNC_HIGH_EN			BIT(3)
> +
> +#define OUTPUT_FORMAT_DEMUX_420_ENABLE		BIT(10)
> +
> +#define REG_VMUTE_EN				BIT(16)
> +
> +#define SCR_OFF					0
> +#define SCR_ON					BIT(4)
> +
> +#define SPD_DIS					0
> +#define SPD_DIS_WR				0
> +#define SPD_EN					BIT(1)
> +#define SPD_EN_WR				BIT(17)
> +#define SPD_RPT_DIS				0
> +#define SPD_RPT_EN				BIT(1)
> +
> +#define TOP_CFG00				0x000
> +#define TOP_CFG01				0x004
> +#define TOP_INFO_EN				0x01C
> +#define TOP_INFO_RPT				0x020
> +#define TOP_AVI_HEADER				0x024
> +#define TOP_AVI_PKT00				0x028
> +#define TOP_AVI_PKT01				0x02C
> +#define TOP_AVI_PKT02				0x030
> +#define TOP_AVI_PKT03				0x034
> +#define TOP_AVI_PKT04				0x038
> +#define TOP_AVI_PKT05				0x03C
> +#define TOP_INT_MASK00				0x1B0
> +#define TOP_INT_MASK01				0x1B4
> +#define TOP_MISC_CTLR				0x1A4
> +#define TOP_SPDIF_HEADER			0x054
> +#define TOP_SPDIF_PKT00				0x058
> +#define TOP_SPDIF_PKT01				0x05C
> +#define TOP_SPDIF_PKT02				0x060
> +#define TOP_SPDIF_PKT03				0x064
> +#define TOP_SPDIF_PKT04				0x068
> +#define TOP_SPDIF_PKT05				0x06C
> +#define TOP_SPDIF_PKT06				0x070
> +#define TOP_SPDIF_PKT07				0x074
> +#define TOP_VMUTE_CFG1				0x1C8
> +
> +#define VID_DOWNSAMPLE_CONFIG			0x8F0
> +#define VID_OUT_FORMAT				0x8FC
> +
> +#define ABIST_ENABLE				BIT(31)
> +#define ABIST_VIDEO_FORMAT_MASKBIT		(0x3F << 16)

Should this be GENMASK()?

> +#define ABIST_VIDEO_FORMAT_720x480P		(0x2 << 16)
> +#define ABIST_VIDEO_FORMAT_720P50		(0xC << 16)
> +#define ABIST_VIDEO_FORMAT_1080P60		(0xA << 16)
> +#define ABIST_VIDEO_FORMAT_3840x2160P30		(0x19 << 16)

And then use FIELD_PREP/FIELD_GET for these.

> +
> +#define HDCP_TOP_CTRL				0xC00
> +#define HDMI_CONFIG				0xEA0
> +
> +#endif /* _MTK_MT8188_HDMI_REGS_H */
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.