From nobody Tue Feb 10 09:57:26 2026 Received: from cstnet.cn (unknown [159.226.251.81]) (using TLSv1.2 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E329A36075C; Fri, 23 Jan 2026 09:29:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.226.251.81 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769160577; cv=none; b=WlsYmHxdyQV+VGKGjXRXO6VOt/Yo0ToW5xL9cnJMG6dEELgNAe1JsM4V8JxipNbd5fZvEEhYUEXYJ+X9UgBGwAi5TVZ1BFqZdmSD+5BNiQHYkQj+Ui1JTqCfQZA9VpYq+f94UQsqSOfo9skUpsItVGSlzN5kQyvHRG2rpRB58vw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769160577; c=relaxed/simple; bh=cpwXIwYFTI7KS7nI3X9YbtDg+h6js4eaNkRzWbe+q1A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=B1JIYbgr23AxbZaVip1INNiYWlk8qY0xO7jwUUa4DgNlDZIUptsMOFNQssxjf8z0+iUkgZVkUjHnog2CIJYnegLXWBamRAPswwEU6qcBiHse9n+4ZOt9x0TL/edCUJWBwI6t67VxJKCL71JSwE7Ai/R9+6KBWMbGtuYxt7dkb7c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn; spf=pass smtp.mailfrom=iscas.ac.cn; arc=none smtp.client-ip=159.226.251.81 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iscas.ac.cn Received: from edelgard.fodlan.icenowy.me (unknown [112.94.103.171]) by APP-03 (Coremail) with SMTP id rQCowABXZ85EP3NppX1gBg--.20954S7; Fri, 23 Jan 2026 17:29:04 +0800 (CST) From: Icenowy Zheng To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Drew Fustini , Guo Ren , Fu Wei Cc: Philipp Zabel , Dmitry Baryshkov , Michal Wilczynski , Luca Ceresoli , Han Gao , Yao Zi , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-riscv@lists.infradead.org, Icenowy Zheng , Icenowy Zheng , Han Gao Subject: [PATCH v6 5/9] drm/bridge: add a driver for T-Head TH1520 HDMI controller Date: Fri, 23 Jan 2026 17:28:26 +0800 Message-ID: <20260123092830.4046009-6-zhengxingda@iscas.ac.cn> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260123092830.4046009-1-zhengxingda@iscas.ac.cn> References: <20260123092830.4046009-1-zhengxingda@iscas.ac.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: rQCowABXZ85EP3NppX1gBg--.20954S7 X-Coremail-Antispam: 1UD129KBjvJXoW3XF13tFy5KFyrXr1DGr4fuFg_yoWfWr43pa y7AayYkrWkXF1aga1fAr48ZrZaya9rXFy5t3y2qwsavw1ftF4rXryDJrWrXFW8ArsrZw13 tFn8urWYgF17J3DanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUmS14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_JF0E3s1l82xGYI kIc2x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2 z4x0Y4vE2Ix0cI8IcVAFwI0_Xr0_Ar1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr1j6F 4UJwA2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x0267AKxVW0oVCq 3wAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7 IYx2IY67AKxVWUJVWUGwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCjc4AY6r1j6r4U M4x0Y48IcxkI7VAKI48JM4x0x7Aq67IIx4CEVc8vx2IErcIFxwACI402YVCY1x02628vn2 kIc2xKxwCY1x0262kKe7AKxVW8ZVWrXwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkE bVWUJVW8JwC20s026c02F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67 AF67kF1VAFwI0_GFv_WrylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUCVW8JwCI 42IY6xIIjxv20xvEc7CjxVAFwI0_Gr1j6F4UJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF 4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVW8Jr0_Cr1UYxBI daVFxhVjvjDU0xZFpf9x0pRQJ5wUUUUU= X-CM-SenderInfo: x2kh0wp0lqwv3d6l2u1dvotugofq/ Content-Type: text/plain; charset="utf-8" From: Icenowy Zheng T-Head TH1520 SoC contains a Synopsys DesignWare HDMI controller (paired with DesignWare HDMI TX PHY Gen2) that takes the "DP" output from the display controller. Add a driver for this controller utilizing the common DesignWare HDMI code in the kernel. Signed-off-by: Icenowy Zheng Signed-off-by: Icenowy Zheng Tested-by: Han Gao Tested-by: Michal Wilczynski Acked-by: Thomas Zimmermann --- No changes since v3. Changes in v2: - Created a new function to set PHY parameters and refactored the control flow of the configure_phy callback. MAINTAINERS | 1 + drivers/gpu/drm/bridge/Kconfig | 10 ++ drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/th1520-dw-hdmi.c | 173 ++++++++++++++++++++++++ 4 files changed, 185 insertions(+) create mode 100644 drivers/gpu/drm/bridge/th1520-dw-hdmi.c diff --git a/MAINTAINERS b/MAINTAINERS index 5b11839cba9de..fc04fc007a054 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22556,6 +22556,7 @@ F: Documentation/devicetree/bindings/reset/thead,th= 1520-reset.yaml F: arch/riscv/boot/dts/thead/ F: drivers/clk/thead/clk-th1520-ap.c F: drivers/firmware/thead,th1520-aon.c +F: drivers/gpu/drm/bridge/th1520-dw-hdmi.c F: drivers/mailbox/mailbox-th1520.c F: drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c F: drivers/pinctrl/pinctrl-th1520.c diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index a250afd8d6622..8e19f5fb9ad7c 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -335,6 +335,16 @@ config DRM_THINE_THC63LVD1024 help Thine THC63LVD1024 LVDS/parallel converter driver. =20 +config DRM_THEAD_TH1520_DW_HDMI + tristate "T-Head TH1520 DesignWare HDMI bridge" + depends on OF + depends on COMMON_CLK + depends on ARCH_THEAD || COMPILE_TEST + select DRM_DW_HDMI + help + Choose this to enable support for the internal HDMI bridge found + on the T-Head TH1520 SoC. + config DRM_TOSHIBA_TC358762 tristate "TC358762 DSI/DPI bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makef= ile index c7dc03182e592..085b5db45d6fd 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_DRM_SII902X) +=3D sii902x.o obj-$(CONFIG_DRM_SII9234) +=3D sii9234.o obj-$(CONFIG_DRM_SIMPLE_BRIDGE) +=3D simple-bridge.o obj-$(CONFIG_DRM_SOLOMON_SSD2825) +=3D ssd2825.o +obj-$(CONFIG_DRM_THEAD_TH1520_DW_HDMI) +=3D th1520-dw-hdmi.o obj-$(CONFIG_DRM_THINE_THC63LVD1024) +=3D thc63lvd1024.o obj-$(CONFIG_DRM_TOSHIBA_TC358762) +=3D tc358762.o obj-$(CONFIG_DRM_TOSHIBA_TC358764) +=3D tc358764.o diff --git a/drivers/gpu/drm/bridge/th1520-dw-hdmi.c b/drivers/gpu/drm/brid= ge/th1520-dw-hdmi.c new file mode 100644 index 0000000000000..389eead5f1c45 --- /dev/null +++ b/drivers/gpu/drm/bridge/th1520-dw-hdmi.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025 Icenowy Zheng + * + * Based on rcar_dw_hdmi.c, which is: + * Copyright (C) 2016 Renesas Electronics Corporation + * Based on imx8mp-hdmi-tx.c, which is: + * Copyright (C) 2022 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define TH1520_HDMI_PHY_OPMODE_PLLCFG 0x06 /* Mode of operation and PLL di= viders */ +#define TH1520_HDMI_PHY_CKSYMTXCTRL 0x09 /* Clock Symbol and Transmitter C= ontrol Register */ +#define TH1520_HDMI_PHY_VLEVCTRL 0x0e /* Voltage Level Control Register */ +#define TH1520_HDMI_PHY_PLLCURRGMPCTRL 0x10 /* PLL current and Gmp (conduc= tance) */ +#define TH1520_HDMI_PHY_PLLDIVCTRL 0x11 /* PLL dividers */ +#define TH1520_HDMI_PHY_TXTERM 0x19 /* Transmission Termination Register = */ + +struct th1520_hdmi_phy_params { + unsigned long mpixelclock; + u16 opmode_pllcfg; + u16 pllcurrgmpctrl; + u16 plldivctrl; + u16 cksymtxctrl; + u16 vlevctrl; + u16 txterm; +}; + +static const struct th1520_hdmi_phy_params th1520_hdmi_phy_params[] =3D { + { 35500000, 0x0003, 0x0283, 0x0628, 0x8088, 0x01a0, 0x0007 }, + { 44900000, 0x0003, 0x0285, 0x0228, 0x8088, 0x01a0, 0x0007 }, + { 71000000, 0x0002, 0x1183, 0x0614, 0x8088, 0x01a0, 0x0007 }, + { 90000000, 0x0002, 0x1142, 0x0214, 0x8088, 0x01a0, 0x0007 }, + { 121750000, 0x0001, 0x20c0, 0x060a, 0x8088, 0x01a0, 0x0007 }, + { 165000000, 0x0001, 0x2080, 0x020a, 0x8088, 0x01a0, 0x0007 }, + { 198000000, 0x0000, 0x3040, 0x0605, 0x83c8, 0x0120, 0x0004 }, + { 297000000, 0x0000, 0x3041, 0x0205, 0x81dc, 0x0200, 0x0005 }, + { 371250000, 0x0640, 0x3041, 0x0205, 0x80f6, 0x0140, 0x0000 }, + { 495000000, 0x0640, 0x3080, 0x0005, 0x80f6, 0x0140, 0x0000 }, + { 594000000, 0x0640, 0x3080, 0x0005, 0x80fa, 0x01e0, 0x0004 }, +}; + +struct th1520_hdmi { + struct dw_hdmi_plat_data plat_data; + struct dw_hdmi *dw_hdmi; + struct clk *pixclk; + struct reset_control *mainrst, *prst; +}; + +static enum drm_mode_status +th1520_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + /* + * The maximum supported clock frequency is 594 MHz, as shown in the PHY + * parameters table. + */ + if (mode->clock > 594000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static void th1520_hdmi_phy_set_params(struct dw_hdmi *hdmi, + const struct th1520_hdmi_phy_params *params) +{ + dw_hdmi_phy_i2c_write(hdmi, params->opmode_pllcfg, + TH1520_HDMI_PHY_OPMODE_PLLCFG); + dw_hdmi_phy_i2c_write(hdmi, params->pllcurrgmpctrl, + TH1520_HDMI_PHY_PLLCURRGMPCTRL); + dw_hdmi_phy_i2c_write(hdmi, params->plldivctrl, + TH1520_HDMI_PHY_PLLDIVCTRL); + dw_hdmi_phy_i2c_write(hdmi, params->vlevctrl, + TH1520_HDMI_PHY_VLEVCTRL); + dw_hdmi_phy_i2c_write(hdmi, params->cksymtxctrl, + TH1520_HDMI_PHY_CKSYMTXCTRL); + dw_hdmi_phy_i2c_write(hdmi, params->txterm, + TH1520_HDMI_PHY_TXTERM); +} + +static int th1520_hdmi_phy_configure(struct dw_hdmi *hdmi, void *data, + unsigned long mpixelclock) +{ + unsigned int i; + + for (i =3D 0; i < ARRAY_SIZE(th1520_hdmi_phy_params); i++) { + if (mpixelclock <=3D th1520_hdmi_phy_params[i].mpixelclock) { + th1520_hdmi_phy_set_params(hdmi, + &th1520_hdmi_phy_params[i]); + return 0; + } + } + + return -EINVAL; +} + +static int th1520_dw_hdmi_probe(struct platform_device *pdev) +{ + struct th1520_hdmi *hdmi; + struct dw_hdmi_plat_data *plat_data; + struct device *dev =3D &pdev->dev; + + hdmi =3D devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + plat_data =3D &hdmi->plat_data; + + hdmi->pixclk =3D devm_clk_get_enabled(dev, "pix"); + if (IS_ERR(hdmi->pixclk)) + return dev_err_probe(dev, PTR_ERR(hdmi->pixclk), + "Unable to get pixel clock\n"); + + hdmi->mainrst =3D devm_reset_control_get_exclusive_deasserted(dev, "main"= ); + if (IS_ERR(hdmi->mainrst)) + return dev_err_probe(dev, PTR_ERR(hdmi->mainrst), + "Unable to get main reset\n"); + + hdmi->prst =3D devm_reset_control_get_exclusive_deasserted(dev, "apb"); + if (IS_ERR(hdmi->prst)) + return dev_err_probe(dev, PTR_ERR(hdmi->prst), + "Unable to get apb reset\n"); + + plat_data->output_port =3D 1; + plat_data->mode_valid =3D th1520_hdmi_mode_valid; + plat_data->configure_phy =3D th1520_hdmi_phy_configure; + plat_data->priv_data =3D hdmi; + + hdmi->dw_hdmi =3D dw_hdmi_probe(pdev, plat_data); + if (IS_ERR(hdmi)) + return PTR_ERR(hdmi); + + platform_set_drvdata(pdev, hdmi); + + return 0; +} + +static void th1520_dw_hdmi_remove(struct platform_device *pdev) +{ + struct dw_hdmi *hdmi =3D platform_get_drvdata(pdev); + + dw_hdmi_remove(hdmi); +} + +static const struct of_device_id th1520_dw_hdmi_of_table[] =3D { + { .compatible =3D "thead,th1520-dw-hdmi" }, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, th1520_dw_hdmi_of_table); + +static struct platform_driver th1520_dw_hdmi_platform_driver =3D { + .probe =3D th1520_dw_hdmi_probe, + .remove =3D th1520_dw_hdmi_remove, + .driver =3D { + .name =3D "th1520-dw-hdmi", + .of_match_table =3D th1520_dw_hdmi_of_table, + }, +}; + +module_platform_driver(th1520_dw_hdmi_platform_driver); + +MODULE_AUTHOR("Icenowy Zheng "); +MODULE_DESCRIPTION("T-Head TH1520 HDMI Encoder Driver"); +MODULE_LICENSE("GPL"); --=20 2.52.0