From nobody Sat Oct 4 00:32:10 2025 Received: from m16.mail.163.com (m16.mail.163.com [117.135.210.2]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 09C4315747D; Fri, 22 Aug 2025 06:40:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=117.135.210.2 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844859; cv=none; b=hclGW3ugRuo8/p/sBJZ6r11BKiUvRGpk9BanvRhiE4zaHhU+nxLs2EYmQ0qwqtukmd3VyNiRiBevqDREq+GW2Fgoj6Zfhmis5msEMGSacZrekymGl7OXLXo8nrrXHiYUvE+LLX06PiBOX8Qpx6B21KvNklBZ6UZ55qoXvaHsniU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844859; c=relaxed/simple; bh=Pg8lVHVpKrLJGyAWWmIMdUMZs2RuoJ91xW03BMj0H5Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Zj9mYpYunh6XRefc8MwUdQuBG04z4GpDq4jeXVvxEO5I4nrfua+kAkxCD7PH9iyRl+QEn1PDW0XFbDVoTsa2iVEfrZrg8u+SvrWjwveKQ52dg1YVQZQVeilCQmUMnzexOA0hFqVkkJI/+1mw0gjlFWNRf6/m1zPHNZhs0ZsBvOs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=GS8Ck+mP; arc=none smtp.client-ip=117.135.210.2 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="GS8Ck+mP" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=AZ MUo7WLXMOMQHzwFbOsQWPJOJMT7XainwvPXkjTvQ0=; b=GS8Ck+mPGVyjDQ/fpi +kmcJ7CZ+tipU5bW12VurVk0HpEKdlSeADsLSPXCbzVQIyIqYKHWBzvKYaW5wW1V 4KlkT1uo3DKNvUYpag1BBLanNKxSSOzyRwlyPfT1SlbhedwcgXwu2LdXh7/FKYLd 6ahCgrKoURcJry7jCKJLKbnX0= Received: from ProDesk.. (unknown []) by gzsmtp3 (Coremail) with SMTP id PigvCgAn9_zCEKhoYtibAA--.23257S3; Fri, 22 Aug 2025 14:40:14 +0800 (CST) From: Andy Yan To: dmitry.baryshkov@oss.qualcomm.com, heiko@sntech.de Cc: hjc@rock-chips.com, mripard@kernel.org, naoki@radxa.com, stephen@radxa.com, cristian.ciocaltea@collabora.com, neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, yubing.zhang@rock-chips.com, krzk+dt@kernel.org, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, robh@kernel.org, sebastian.reichel@collabora.com, Andy Yan Subject: [PATCH v7 01/10] dt-bindings: display: rockchip: Add schema for RK3588 DPTX Controller Date: Fri, 22 Aug 2025 14:39:45 +0800 Message-ID: <20250822063959.692098-2-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822063959.692098-1-andyshrk@163.com> References: <20250822063959.692098-1-andyshrk@163.com> 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: PigvCgAn9_zCEKhoYtibAA--.23257S3 X-Coremail-Antispam: 1Uf129KBjvJXoWxWryfKrWfCryDXFW7uF13twb_yoWrCF4xpa n3CFZ8JrW09Fy7Xa95tF1kCrsYqw4kA3y7tw1xXw17tr4agFyYgw1a9rn8Z3srGFnrZay2 9FW7u34xtw47Zw7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jz4E_UUUUU= X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/xtbB0hmxXmioDHlwegAAsb Content-Type: text/plain; charset="utf-8" From: Andy Yan The Rockchip RK3588 SoC integrates the Synopsys DesignWare DPTX controller. And this DPTX controller need share a USBDP PHY with the USB 3.0 OTG controller during operation. Signed-off-by: Andy Yan Reviewed-by: Rob Herring (Arm) --- (no changes since v2) Changes in v2: - Link to V1: https://lore.kernel.org/linux-rockchip/20250223113036.74252-1= -andyshrk@163.com/ - Fix a character encoding issue .../display/rockchip/rockchip,dw-dp.yaml | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/rockchip/rock= chip,dw-dp.yaml diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw= -dp.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-d= p.yaml new file mode 100644 index 0000000000000..a8a0087179972 --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-dp.yaml @@ -0,0 +1,150 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/rockchip/rockchip,dw-dp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip DW DisplayPort Transmitter + +maintainers: + - Andy Yan + +description: | + The Rockchip RK3588 SoC integrates the Synopsys DesignWare DPTX controll= er + which is compliant with the DisplayPort Specification Version 1.4 with t= he + following features: + + * DisplayPort 1.4a + * Main Link: 1/2/4 lanes + * Main Link Support 1.62Gbps, 2.7Gbps, 5.4Gbps and 8.1Gbps + * AUX channel 1Mbps + * Single Stream Transport(SST) + * Multistream Transport (MST) + * Type-C support (alternate mode) + * HDCP 2.2, HDCP 1.3 + * Supports up to 8/10 bits per color component + * Supports RBG, YCbCr4:4:4, YCbCr4:2:2, YCbCr4:2:0 + * Pixel clock up to 594MHz + * I2S, SPDIF audio interface + +allOf: + - $ref: /schemas/sound/dai-common.yaml# + +properties: + compatible: + enum: + - rockchip,rk3588-dp + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Peripheral/APB bus clock + - description: DisplayPort AUX clock + - description: HDCP clock + - description: I2S interface clock + - description: SPDIF interfce clock + + clock-names: + items: + - const: apb + - const: aux + - const: hdcp + - const: i2s + - const: spdif + + phys: + maxItems: 1 + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: Video port for RGB/YUV input. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Video port for DP output. + + required: + - port@0 + - port@1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + "#sound-dai-cells": + const: 0 + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - phys + - ports + - resets + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + + soc { + #address-cells =3D <2>; + #size-cells =3D <2>; + + dp@fde50000 { + compatible =3D "rockchip,rk3588-dp"; + reg =3D <0x0 0xfde50000 0x0 0x4000>; + interrupts =3D ; + clocks =3D <&cru PCLK_DP0>, <&cru CLK_AUX16M_0>, + <&cru CLK_DP0>, <&cru MCLK_I2S4_8CH_TX>, + <&cru MCLK_SPDIF2_DP0>; + clock-names =3D "apb", "aux", "hdcp", "i2s", "spdif"; + assigned-clocks =3D <&cru CLK_AUX16M_0>; + assigned-clock-rates =3D <16000000>; + resets =3D <&cru SRST_DP0>; + phys =3D <&usbdp_phy0 PHY_TYPE_DP>; + power-domains =3D <&power RK3588_PD_VO0>; + #sound-dai-cells =3D <0>; + + + ports { + #address-cells =3D <1>; + #size-cells =3D <0>; + + port@0 { + reg =3D <0>; + + dp0_in_vp2: endpoint { + remote-endpoint =3D <&vp2_out_dp0>; + }; + }; + + port@1 { + reg =3D <1>; + + dp0_out_con0: endpoint { + remote-endpoint =3D <&dp_con0_in>; + }; + }; + }; + }; + }; --=20 2.43.0 From nobody Sat Oct 4 00:32:10 2025 Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.4]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3BDD52E7169; Fri, 22 Aug 2025 06:41:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.31.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844865; cv=none; b=grEYmWBpae1sX9SZTNCNry8rwTDA4Z3OyzoL3yHUg0D0IEwrptqHFI+PrEM+2+7M4Ucj5hO7ntCwpr1TPCCppJAmpyPPUMOm7ICMhb72lUy4J7WYurcrFuTIwyqGMmcaxUL37U7tvzkcYb2PXLkIDN/YzWeJKWv87MI7bI3QleI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844865; c=relaxed/simple; bh=nOl2E9JWLPH9SWrJNESwofvJSW8+LXqcscPcTq6aIzg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=puYG8ygNsK1FcVXBKzw7C0UJSaK2iDozpFXiqFawFlg1M3du6XHlluU3LrAsvle56jB8rCmfHTo8iZspElNvOrGjcN3YXzHgAEY7Q0glLvod0z9JFC94yCufgHh1VoFECwhLutxYPWWeAohlGGwRvjhPDQqffJEkIT66tGd2Xj0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=S9B53CiG; arc=none smtp.client-ip=220.197.31.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="S9B53CiG" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=7z dYn5MzM7XhZHmIFvigyn5X37wQeyKc0fEeZlTZR0E=; b=S9B53CiGDb4Wy4z2nw 2Xz+xlKR/9l08OClvHLMsiptGzNF+zb8Pnos08WZi2dVRQVaa33DM4j1um/FBiL/ zWit+1QT/wergsKIx8xbxyMSXRZsxvEYKBwMh1Xdd8F9S5uwuQHZZICEISBTlDag rI04Q1stK4bT2DVxYRYCVBkjU= Received: from ProDesk.. (unknown []) by gzsmtp3 (Coremail) with SMTP id PigvCgAn9_zCEKhoYtibAA--.23257S4; Fri, 22 Aug 2025 14:40:17 +0800 (CST) From: Andy Yan To: dmitry.baryshkov@oss.qualcomm.com, heiko@sntech.de Cc: hjc@rock-chips.com, mripard@kernel.org, naoki@radxa.com, stephen@radxa.com, cristian.ciocaltea@collabora.com, neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, yubing.zhang@rock-chips.com, krzk+dt@kernel.org, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, robh@kernel.org, sebastian.reichel@collabora.com, Andy Yan Subject: [PATCH v7 02/10] drm/bridge: synopsys: Add DW DPTX Controller support library Date: Fri, 22 Aug 2025 14:39:46 +0800 Message-ID: <20250822063959.692098-3-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822063959.692098-1-andyshrk@163.com> References: <20250822063959.692098-1-andyshrk@163.com> 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: PigvCgAn9_zCEKhoYtibAA--.23257S4 X-Coremail-Antispam: 1Uf129KBjvAXoWDJF4ruFW3XFW7KF4DGF47XFb_yoWxJFyrto WfurnxXw1xtryIvrZ3G3WIqa1jva4DJ39xCw1Fvr4ku3W3Zw1FgrZxKw43Ar1YqrWagrW7 ZrZ7t3Z3JFs3A3Z7n29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UbIYCTnIWIevJa73UjIFyTuYvjxUIBHqDUUUU X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiMxCxXmioB5f5vgAAsb Content-Type: text/plain; charset="utf-8" From: Andy Yan The DW DP TX Controller is compliant with the DisplayPort Specification Version 1.4 with the following features: * DisplayPort 1.4a * Main Link: 1/2/4 lanes * Main Link Support 1.62Gbps, 2.7Gbps, 5.4Gbps and 8.1Gbps * AUX channel 1Mbps * Single Stream Transport(SST) * Multistream Transport (MST) * Type-C support (alternate mode) * HDCP 2.2, HDCP 1.3 * Supports up to 8/10 bits per color component * Supports RBG, YCbCr4:4:4, YCbCr4:2:2, YCbCr4:2:0 * Pixel clock up to 594MHz * I2S, SPDIF audio interface Add library with common helpers to make it can be shared with other SoC. Signed-off-by: Andy Yan Reviewed-by: Dmitry Baryshkov Tested-by: Sebastian Reichel --- Changes in v7: - Fix checkpatch warnings Changes in v6: - Use drm_dp_vsc_sdp_supported - Store bpc/bpp/color format in dw_dp_bridge_state Changes in v5: - Use drm_dp_read_sink_count_cap instead of the private implementation. Changes in v4: - Drop unnecessary header files - Switch to devm_drm_bridge_alloc Changes in v3: - Rebase on drm-misc-next - Switch to common helpers to power up/down dp link - Only pass parameters to phy that should be set Changes in v2: - Fix compile error when build as module - Add phy init - Only use one dw_dp_link_train_set - inline dw_dp_phy_update_vs_emph - Use dp_sdp - Check return value of drm_modeset_lock - Merge code in atomic_pre_enable/mode_fixup to atomic_check - Return NULL if can't find a supported output format - Fix max_link_rate from plat_data drivers/gpu/drm/bridge/synopsys/Kconfig | 7 + drivers/gpu/drm/bridge/synopsys/Makefile | 1 + drivers/gpu/drm/bridge/synopsys/dw-dp.c | 2095 ++++++++++++++++++++++ include/drm/bridge/dw_dp.h | 20 + 4 files changed, 2123 insertions(+) create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-dp.c create mode 100644 include/drm/bridge/dw_dp.h diff --git a/drivers/gpu/drm/bridge/synopsys/Kconfig b/drivers/gpu/drm/brid= ge/synopsys/Kconfig index 99878f051067e..a46df7583bcf9 100644 --- a/drivers/gpu/drm/bridge/synopsys/Kconfig +++ b/drivers/gpu/drm/bridge/synopsys/Kconfig @@ -1,4 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-only +config DRM_DW_DP + tristate + select DRM_DISPLAY_HELPER + select DRM_DISPLAY_DP_HELPER + select DRM_KMS_HELPER + select REGMAP_MMIO + config DRM_DW_HDMI tristate select DRM_DISPLAY_HDMI_HELPER diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile b/drivers/gpu/drm/bri= dge/synopsys/Makefile index 9dc376d220ad7..4dada44029acf 100644 --- a/drivers/gpu/drm/bridge/synopsys/Makefile +++ b/drivers/gpu/drm/bridge/synopsys/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_DRM_DW_DP) +=3D dw-dp.o obj-$(CONFIG_DRM_DW_HDMI) +=3D dw-hdmi.o obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) +=3D dw-hdmi-ahb-audio.o obj-$(CONFIG_DRM_DW_HDMI_GP_AUDIO) +=3D dw-hdmi-gp-audio.o diff --git a/drivers/gpu/drm/bridge/synopsys/dw-dp.c b/drivers/gpu/drm/brid= ge/synopsys/dw-dp.c new file mode 100644 index 0000000000000..9bbfe8da3de02 --- /dev/null +++ b/drivers/gpu/drm/bridge/synopsys/dw-dp.c @@ -0,0 +1,2095 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Synopsys DesignWare Cores DisplayPort Transmitter Controller + * + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + * + * Author: Andy Yan + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DW_DP_VERSION_NUMBER 0x0000 +#define DW_DP_VERSION_TYPE 0x0004 +#define DW_DP_ID 0x0008 + +#define DW_DP_CONFIG_REG1 0x0100 +#define DW_DP_CONFIG_REG2 0x0104 +#define DW_DP_CONFIG_REG3 0x0108 + +#define DW_DP_CCTL 0x0200 +#define FORCE_HPD BIT(4) +#define DEFAULT_FAST_LINK_TRAIN_EN BIT(2) +#define ENHANCE_FRAMING_EN BIT(1) +#define SCRAMBLE_DIS BIT(0) +#define DW_DP_SOFT_RESET_CTRL 0x0204 +#define VIDEO_RESET BIT(5) +#define AUX_RESET BIT(4) +#define AUDIO_SAMPLER_RESET BIT(3) +#define HDCP_MODULE_RESET BIT(2) +#define PHY_SOFT_RESET BIT(1) +#define CONTROLLER_RESET BIT(0) + +#define DW_DP_VSAMPLE_CTRL 0x0300 +#define PIXEL_MODE_SELECT GENMASK(22, 21) +#define VIDEO_MAPPING GENMASK(20, 16) +#define VIDEO_STREAM_ENABLE BIT(5) + +#define DW_DP_VSAMPLE_STUFF_CTRL1 0x0304 + +#define DW_DP_VSAMPLE_STUFF_CTRL2 0x0308 + +#define DW_DP_VINPUT_POLARITY_CTRL 0x030c +#define DE_IN_POLARITY BIT(2) +#define HSYNC_IN_POLARITY BIT(1) +#define VSYNC_IN_POLARITY BIT(0) + +#define DW_DP_VIDEO_CONFIG1 0x0310 +#define HACTIVE GENMASK(31, 16) +#define HBLANK GENMASK(15, 2) +#define I_P BIT(1) +#define R_V_BLANK_IN_OSC BIT(0) + +#define DW_DP_VIDEO_CONFIG2 0x0314 +#define VBLANK GENMASK(31, 16) +#define VACTIVE GENMASK(15, 0) + +#define DW_DP_VIDEO_CONFIG3 0x0318 +#define H_SYNC_WIDTH GENMASK(31, 16) +#define H_FRONT_PORCH GENMASK(15, 0) + +#define DW_DP_VIDEO_CONFIG4 0x031c +#define V_SYNC_WIDTH GENMASK(31, 16) +#define V_FRONT_PORCH GENMASK(15, 0) + +#define DW_DP_VIDEO_CONFIG5 0x0320 +#define INIT_THRESHOLD_HI GENMASK(22, 21) +#define AVERAGE_BYTES_PER_TU_FRAC GENMASK(19, 16) +#define INIT_THRESHOLD GENMASK(13, 7) +#define AVERAGE_BYTES_PER_TU GENMASK(6, 0) + +#define DW_DP_VIDEO_MSA1 0x0324 +#define VSTART GENMASK(31, 16) +#define HSTART GENMASK(15, 0) + +#define DW_DP_VIDEO_MSA2 0x0328 +#define MISC0 GENMASK(31, 24) + +#define DW_DP_VIDEO_MSA3 0x032c +#define MISC1 GENMASK(31, 24) + +#define DW_DP_VIDEO_HBLANK_INTERVAL 0x0330 +#define HBLANK_INTERVAL_EN BIT(16) +#define HBLANK_INTERVAL GENMASK(15, 0) + +#define DW_DP_AUD_CONFIG1 0x0400 +#define AUDIO_TIMESTAMP_VERSION_NUM GENMASK(29, 24) +#define AUDIO_PACKET_ID GENMASK(23, 16) +#define AUDIO_MUTE BIT(15) +#define NUM_CHANNELS GENMASK(14, 12) +#define HBR_MODE_ENABLE BIT(10) +#define AUDIO_DATA_WIDTH GENMASK(9, 5) +#define AUDIO_DATA_IN_EN GENMASK(4, 1) +#define AUDIO_INF_SELECT BIT(0) + +#define DW_DP_SDP_VERTICAL_CTRL 0x0500 +#define EN_VERTICAL_SDP BIT(2) +#define EN_AUDIO_STREAM_SDP BIT(1) +#define EN_AUDIO_TIMESTAMP_SDP BIT(0) +#define DW_DP_SDP_HORIZONTAL_CTRL 0x0504 +#define EN_HORIZONTAL_SDP BIT(2) +#define DW_DP_SDP_STATUS_REGISTER 0x0508 +#define DW_DP_SDP_MANUAL_CTRL 0x050c +#define DW_DP_SDP_STATUS_EN 0x0510 + +#define DW_DP_SDP_REGISTER_BANK 0x0600 +#define SDP_REGS GENMASK(31, 0) + +#define DW_DP_PHYIF_CTRL 0x0a00 +#define PHY_WIDTH BIT(25) +#define PHY_POWERDOWN GENMASK(20, 17) +#define PHY_BUSY GENMASK(15, 12) +#define SSC_DIS BIT(16) +#define XMIT_ENABLE GENMASK(11, 8) +#define PHY_LANES GENMASK(7, 6) +#define PHY_RATE GENMASK(5, 4) +#define TPS_SEL GENMASK(3, 0) + +#define DW_DP_PHY_TX_EQ 0x0a04 +#define DW_DP_CUSTOMPAT0 0x0a08 +#define DW_DP_CUSTOMPAT1 0x0a0c +#define DW_DP_CUSTOMPAT2 0x0a10 +#define DW_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET 0x0a14 +#define DW_DP_PHYIF_PWRDOWN_CTRL 0x0a18 + +#define DW_DP_AUX_CMD 0x0b00 +#define AUX_CMD_TYPE GENMASK(31, 28) +#define AUX_ADDR GENMASK(27, 8) +#define I2C_ADDR_ONLY BIT(4) +#define AUX_LEN_REQ GENMASK(3, 0) + +#define DW_DP_AUX_STATUS 0x0b04 +#define AUX_TIMEOUT BIT(17) +#define AUX_BYTES_READ GENMASK(23, 19) +#define AUX_STATUS GENMASK(7, 4) + +#define DW_DP_AUX_DATA0 0x0b08 +#define DW_DP_AUX_DATA1 0x0b0c +#define DW_DP_AUX_DATA2 0x0b10 +#define DW_DP_AUX_DATA3 0x0b14 + +#define DW_DP_GENERAL_INTERRUPT 0x0d00 +#define VIDEO_FIFO_OVERFLOW_STREAM0 BIT(6) +#define AUDIO_FIFO_OVERFLOW_STREAM0 BIT(5) +#define SDP_EVENT_STREAM0 BIT(4) +#define AUX_CMD_INVALID BIT(3) +#define HDCP_EVENT BIT(2) +#define AUX_REPLY_EVENT BIT(1) +#define HPD_EVENT BIT(0) + +#define DW_DP_GENERAL_INTERRUPT_ENABLE 0x0d04 +#define HDCP_EVENT_EN BIT(2) +#define AUX_REPLY_EVENT_EN BIT(1) +#define HPD_EVENT_EN BIT(0) + +#define DW_DP_HPD_STATUS 0x0d08 +#define HPD_STATE GENMASK(11, 9) +#define HPD_STATUS BIT(8) +#define HPD_HOT_UNPLUG BIT(2) +#define HPD_HOT_PLUG BIT(1) +#define HPD_IRQ BIT(0) + +#define DW_DP_HPD_INTERRUPT_ENABLE 0x0d0c +#define HPD_UNPLUG_ERR_EN BIT(3) +#define HPD_UNPLUG_EN BIT(2) +#define HPD_PLUG_EN BIT(1) +#define HPD_IRQ_EN BIT(0) + +#define DW_DP_HDCP_CFG 0x0e00 +#define DPCD12PLUS BIT(7) +#define CP_IRQ BIT(6) +#define BYPENCRYPTION BIT(5) +#define HDCP_LOCK BIT(4) +#define ENCRYPTIONDISABLE BIT(3) +#define ENABLE_HDCP_13 BIT(2) +#define ENABLE_HDCP BIT(1) + +#define DW_DP_HDCP_OBS 0x0e04 +#define HDCP22_RE_AUTHENTICATION_REQ BIT(31) +#define HDCP22_AUTHENTICATION_FAILED BIT(30) +#define HDCP22_AUTHENTICATION_SUCCESS BIT(29) +#define HDCP22_CAPABLE_SINK BIT(28) +#define HDCP22_SINK_CAP_CHECK_COMPLETE BIT(27) +#define HDCP22_STATE GENMASK(26, 24) +#define HDCP22_BOOTED BIT(23) +#define HDCP13_BSTATUS GENMASK(22, 19) +#define REPEATER BIT(18) +#define HDCP_CAPABLE BIT(17) +#define STATEE GENMASK(16, 14) +#define STATEOEG GENMASK(13, 11) +#define STATER GENMASK(10, 8) +#define STATEA GENMASK(7, 4) +#define SUBSTATEA GENMASK(3, 1) +#define HDCPENGAGED BIT(0) + +#define DW_DP_HDCP_APIINTCLR 0x0e08 +#define DW_DP_HDCP_APIINTSTAT 0x0e0c +#define DW_DP_HDCP_APIINTMSK 0x0e10 +#define HDCP22_GPIOINT BIT(8) +#define HDCP_ENGAGED BIT(7) +#define HDCP_FAILED BIT(6) +#define KSVSHA1CALCDONEINT BIT(5) +#define AUXRESPNACK7TIMES BIT(4) +#define AUXRESPTIMEOUT BIT(3) +#define AUXRESPDEFER7TIMES BIT(2) +#define KSVACCESSINT BIT(0) + +#define DW_DP_HDCP_KSVMEMCTRL 0x0e18 +#define KSVSHA1STATUS BIT(4) +#define KSVMEMACCESS BIT(1) +#define KSVMEMREQUEST BIT(0) + +#define DW_DP_HDCP_REG_BKSV0 0x3600 +#define DW_DP_HDCP_REG_BKSV1 0x3604 +#define DW_DP_HDCP_REG_ANCONF 0x3608 +#define AN_BYPASS BIT(0) + +#define DW_DP_HDCP_REG_AN0 0x360c +#define DW_DP_HDCP_REG_AN1 0x3610 +#define DW_DP_HDCP_REG_RMLCTL 0x3614 +#define ODPK_DECRYPT_ENABLE BIT(0) + +#define DW_DP_HDCP_REG_RMLSTS 0x3618 +#define IDPK_WR_OK_STS BIT(6) +#define IDPK_DATA_INDEX GENMASK(5, 0) +#define DW_DP_HDCP_REG_SEED 0x361c +#define DW_DP_HDCP_REG_DPK0 0x3620 +#define DW_DP_HDCP_REG_DPK1 0x3624 +#define DW_DP_HDCP22_GPIOSTS 0x3628 +#define DW_DP_HDCP22_GPIOCHNGSTS 0x362c +#define DW_DP_HDCP_REG_DPK_CRC 0x3630 + +#define DW_DP_MAX_REGISTER DW_DP_HDCP_REG_DPK_CRC + +#define SDP_REG_BANK_SIZE 16 + +struct dw_dp_link_caps { + bool enhanced_framing; + bool tps3_supported; + bool tps4_supported; + bool fast_training; + bool channel_coding; + bool ssc; +}; + +struct dw_dp_link_train_set { + unsigned int voltage_swing[4]; + unsigned int pre_emphasis[4]; + bool voltage_max_reached[4]; + bool pre_max_reached[4]; +}; + +struct dw_dp_link_train { + struct dw_dp_link_train_set adjust; + bool clock_recovered; + bool channel_equalized; +}; + +struct dw_dp_link { + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + unsigned char revision; + unsigned int rate; + unsigned int lanes; + u8 sink_count; + u8 vsc_sdp_supported; + struct dw_dp_link_caps caps; + struct dw_dp_link_train train; + struct drm_dp_desc desc; +}; + +struct dw_dp_bridge_state { + struct drm_bridge_state base; + struct drm_display_mode mode; + u8 video_mapping; + u8 color_format; + u8 bpc; + u8 bpp; +}; + +struct dw_dp_sdp { + struct dp_sdp base; + unsigned long flags; +}; + +struct dw_dp_hotplug { + bool long_hpd; +}; + +struct dw_dp { + struct drm_bridge bridge; + struct device *dev; + struct regmap *regmap; + struct phy *phy; + struct clk *apb_clk; + struct clk *aux_clk; + struct clk *i2s_clk; + struct clk *spdif_clk; + struct clk *hdcp_clk; + struct reset_control *rstc; + struct completion complete; + int irq; + struct work_struct hpd_work; + struct dw_dp_hotplug hotplug; + /* Serialize hpd status access */ + struct mutex irq_lock; + + struct drm_dp_aux aux; + + struct dw_dp_link link; + struct dw_dp_plat_data plat_data; + u8 pixel_mode; + + DECLARE_BITMAP(sdp_reg_bank, SDP_REG_BANK_SIZE); +}; + +enum { + DW_DP_RGB_6BIT, + DW_DP_RGB_8BIT, + DW_DP_RGB_10BIT, + DW_DP_RGB_12BIT, + DW_DP_RGB_16BIT, + DW_DP_YCBCR444_8BIT, + DW_DP_YCBCR444_10BIT, + DW_DP_YCBCR444_12BIT, + DW_DP_YCBCR444_16BIT, + DW_DP_YCBCR422_8BIT, + DW_DP_YCBCR422_10BIT, + DW_DP_YCBCR422_12BIT, + DW_DP_YCBCR422_16BIT, + DW_DP_YCBCR420_8BIT, + DW_DP_YCBCR420_10BIT, + DW_DP_YCBCR420_12BIT, + DW_DP_YCBCR420_16BIT, +}; + +enum { + DW_DP_MP_SINGLE_PIXEL, + DW_DP_MP_DUAL_PIXEL, + DW_DP_MP_QUAD_PIXEL, +}; + +enum { + DW_DP_SDP_VERTICAL_INTERVAL =3D BIT(0), + DW_DP_SDP_HORIZONTAL_INTERVAL =3D BIT(1), +}; + +enum { + DW_DP_HPD_STATE_IDLE, + DW_DP_HPD_STATE_UNPLUG, + DP_DP_HPD_STATE_TIMEOUT =3D 4, + DW_DP_HPD_STATE_PLUG =3D 7 +}; + +enum { + DW_DP_PHY_PATTERN_NONE, + DW_DP_PHY_PATTERN_TPS_1, + DW_DP_PHY_PATTERN_TPS_2, + DW_DP_PHY_PATTERN_TPS_3, + DW_DP_PHY_PATTERN_TPS_4, + DW_DP_PHY_PATTERN_SERM, + DW_DP_PHY_PATTERN_PBRS7, + DW_DP_PHY_PATTERN_CUSTOM_80BIT, + DW_DP_PHY_PATTERN_CP2520_1, + DW_DP_PHY_PATTERN_CP2520_2, +}; + +struct dw_dp_output_format { + u32 bus_format; + u32 color_format; + u8 video_mapping; + u8 bpc; + u8 bpp; +}; + +#define to_dw_dp_bridge_state(s) container_of(s, struct dw_dp_bridge_state= , base) + +static const struct dw_dp_output_format dw_dp_output_formats[] =3D { + { MEDIA_BUS_FMT_RGB101010_1X30, DRM_COLOR_FORMAT_RGB444, DW_DP_RGB_10BIT,= 10, 30 }, + { MEDIA_BUS_FMT_RGB888_1X24, DRM_COLOR_FORMAT_RGB444, DW_DP_RGB_8BIT, 8, = 24 }, + { MEDIA_BUS_FMT_YUV10_1X30, DRM_COLOR_FORMAT_YCBCR444, DW_DP_YCBCR444_10B= IT, 10, 30 }, + { MEDIA_BUS_FMT_YUV8_1X24, DRM_COLOR_FORMAT_YCBCR444, DW_DP_YCBCR444_8BIT= , 8, 24}, + { MEDIA_BUS_FMT_YUYV10_1X20, DRM_COLOR_FORMAT_YCBCR422, DW_DP_YCBCR422_10= BIT, 10, 20 }, + { MEDIA_BUS_FMT_YUYV8_1X16, DRM_COLOR_FORMAT_YCBCR422, DW_DP_YCBCR422_8BI= T, 8, 16 }, + { MEDIA_BUS_FMT_UYYVYY10_0_5X30, DRM_COLOR_FORMAT_YCBCR420, DW_DP_YCBCR42= 0_10BIT, 10, 15 }, + { MEDIA_BUS_FMT_UYYVYY8_0_5X24, DRM_COLOR_FORMAT_YCBCR420, DW_DP_YCBCR420= _8BIT, 8, 12 }, + { MEDIA_BUS_FMT_RGB666_1X24_CPADHI, DRM_COLOR_FORMAT_RGB444, DW_DP_RGB_6B= IT, 6, 18 }, +}; + +static const struct dw_dp_output_format *dw_dp_get_output_format(u32 bus_f= ormat) +{ + unsigned int i; + + for (i =3D 0; i < ARRAY_SIZE(dw_dp_output_formats); i++) + if (dw_dp_output_formats[i].bus_format =3D=3D bus_format) + return &dw_dp_output_formats[i]; + + return NULL; +} + +static inline struct dw_dp *bridge_to_dp(struct drm_bridge *b) +{ + return container_of(b, struct dw_dp, bridge); +} + +static struct dw_dp_bridge_state *dw_dp_get_bridge_state(struct dw_dp *dp) +{ + struct dw_dp_bridge_state *dw_bridge_state; + struct drm_bridge_state *state; + + state =3D drm_priv_to_bridge_state(dp->bridge.base.state); + if (!state) + return NULL; + + dw_bridge_state =3D to_dw_dp_bridge_state(state); + if (!dw_bridge_state) + return NULL; + + return dw_bridge_state; +} + +static inline void dw_dp_phy_set_pattern(struct dw_dp *dp, u32 pattern) +{ + regmap_update_bits(dp->regmap, DW_DP_PHYIF_CTRL, TPS_SEL, + FIELD_PREP(TPS_SEL, pattern)); +} + +static void dw_dp_phy_xmit_enable(struct dw_dp *dp, u32 lanes) +{ + u32 xmit_enable; + + switch (lanes) { + case 4: + case 2: + case 1: + xmit_enable =3D GENMASK(lanes - 1, 0); + break; + case 0: + default: + xmit_enable =3D 0; + break; + } + + regmap_update_bits(dp->regmap, DW_DP_PHYIF_CTRL, XMIT_ENABLE, + FIELD_PREP(XMIT_ENABLE, xmit_enable)); +} + +static bool dw_dp_bandwidth_ok(struct dw_dp *dp, + const struct drm_display_mode *mode, u32 bpp, + unsigned int lanes, unsigned int rate) +{ + u32 max_bw, req_bw; + + req_bw =3D mode->clock * bpp / 8; + max_bw =3D lanes * rate; + if (req_bw > max_bw) + return false; + + return true; +} + +static bool dw_dp_hpd_detect(struct dw_dp *dp) +{ + u32 value; + + regmap_read(dp->regmap, DW_DP_HPD_STATUS, &value); + + return FIELD_GET(HPD_STATE, value) =3D=3D DW_DP_HPD_STATE_PLUG; +} + +static void dw_dp_link_caps_reset(struct dw_dp_link_caps *caps) +{ + caps->enhanced_framing =3D false; + caps->tps3_supported =3D false; + caps->tps4_supported =3D false; + caps->fast_training =3D false; + caps->channel_coding =3D false; +} + +static void dw_dp_link_reset(struct dw_dp_link *link) +{ + link->vsc_sdp_supported =3D 0; + link->sink_count =3D 0; + link->revision =3D 0; + link->rate =3D 0; + link->lanes =3D 0; + + dw_dp_link_caps_reset(&link->caps); + memset(link->dpcd, 0, sizeof(link->dpcd)); +} + +static int dw_dp_link_parse(struct dw_dp *dp, struct drm_connector *connec= tor) +{ + struct dw_dp_link *link =3D &dp->link; + int ret; + + dw_dp_link_reset(link); + + ret =3D drm_dp_read_dpcd_caps(&dp->aux, link->dpcd); + if (ret < 0) + return ret; + + drm_dp_read_desc(&dp->aux, &link->desc, drm_dp_is_branch(link->dpcd)); + + if (drm_dp_read_sink_count_cap(connector, link->dpcd, &link->desc)) { + ret =3D drm_dp_read_sink_count(&dp->aux); + if (ret < 0) + return ret; + + link->sink_count =3D ret; + + /* Dongle connected, but no display */ + if (!link->sink_count) + return -ENODEV; + } + + link->vsc_sdp_supported =3D drm_dp_vsc_sdp_supported(&dp->aux, link->dpcd= ); + + link->revision =3D link->dpcd[DP_DPCD_REV]; + link->rate =3D min_t(u32, min(dp->plat_data.max_link_rate, + dp->phy->attrs.max_link_rate * 100), + drm_dp_max_link_rate(link->dpcd)); + link->lanes =3D min_t(u8, phy_get_bus_width(dp->phy), + drm_dp_max_lane_count(link->dpcd)); + + link->caps.enhanced_framing =3D drm_dp_enhanced_frame_cap(link->dpcd); + link->caps.tps3_supported =3D drm_dp_tps3_supported(link->dpcd); + link->caps.tps4_supported =3D drm_dp_tps4_supported(link->dpcd); + link->caps.fast_training =3D drm_dp_fast_training_cap(link->dpcd); + link->caps.channel_coding =3D drm_dp_channel_coding_supported(link->dpcd); + link->caps.ssc =3D !!(link->dpcd[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0= _5); + + return 0; +} + +static int dw_dp_link_train_update_vs_emph(struct dw_dp *dp) +{ + struct dw_dp_link *link =3D &dp->link; + struct dw_dp_link_train_set *train_set =3D &link->train.adjust; + unsigned int lanes =3D dp->link.lanes; + union phy_configure_opts phy_cfg; + unsigned int *vs, *pe; + int i, ret; + u8 buf[4]; + + vs =3D train_set->voltage_swing; + pe =3D train_set->pre_emphasis; + + for (i =3D 0; i < lanes; i++) { + phy_cfg.dp.voltage[i] =3D vs[i]; + phy_cfg.dp.pre[i] =3D pe[i]; + } + + phy_cfg.dp.set_lanes =3D false; + phy_cfg.dp.set_rate =3D false; + phy_cfg.dp.set_voltages =3D true; + + ret =3D phy_configure(dp->phy, &phy_cfg); + if (ret) + return ret; + + for (i =3D 0; i < lanes; i++) { + buf[i] =3D (vs[i] << DP_TRAIN_VOLTAGE_SWING_SHIFT) | + (pe[i] << DP_TRAIN_PRE_EMPHASIS_SHIFT); + if (train_set->voltage_max_reached[i]) + buf[i] |=3D DP_TRAIN_MAX_SWING_REACHED; + if (train_set->pre_max_reached[i]) + buf[i] |=3D DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; + } + + ret =3D drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf, lanes); + if (ret < 0) + return ret; + + return 0; +} + +static int dw_dp_phy_configure(struct dw_dp *dp, unsigned int rate, + unsigned int lanes, bool ssc) +{ + union phy_configure_opts phy_cfg; + int ret; + + /* Move PHY to P3 */ + regmap_update_bits(dp->regmap, DW_DP_PHYIF_CTRL, PHY_POWERDOWN, + FIELD_PREP(PHY_POWERDOWN, 0x3)); + + phy_cfg.dp.lanes =3D lanes; + phy_cfg.dp.link_rate =3D rate / 100; + phy_cfg.dp.ssc =3D ssc; + phy_cfg.dp.set_lanes =3D true; + phy_cfg.dp.set_rate =3D true; + phy_cfg.dp.set_voltages =3D false; + ret =3D phy_configure(dp->phy, &phy_cfg); + if (ret) + return ret; + + regmap_update_bits(dp->regmap, DW_DP_PHYIF_CTRL, PHY_LANES, + FIELD_PREP(PHY_LANES, lanes / 2)); + + /* Move PHY to P0 */ + regmap_update_bits(dp->regmap, DW_DP_PHYIF_CTRL, PHY_POWERDOWN, + FIELD_PREP(PHY_POWERDOWN, 0x0)); + + dw_dp_phy_xmit_enable(dp, lanes); + + return 0; +} + +static int dw_dp_link_configure(struct dw_dp *dp) +{ + struct dw_dp_link *link =3D &dp->link; + u8 buf[2]; + int ret; + + ret =3D dw_dp_phy_configure(dp, link->rate, link->lanes, link->caps.ssc); + if (ret) + return ret; + + buf[0] =3D drm_dp_link_rate_to_bw_code(link->rate); + buf[1] =3D link->lanes; + + if (link->caps.enhanced_framing) { + buf[1] |=3D DP_LANE_COUNT_ENHANCED_FRAME_EN; + regmap_update_bits(dp->regmap, DW_DP_CCTL, ENHANCE_FRAMING_EN, + FIELD_PREP(ENHANCE_FRAMING_EN, 1)); + } else { + regmap_update_bits(dp->regmap, DW_DP_CCTL, ENHANCE_FRAMING_EN, + FIELD_PREP(ENHANCE_FRAMING_EN, 0)); + } + + ret =3D drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, sizeof(buf)); + if (ret < 0) + return ret; + + buf[0] =3D link->caps.ssc ? DP_SPREAD_AMP_0_5 : 0; + buf[1] =3D link->caps.channel_coding ? DP_SET_ANSI_8B10B : 0; + + ret =3D drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf, sizeof(buf)); + if (ret < 0) + return ret; + + return 0; +} + +static void dw_dp_link_train_init(struct dw_dp_link_train *train) +{ + struct dw_dp_link_train_set *adj =3D &train->adjust; + unsigned int i; + + for (i =3D 0; i < 4; i++) { + adj->voltage_swing[i] =3D 0; + adj->pre_emphasis[i] =3D 0; + adj->voltage_max_reached[i] =3D false; + adj->pre_max_reached[i] =3D false; + } + + train->clock_recovered =3D false; + train->channel_equalized =3D false; +} + +static bool dw_dp_link_train_valid(const struct dw_dp_link_train *train) +{ + return train->clock_recovered && train->channel_equalized; +} + +static int dw_dp_link_train_set_pattern(struct dw_dp *dp, u32 pattern) +{ + u8 buf =3D 0; + int ret; + + if (pattern && pattern !=3D DP_TRAINING_PATTERN_4) { + buf |=3D DP_LINK_SCRAMBLING_DISABLE; + + regmap_update_bits(dp->regmap, DW_DP_CCTL, SCRAMBLE_DIS, + FIELD_PREP(SCRAMBLE_DIS, 1)); + } else { + regmap_update_bits(dp->regmap, DW_DP_CCTL, SCRAMBLE_DIS, + FIELD_PREP(SCRAMBLE_DIS, 0)); + } + + switch (pattern) { + case DP_TRAINING_PATTERN_DISABLE: + dw_dp_phy_set_pattern(dp, DW_DP_PHY_PATTERN_NONE); + break; + case DP_TRAINING_PATTERN_1: + dw_dp_phy_set_pattern(dp, DW_DP_PHY_PATTERN_TPS_1); + break; + case DP_TRAINING_PATTERN_2: + dw_dp_phy_set_pattern(dp, DW_DP_PHY_PATTERN_TPS_2); + break; + case DP_TRAINING_PATTERN_3: + dw_dp_phy_set_pattern(dp, DW_DP_PHY_PATTERN_TPS_3); + break; + case DP_TRAINING_PATTERN_4: + dw_dp_phy_set_pattern(dp, DW_DP_PHY_PATTERN_TPS_4); + break; + default: + return -EINVAL; + } + + ret =3D drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, + buf | pattern); + if (ret < 0) + return ret; + + return 0; +} + +static u8 dw_dp_voltage_max(u8 preemph) +{ + switch (preemph & DP_TRAIN_PRE_EMPHASIS_MASK) { + case DP_TRAIN_PRE_EMPH_LEVEL_0: + return DP_TRAIN_VOLTAGE_SWING_LEVEL_3; + case DP_TRAIN_PRE_EMPH_LEVEL_1: + return DP_TRAIN_VOLTAGE_SWING_LEVEL_2; + case DP_TRAIN_PRE_EMPH_LEVEL_2: + return DP_TRAIN_VOLTAGE_SWING_LEVEL_1; + case DP_TRAIN_PRE_EMPH_LEVEL_3: + default: + return DP_TRAIN_VOLTAGE_SWING_LEVEL_0; + } +} + +static bool dw_dp_link_get_adjustments(struct dw_dp_link *link, + u8 status[DP_LINK_STATUS_SIZE]) +{ + struct dw_dp_link_train_set *adj =3D &link->train.adjust; + unsigned int i; + bool changed =3D false; + u8 v =3D 0; + u8 p =3D 0; + + for (i =3D 0; i < link->lanes; i++) { + v =3D drm_dp_get_adjust_request_voltage(status, i); + v >>=3D DP_TRAIN_VOLTAGE_SWING_SHIFT; + p =3D drm_dp_get_adjust_request_pre_emphasis(status, i); + p >>=3D DP_TRAIN_PRE_EMPHASIS_SHIFT; + + if (v !=3D adj->voltage_swing[i] || p !=3D adj->pre_emphasis[i]) + changed =3D true; + + if (p >=3D (DP_TRAIN_PRE_EMPH_LEVEL_3 >> DP_TRAIN_PRE_EMPHASIS_SHIFT)) { + adj->pre_emphasis[i] =3D DP_TRAIN_PRE_EMPH_LEVEL_3 >> + DP_TRAIN_PRE_EMPHASIS_SHIFT; + adj->pre_max_reached[i] =3D true; + } else { + adj->pre_emphasis[i] =3D p; + adj->pre_max_reached[i] =3D false; + } + + v =3D min(v, dw_dp_voltage_max(p)); + if (v >=3D (DP_TRAIN_VOLTAGE_SWING_LEVEL_3 >> DP_TRAIN_VOLTAGE_SWING_SHI= FT)) { + adj->voltage_swing[i] =3D DP_TRAIN_VOLTAGE_SWING_LEVEL_3 >> + DP_TRAIN_VOLTAGE_SWING_SHIFT; + adj->voltage_max_reached[i] =3D true; + } else { + adj->voltage_swing[i] =3D v; + adj->voltage_max_reached[i] =3D false; + } + } + + return changed; +} + +static int dw_dp_link_clock_recovery(struct dw_dp *dp) +{ + struct dw_dp_link *link =3D &dp->link; + u8 status[DP_LINK_STATUS_SIZE]; + unsigned int tries =3D 0; + int ret; + bool adj_changed; + + ret =3D dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_1); + if (ret) + return ret; + + for (;;) { + ret =3D dw_dp_link_train_update_vs_emph(dp); + if (ret) + return ret; + + drm_dp_link_train_clock_recovery_delay(&dp->aux, link->dpcd); + + ret =3D drm_dp_dpcd_read_link_status(&dp->aux, status); + if (ret < 0) { + dev_err(dp->dev, "failed to read link status: %d\n", ret); + return ret; + } + + if (drm_dp_clock_recovery_ok(status, link->lanes)) { + link->train.clock_recovered =3D true; + break; + } + + /* + * According to DP spec 1.4, if current ADJ is the same + * with previous REQ, we need to retry 5 times. + */ + adj_changed =3D dw_dp_link_get_adjustments(link, status); + if (!adj_changed) + tries++; + else + tries =3D 0; + + if (tries =3D=3D 5) + break; + } + + return 0; +} + +static int dw_dp_link_channel_equalization(struct dw_dp *dp) +{ + struct dw_dp_link *link =3D &dp->link; + u8 status[DP_LINK_STATUS_SIZE], pattern; + unsigned int tries; + int ret; + + if (link->caps.tps4_supported) + pattern =3D DP_TRAINING_PATTERN_4; + else if (link->caps.tps3_supported) + pattern =3D DP_TRAINING_PATTERN_3; + else + pattern =3D DP_TRAINING_PATTERN_2; + ret =3D dw_dp_link_train_set_pattern(dp, pattern); + if (ret) + return ret; + + for (tries =3D 1; tries < 5; tries++) { + ret =3D dw_dp_link_train_update_vs_emph(dp); + if (ret) + return ret; + + drm_dp_link_train_channel_eq_delay(&dp->aux, link->dpcd); + + ret =3D drm_dp_dpcd_read_link_status(&dp->aux, status); + if (ret < 0) + return ret; + + if (!drm_dp_clock_recovery_ok(status, link->lanes)) { + dev_err(dp->dev, "clock recovery lost while equalizing channel\n"); + link->train.clock_recovered =3D false; + break; + } + + if (drm_dp_channel_eq_ok(status, link->lanes)) { + link->train.channel_equalized =3D true; + break; + } + + dw_dp_link_get_adjustments(link, status); + } + + return 0; +} + +static int dw_dp_link_downgrade(struct dw_dp *dp) +{ + struct dw_dp_link *link =3D &dp->link; + struct dw_dp_bridge_state *state; + + state =3D dw_dp_get_bridge_state(dp); + + switch (link->rate) { + case 162000: + return -EINVAL; + case 270000: + link->rate =3D 162000; + break; + case 540000: + link->rate =3D 270000; + break; + case 810000: + link->rate =3D 540000; + break; + } + + if (!dw_dp_bandwidth_ok(dp, &state->mode, state->bpp, link->lanes, + link->rate)) + return -E2BIG; + + return 0; +} + +static int dw_dp_link_train_full(struct dw_dp *dp) +{ + struct dw_dp_link *link =3D &dp->link; + int ret; + +retry: + dw_dp_link_train_init(&link->train); + + dev_dbg(dp->dev, "full-training link: %u lane%s at %u MHz\n", + link->lanes, (link->lanes > 1) ? "s" : "", link->rate / 100); + + ret =3D dw_dp_link_configure(dp); + if (ret < 0) { + dev_err(dp->dev, "failed to configure DP link: %d\n", ret); + return ret; + } + + ret =3D dw_dp_link_clock_recovery(dp); + if (ret < 0) { + dev_err(dp->dev, "clock recovery failed: %d\n", ret); + goto out; + } + + if (!link->train.clock_recovered) { + dev_err(dp->dev, "clock recovery failed, downgrading link\n"); + + ret =3D dw_dp_link_downgrade(dp); + if (ret < 0) + goto out; + else + goto retry; + } + + dev_dbg(dp->dev, "clock recovery succeeded\n"); + + ret =3D dw_dp_link_channel_equalization(dp); + if (ret < 0) { + dev_err(dp->dev, "channel equalization failed: %d\n", ret); + goto out; + } + + if (!link->train.channel_equalized) { + dev_err(dp->dev, "channel equalization failed, downgrading link\n"); + + ret =3D dw_dp_link_downgrade(dp); + if (ret < 0) + goto out; + else + goto retry; + } + + dev_dbg(dp->dev, "channel equalization succeeded\n"); + +out: + dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE); + return ret; +} + +static int dw_dp_link_train_fast(struct dw_dp *dp) +{ + struct dw_dp_link *link =3D &dp->link; + int ret; + u8 status[DP_LINK_STATUS_SIZE]; + u8 pattern; + + dw_dp_link_train_init(&link->train); + + dev_dbg(dp->dev, "fast-training link: %u lane%s at %u MHz\n", + link->lanes, (link->lanes > 1) ? "s" : "", link->rate / 100); + + ret =3D dw_dp_link_configure(dp); + if (ret < 0) { + dev_err(dp->dev, "failed to configure DP link: %d\n", ret); + return ret; + } + + ret =3D dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_1); + if (ret) + goto out; + + usleep_range(500, 1000); + + if (link->caps.tps4_supported) + pattern =3D DP_TRAINING_PATTERN_4; + else if (link->caps.tps3_supported) + pattern =3D DP_TRAINING_PATTERN_3; + else + pattern =3D DP_TRAINING_PATTERN_2; + ret =3D dw_dp_link_train_set_pattern(dp, pattern); + if (ret) + goto out; + + usleep_range(500, 1000); + + ret =3D drm_dp_dpcd_read_link_status(&dp->aux, status); + if (ret < 0) { + dev_err(dp->dev, "failed to read link status: %d\n", ret); + goto out; + } + + if (!drm_dp_clock_recovery_ok(status, link->lanes)) { + dev_err(dp->dev, "clock recovery failed\n"); + ret =3D -EIO; + goto out; + } + + if (!drm_dp_channel_eq_ok(status, link->lanes)) { + dev_err(dp->dev, "channel equalization failed\n"); + ret =3D -EIO; + goto out; + } + +out: + dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE); + return ret; +} + +static int dw_dp_link_train(struct dw_dp *dp) +{ + struct dw_dp_link *link =3D &dp->link; + int ret; + + if (link->caps.fast_training) { + if (dw_dp_link_train_valid(&link->train)) { + ret =3D dw_dp_link_train_fast(dp); + if (ret < 0) + dev_err(dp->dev, "fast link training failed: %d\n", ret); + else + return 0; + } + } + + ret =3D dw_dp_link_train_full(dp); + if (ret < 0) { + dev_err(dp->dev, "full link training failed: %d\n", ret); + return ret; + } + + return 0; +} + +static int dw_dp_send_sdp(struct dw_dp *dp, struct dw_dp_sdp *sdp) +{ + const u8 *payload =3D sdp->base.db; + u32 reg; + int i, nr; + + nr =3D find_first_zero_bit(dp->sdp_reg_bank, SDP_REG_BANK_SIZE); + if (nr < SDP_REG_BANK_SIZE) + set_bit(nr, dp->sdp_reg_bank); + else + return -EBUSY; + + reg =3D DW_DP_SDP_REGISTER_BANK + nr * 9 * 4; + + /* SDP header */ + regmap_write(dp->regmap, reg, get_unaligned_le32(&sdp->base.sdp_header)); + + /* SDP data payload */ + for (i =3D 1; i < 9; i++, payload +=3D 4) + regmap_write(dp->regmap, reg + i * 4, + FIELD_PREP(SDP_REGS, get_unaligned_le32(payload))); + + if (sdp->flags & DW_DP_SDP_VERTICAL_INTERVAL) + regmap_update_bits(dp->regmap, DW_DP_SDP_VERTICAL_CTRL, + EN_VERTICAL_SDP << nr, + EN_VERTICAL_SDP << nr); + + if (sdp->flags & DW_DP_SDP_HORIZONTAL_INTERVAL) + regmap_update_bits(dp->regmap, DW_DP_SDP_HORIZONTAL_CTRL, + EN_HORIZONTAL_SDP << nr, + EN_HORIZONTAL_SDP << nr); + + return 0; +} + +static int dw_dp_send_vsc_sdp(struct dw_dp *dp) +{ + struct dw_dp_bridge_state *state; + struct dw_dp_sdp sdp =3D {}; + struct drm_dp_vsc_sdp vsc =3D {}; + + state =3D dw_dp_get_bridge_state(dp); + if (!state) + return -EINVAL; + + vsc.bpc =3D state->bpc; + + vsc.sdp_type =3D DP_SDP_VSC; + vsc.revision =3D 0x5; + vsc.length =3D 0x13; + vsc.content_type =3D DP_CONTENT_TYPE_NOT_DEFINED; + + sdp.flags =3D DW_DP_SDP_VERTICAL_INTERVAL; + + switch (state->color_format) { + case DRM_COLOR_FORMAT_YCBCR444: + vsc.pixelformat =3D DP_PIXELFORMAT_YUV444; + break; + case DRM_COLOR_FORMAT_YCBCR420: + vsc.pixelformat =3D DP_PIXELFORMAT_YUV420; + break; + case DRM_COLOR_FORMAT_YCBCR422: + vsc.pixelformat =3D DP_PIXELFORMAT_YUV422; + break; + case DRM_COLOR_FORMAT_RGB444: + default: + vsc.pixelformat =3D DP_PIXELFORMAT_RGB; + break; + } + + if (state->color_format =3D=3D DRM_COLOR_FORMAT_RGB444) { + vsc.colorimetry =3D DP_COLORIMETRY_DEFAULT; + vsc.dynamic_range =3D DP_DYNAMIC_RANGE_VESA; + } else { + vsc.colorimetry =3D DP_COLORIMETRY_BT709_YCC; + vsc.dynamic_range =3D DP_DYNAMIC_RANGE_CTA; + } + + drm_dp_vsc_sdp_pack(&vsc, &sdp.base); + + return dw_dp_send_sdp(dp, &sdp); +} + +static int dw_dp_video_set_pixel_mode(struct dw_dp *dp) +{ + switch (dp->pixel_mode) { + case DW_DP_MP_SINGLE_PIXEL: + case DW_DP_MP_DUAL_PIXEL: + case DW_DP_MP_QUAD_PIXEL: + break; + default: + return -EINVAL; + } + + regmap_update_bits(dp->regmap, DW_DP_VSAMPLE_CTRL, PIXEL_MODE_SELECT, + FIELD_PREP(PIXEL_MODE_SELECT, dp->pixel_mode)); + + return 0; +} + +static bool dw_dp_video_need_vsc_sdp(struct dw_dp *dp) +{ + struct dw_dp_link *link =3D &dp->link; + struct dw_dp_bridge_state *state; + + state =3D dw_dp_get_bridge_state(dp); + if (!state) + return -EINVAL; + + if (!link->vsc_sdp_supported) + return false; + + if (state->color_format =3D=3D DRM_COLOR_FORMAT_YCBCR420) + return true; + + return false; +} + +static int dw_dp_video_set_msa(struct dw_dp *dp, u8 color_format, u8 bpc, + u16 vstart, u16 hstart) +{ + u16 misc =3D 0; + + if (dw_dp_video_need_vsc_sdp(dp)) + misc |=3D DP_MSA_MISC_COLOR_VSC_SDP; + + switch (color_format) { + case DRM_COLOR_FORMAT_RGB444: + misc |=3D DP_MSA_MISC_COLOR_RGB; + break; + case DRM_COLOR_FORMAT_YCBCR444: + misc |=3D DP_MSA_MISC_COLOR_YCBCR_444_BT709; + break; + case DRM_COLOR_FORMAT_YCBCR422: + misc |=3D DP_MSA_MISC_COLOR_YCBCR_422_BT709; + break; + case DRM_COLOR_FORMAT_YCBCR420: + break; + default: + return -EINVAL; + } + + switch (bpc) { + case 6: + misc |=3D DP_MSA_MISC_6_BPC; + break; + case 8: + misc |=3D DP_MSA_MISC_8_BPC; + break; + case 10: + misc |=3D DP_MSA_MISC_10_BPC; + break; + case 12: + misc |=3D DP_MSA_MISC_12_BPC; + break; + case 16: + misc |=3D DP_MSA_MISC_16_BPC; + break; + default: + return -EINVAL; + } + + regmap_write(dp->regmap, DW_DP_VIDEO_MSA1, + FIELD_PREP(VSTART, vstart) | FIELD_PREP(HSTART, hstart)); + regmap_write(dp->regmap, DW_DP_VIDEO_MSA2, FIELD_PREP(MISC0, misc)); + regmap_write(dp->regmap, DW_DP_VIDEO_MSA3, FIELD_PREP(MISC1, misc >> 8)); + + return 0; +} + +static void dw_dp_video_disable(struct dw_dp *dp) +{ + regmap_update_bits(dp->regmap, DW_DP_VSAMPLE_CTRL, VIDEO_STREAM_ENABLE, + FIELD_PREP(VIDEO_STREAM_ENABLE, 0)); +} + +static int dw_dp_video_enable(struct dw_dp *dp) +{ + struct dw_dp_link *link =3D &dp->link; + struct dw_dp_bridge_state *state; + struct drm_display_mode *mode; + u8 color_format, bpc, bpp; + u8 init_threshold, vic; + u32 hstart, hactive, hblank, h_sync_width, h_front_porch; + u32 vstart, vactive, vblank, v_sync_width, v_front_porch; + u32 peak_stream_bandwidth, link_bandwidth; + u32 average_bytes_per_tu, average_bytes_per_tu_frac; + u32 ts, hblank_interval; + u32 value; + int ret; + + state =3D dw_dp_get_bridge_state(dp); + if (!state) + return -EINVAL; + + bpc =3D state->bpc; + bpp =3D state->bpp; + color_format =3D state->color_format; + mode =3D &state->mode; + + vstart =3D mode->vtotal - mode->vsync_start; + hstart =3D mode->htotal - mode->hsync_start; + + ret =3D dw_dp_video_set_pixel_mode(dp); + if (ret) + return ret; + + ret =3D dw_dp_video_set_msa(dp, color_format, bpc, vstart, hstart); + if (ret) + return ret; + + regmap_update_bits(dp->regmap, DW_DP_VSAMPLE_CTRL, VIDEO_MAPPING, + FIELD_PREP(VIDEO_MAPPING, state->video_mapping)); + + /* Configure DW_DP_VINPUT_POLARITY_CTRL register */ + value =3D 0; + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + value |=3D FIELD_PREP(HSYNC_IN_POLARITY, 1); + if (mode->flags & DRM_MODE_FLAG_PVSYNC) + value |=3D FIELD_PREP(VSYNC_IN_POLARITY, 1); + regmap_write(dp->regmap, DW_DP_VINPUT_POLARITY_CTRL, value); + + /* Configure DW_DP_VIDEO_CONFIG1 register */ + hactive =3D mode->hdisplay; + hblank =3D mode->htotal - mode->hdisplay; + value =3D FIELD_PREP(HACTIVE, hactive) | FIELD_PREP(HBLANK, hblank); + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + value |=3D FIELD_PREP(I_P, 1); + vic =3D drm_match_cea_mode(mode); + if (vic =3D=3D 5 || vic =3D=3D 6 || vic =3D=3D 7 || + vic =3D=3D 10 || vic =3D=3D 11 || vic =3D=3D 20 || + vic =3D=3D 21 || vic =3D=3D 22 || vic =3D=3D 39 || + vic =3D=3D 25 || vic =3D=3D 26 || vic =3D=3D 40 || + vic =3D=3D 44 || vic =3D=3D 45 || vic =3D=3D 46 || + vic =3D=3D 50 || vic =3D=3D 51 || vic =3D=3D 54 || + vic =3D=3D 55 || vic =3D=3D 58 || vic =3D=3D 59) + value |=3D R_V_BLANK_IN_OSC; + regmap_write(dp->regmap, DW_DP_VIDEO_CONFIG1, value); + + /* Configure DW_DP_VIDEO_CONFIG2 register */ + vblank =3D mode->vtotal - mode->vdisplay; + vactive =3D mode->vdisplay; + regmap_write(dp->regmap, DW_DP_VIDEO_CONFIG2, + FIELD_PREP(VBLANK, vblank) | FIELD_PREP(VACTIVE, vactive)); + + /* Configure DW_DP_VIDEO_CONFIG3 register */ + h_sync_width =3D mode->hsync_end - mode->hsync_start; + h_front_porch =3D mode->hsync_start - mode->hdisplay; + regmap_write(dp->regmap, DW_DP_VIDEO_CONFIG3, + FIELD_PREP(H_SYNC_WIDTH, h_sync_width) | + FIELD_PREP(H_FRONT_PORCH, h_front_porch)); + + /* Configure DW_DP_VIDEO_CONFIG4 register */ + v_sync_width =3D mode->vsync_end - mode->vsync_start; + v_front_porch =3D mode->vsync_start - mode->vdisplay; + regmap_write(dp->regmap, DW_DP_VIDEO_CONFIG4, + FIELD_PREP(V_SYNC_WIDTH, v_sync_width) | + FIELD_PREP(V_FRONT_PORCH, v_front_porch)); + + /* Configure DW_DP_VIDEO_CONFIG5 register */ + peak_stream_bandwidth =3D mode->clock * bpp / 8; + link_bandwidth =3D (link->rate / 1000) * link->lanes; + ts =3D peak_stream_bandwidth * 64 / link_bandwidth; + average_bytes_per_tu =3D ts / 1000; + average_bytes_per_tu_frac =3D ts / 100 - average_bytes_per_tu * 10; + if (dp->pixel_mode =3D=3D DW_DP_MP_SINGLE_PIXEL) { + if (average_bytes_per_tu < 6) + init_threshold =3D 32; + else if (hblank <=3D 80 && color_format !=3D DRM_COLOR_FORMAT_YCBCR420) + init_threshold =3D 12; + else if (hblank <=3D 40 && color_format =3D=3D DRM_COLOR_FORMAT_YCBCR420) + init_threshold =3D 3; + else + init_threshold =3D 16; + } else { + u32 t1 =3D 0, t2 =3D 0, t3 =3D 0; + + switch (bpc) { + case 6: + t1 =3D (4 * 1000 / 9) * link->lanes; + break; + case 8: + if (color_format =3D=3D DRM_COLOR_FORMAT_YCBCR422) { + t1 =3D (1000 / 2) * link->lanes; + } else { + if (dp->pixel_mode =3D=3D DW_DP_MP_DUAL_PIXEL) + t1 =3D (1000 / 3) * link->lanes; + else + t1 =3D (3000 / 16) * link->lanes; + } + break; + case 10: + if (color_format =3D=3D DRM_COLOR_FORMAT_YCBCR422) + t1 =3D (2000 / 5) * link->lanes; + else + t1 =3D (4000 / 15) * link->lanes; + break; + case 12: + if (color_format =3D=3D DRM_COLOR_FORMAT_YCBCR422) { + if (dp->pixel_mode =3D=3D DW_DP_MP_DUAL_PIXEL) + t1 =3D (1000 / 6) * link->lanes; + else + t1 =3D (1000 / 3) * link->lanes; + } else { + t1 =3D (2000 / 9) * link->lanes; + } + break; + case 16: + if (color_format !=3D DRM_COLOR_FORMAT_YCBCR422 && + dp->pixel_mode =3D=3D DW_DP_MP_DUAL_PIXEL) + t1 =3D (1000 / 6) * link->lanes; + else + t1 =3D (1000 / 4) * link->lanes; + break; + default: + return -EINVAL; + } + + if (color_format =3D=3D DRM_COLOR_FORMAT_YCBCR420) + t2 =3D (link->rate / 4) * 1000 / (mode->clock / 2); + else + t2 =3D (link->rate / 4) * 1000 / mode->clock; + + if (average_bytes_per_tu_frac) + t3 =3D average_bytes_per_tu + 1; + else + t3 =3D average_bytes_per_tu; + init_threshold =3D t1 * t2 * t3 / (1000 * 1000); + if (init_threshold <=3D 16 || average_bytes_per_tu < 10) + init_threshold =3D 40; + } + + regmap_write(dp->regmap, DW_DP_VIDEO_CONFIG5, + FIELD_PREP(INIT_THRESHOLD_HI, init_threshold >> 6) | + FIELD_PREP(AVERAGE_BYTES_PER_TU_FRAC, average_bytes_per_tu_frac) | + FIELD_PREP(INIT_THRESHOLD, init_threshold) | + FIELD_PREP(AVERAGE_BYTES_PER_TU, average_bytes_per_tu)); + + /* Configure DW_DP_VIDEO_HBLANK_INTERVAL register */ + hblank_interval =3D hblank * (link->rate / 4) / mode->clock; + regmap_write(dp->regmap, DW_DP_VIDEO_HBLANK_INTERVAL, + FIELD_PREP(HBLANK_INTERVAL_EN, 1) | + FIELD_PREP(HBLANK_INTERVAL, hblank_interval)); + + /* Video stream enable */ + regmap_update_bits(dp->regmap, DW_DP_VSAMPLE_CTRL, VIDEO_STREAM_ENABLE, + FIELD_PREP(VIDEO_STREAM_ENABLE, 1)); + + if (dw_dp_video_need_vsc_sdp(dp)) + dw_dp_send_vsc_sdp(dp); + + return 0; +} + +static void dw_dp_hpd_init(struct dw_dp *dp) +{ + /* Enable all HPD interrupts */ + regmap_update_bits(dp->regmap, DW_DP_HPD_INTERRUPT_ENABLE, + HPD_UNPLUG_EN | HPD_PLUG_EN | HPD_IRQ_EN, + FIELD_PREP(HPD_UNPLUG_EN, 1) | + FIELD_PREP(HPD_PLUG_EN, 1) | + FIELD_PREP(HPD_IRQ_EN, 1)); + + /* Enable all top-level interrupts */ + regmap_update_bits(dp->regmap, DW_DP_GENERAL_INTERRUPT_ENABLE, + HPD_EVENT_EN, FIELD_PREP(HPD_EVENT_EN, 1)); +} + +static void dw_dp_aux_init(struct dw_dp *dp) +{ + regmap_update_bits(dp->regmap, DW_DP_GENERAL_INTERRUPT_ENABLE, + AUX_REPLY_EVENT_EN, FIELD_PREP(AUX_REPLY_EVENT_EN, 1)); +} + +static void dw_dp_init_hw(struct dw_dp *dp) +{ + regmap_update_bits(dp->regmap, DW_DP_CCTL, DEFAULT_FAST_LINK_TRAIN_EN, + FIELD_PREP(DEFAULT_FAST_LINK_TRAIN_EN, 0)); + + dw_dp_hpd_init(dp); + dw_dp_aux_init(dp); +} + +static int dw_dp_aux_write_data(struct dw_dp *dp, const u8 *buffer, size_t= size) +{ + size_t i, j; + + for (i =3D 0; i < DIV_ROUND_UP(size, 4); i++) { + size_t num =3D min_t(size_t, size - i * 4, 4); + u32 value =3D 0; + + for (j =3D 0; j < num; j++) + value |=3D buffer[i * 4 + j] << (j * 8); + + regmap_write(dp->regmap, DW_DP_AUX_DATA0 + i * 4, value); + } + + return size; +} + +static int dw_dp_aux_read_data(struct dw_dp *dp, u8 *buffer, size_t size) +{ + size_t i, j; + + for (i =3D 0; i < DIV_ROUND_UP(size, 4); i++) { + size_t num =3D min_t(size_t, size - i * 4, 4); + u32 value; + + regmap_read(dp->regmap, DW_DP_AUX_DATA0 + i * 4, &value); + + for (j =3D 0; j < num; j++) + buffer[i * 4 + j] =3D value >> (j * 8); + } + + return size; +} + +static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct dw_dp *dp =3D container_of(aux, struct dw_dp, aux); + unsigned long timeout =3D msecs_to_jiffies(10); + u32 status, value; + ssize_t ret =3D 0; + + if (WARN_ON(msg->size > 16)) + return -E2BIG; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret =3D dw_dp_aux_write_data(dp, msg->buffer, msg->size); + if (ret < 0) + return ret; + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + break; + default: + return -EINVAL; + } + + if (msg->size > 0) + value =3D FIELD_PREP(AUX_LEN_REQ, msg->size - 1); + else + value =3D FIELD_PREP(I2C_ADDR_ONLY, 1); + value |=3D FIELD_PREP(AUX_CMD_TYPE, msg->request); + value |=3D FIELD_PREP(AUX_ADDR, msg->address); + regmap_write(dp->regmap, DW_DP_AUX_CMD, value); + + status =3D wait_for_completion_timeout(&dp->complete, timeout); + if (!status) { + dev_err(dp->dev, "timeout waiting for AUX reply\n"); + return -ETIMEDOUT; + } + + regmap_read(dp->regmap, DW_DP_AUX_STATUS, &value); + if (value & AUX_TIMEOUT) + return -ETIMEDOUT; + + msg->reply =3D FIELD_GET(AUX_STATUS, value); + + if (msg->size > 0 && msg->reply =3D=3D DP_AUX_NATIVE_REPLY_ACK) { + if (msg->request & DP_AUX_I2C_READ) { + size_t count =3D FIELD_GET(AUX_BYTES_READ, value) - 1; + + if (count !=3D msg->size) + return -EBUSY; + + ret =3D dw_dp_aux_read_data(dp, msg->buffer, count); + if (ret < 0) + return ret; + } + } + + return ret; +} + +/* + * Limits for the video timing for DP: + * 1. the hfp should be 2 pixels aligned; + * 2. the minimum hsync should be 9 pixel; + * 3. the minimum hbp should be 16 pixel; + */ +static int dw_dp_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_display_mode *adjusted_mode =3D &crtc_state->adjusted_mode; + struct dw_dp *dp =3D bridge_to_dp(bridge); + struct dw_dp_bridge_state *state; + const struct dw_dp_output_format *fmt; + struct drm_display_mode *mode; + int min_hbp =3D 16; + int min_hsync =3D 9; + + state =3D to_dw_dp_bridge_state(bridge_state); + mode =3D &state->mode; + + fmt =3D dw_dp_get_output_format(bridge_state->output_bus_cfg.format); + if (!fmt) + return -EINVAL; + + state->video_mapping =3D fmt->video_mapping; + state->color_format =3D fmt->color_format; + state->bpc =3D fmt->bpc; + state->bpp =3D fmt->bpp; + + if ((adjusted_mode->hsync_start - adjusted_mode->hdisplay) & 0x1) { + adjusted_mode->hsync_start +=3D 1; + dev_warn(dp->dev, "hfp is not 2 pixeel aligned, fixup to aligned hfp\n"); + } + + if (adjusted_mode->hsync_end - adjusted_mode->hsync_start < min_hsync) { + adjusted_mode->hsync_end =3D adjusted_mode->hsync_start + min_hsync; + dev_warn(dp->dev, "hsync is too narrow, fixup to min hsync:%d\n", min_hs= ync); + } + + if (adjusted_mode->htotal - adjusted_mode->hsync_end < min_hbp) { + adjusted_mode->htotal =3D adjusted_mode->hsync_end + min_hbp; + dev_warn(dp->dev, "hbp is too narrow, fixup to min hbp:%d\n", min_hbp); + } + + drm_mode_copy(mode, adjusted_mode); + + return 0; +} + +static enum drm_mode_status dw_dp_bridge_mode_valid(struct drm_bridge *bri= dge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct dw_dp *dp =3D bridge_to_dp(bridge); + struct dw_dp_link *link =3D &dp->link; + u32 min_bpp; + + if (info->color_formats & DRM_COLOR_FORMAT_YCBCR420 && + link->vsc_sdp_supported && + (drm_mode_is_420_only(info, mode) || drm_mode_is_420_also(info, mode)= )) + min_bpp =3D 12; + else if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) + min_bpp =3D 16; + else if (info->color_formats & DRM_COLOR_FORMAT_RGB444) + min_bpp =3D 18; + else + min_bpp =3D 24; + + if (!link->vsc_sdp_supported && + drm_mode_is_420_only(info, mode)) + return MODE_NO_420; + + if (!dw_dp_bandwidth_ok(dp, mode, min_bpp, link->lanes, link->rate)) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static bool dw_dp_needs_link_retrain(struct dw_dp *dp) +{ + struct dw_dp_link *link =3D &dp->link; + u8 link_status[DP_LINK_STATUS_SIZE]; + + if (!dw_dp_link_train_valid(&link->train)) + return false; + + if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) < 0) + return false; + + /* Retrain if Channel EQ or CR not ok */ + return !drm_dp_channel_eq_ok(link_status, dp->link.lanes); +} + +static void dw_dp_link_disable(struct dw_dp *dp) +{ + struct dw_dp_link *link =3D &dp->link; + + if (dw_dp_hpd_detect(dp)) + drm_dp_link_power_down(&dp->aux, dp->link.revision); + + dw_dp_phy_xmit_enable(dp, 0); + + phy_power_off(dp->phy); + + link->train.clock_recovered =3D false; + link->train.channel_equalized =3D false; +} + +static int dw_dp_link_enable(struct dw_dp *dp) +{ + int ret; + + ret =3D phy_power_on(dp->phy); + if (ret) + return ret; + + ret =3D drm_dp_link_power_up(&dp->aux, dp->link.revision); + if (ret < 0) + return ret; + + ret =3D dw_dp_link_train(dp); + + return ret; +} + +static void dw_dp_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) +{ + struct dw_dp *dp =3D bridge_to_dp(bridge); + struct drm_connector *connector; + struct drm_connector_state *conn_state; + int ret; + + connector =3D drm_atomic_get_new_connector_for_encoder(state, bridge->enc= oder); + if (!connector) { + dev_err(dp->dev, "failed to get connector\n"); + return; + } + + conn_state =3D drm_atomic_get_new_connector_state(state, connector); + if (!conn_state) { + dev_err(dp->dev, "failed to get connector state\n"); + return; + } + + set_bit(0, dp->sdp_reg_bank); + + ret =3D dw_dp_link_enable(dp); + if (ret < 0) { + dev_err(dp->dev, "failed to enable link: %d\n", ret); + return; + } + + ret =3D dw_dp_video_enable(dp); + if (ret < 0) { + dev_err(dp->dev, "failed to enable video: %d\n", ret); + return; + } +} + +static void dw_dp_reset(struct dw_dp *dp) +{ + int val; + + disable_irq(dp->irq); + regmap_update_bits(dp->regmap, DW_DP_SOFT_RESET_CTRL, CONTROLLER_RESET, + FIELD_PREP(CONTROLLER_RESET, 1)); + usleep_range(10, 20); + regmap_update_bits(dp->regmap, DW_DP_SOFT_RESET_CTRL, CONTROLLER_RESET, + FIELD_PREP(CONTROLLER_RESET, 0)); + + dw_dp_init_hw(dp); + regmap_read_poll_timeout(dp->regmap, DW_DP_HPD_STATUS, val, + FIELD_GET(HPD_HOT_PLUG, val), 200, 200000); + regmap_write(dp->regmap, DW_DP_HPD_STATUS, HPD_HOT_PLUG); + enable_irq(dp->irq); +} + +static void dw_dp_bridge_atomic_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state) +{ + struct dw_dp *dp =3D bridge_to_dp(bridge); + + dw_dp_video_disable(dp); + dw_dp_link_disable(dp); + bitmap_zero(dp->sdp_reg_bank, SDP_REG_BANK_SIZE); + dw_dp_reset(dp); +} + +static bool dw_dp_hpd_detect_link(struct dw_dp *dp, struct drm_connector *= connector) +{ + int ret; + + ret =3D phy_power_on(dp->phy); + if (ret < 0) + return false; + ret =3D dw_dp_link_parse(dp, connector); + phy_power_off(dp->phy); + + return !ret; +} + +static enum drm_connector_status dw_dp_bridge_detect(struct drm_bridge *br= idge, + struct drm_connector *connector) +{ + struct dw_dp *dp =3D bridge_to_dp(bridge); + + if (!dw_dp_hpd_detect(dp)) + return connector_status_disconnected; + + if (!dw_dp_hpd_detect_link(dp, connector)) + return connector_status_disconnected; + + return connector_status_connected; +} + +static const struct drm_edid *dw_dp_bridge_edid_read(struct drm_bridge *br= idge, + struct drm_connector *connector) +{ + struct dw_dp *dp =3D bridge_to_dp(bridge); + const struct drm_edid *edid; + int ret; + + ret =3D phy_power_on(dp->phy); + if (ret) + return NULL; + + edid =3D drm_edid_read_ddc(connector, &dp->aux.ddc); + + phy_power_off(dp->phy); + + return edid; +} + +static u32 *dw_dp_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bri= dge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + unsigned int *num_output_fmts) +{ + struct dw_dp *dp =3D bridge_to_dp(bridge); + struct dw_dp_link *link =3D &dp->link; + struct drm_display_info *di =3D &conn_state->connector->display_info; + struct drm_display_mode mode =3D crtc_state->mode; + const struct dw_dp_output_format *fmt; + u32 i, j =3D 0; + u32 *output_fmts; + + *num_output_fmts =3D 0; + + output_fmts =3D kcalloc(ARRAY_SIZE(dw_dp_output_formats), sizeof(*output_= fmts), GFP_KERNEL); + if (!output_fmts) + return NULL; + + for (i =3D 0; i < ARRAY_SIZE(dw_dp_output_formats); i++) { + fmt =3D &dw_dp_output_formats[i]; + + if (fmt->bpc > conn_state->max_bpc) + continue; + + if (!(fmt->color_format & di->color_formats)) + continue; + + if (fmt->color_format =3D=3D DRM_COLOR_FORMAT_YCBCR420 && + !link->vsc_sdp_supported) + continue; + + if (fmt->color_format !=3D DRM_COLOR_FORMAT_YCBCR420 && + drm_mode_is_420_only(di, &mode)) + continue; + + if (!dw_dp_bandwidth_ok(dp, &mode, fmt->bpp, link->lanes, link->rate)) + continue; + + output_fmts[j++] =3D fmt->bus_format; + } + + *num_output_fmts =3D j; + + return output_fmts; +} + +static struct drm_bridge_state *dw_dp_bridge_atomic_duplicate_state(struct= drm_bridge *bridge) +{ + struct dw_dp_bridge_state *state; + + state =3D kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_bridge_duplicate_state(bridge, &state->base); + + return &state->base; +} + +static const struct drm_bridge_funcs dw_dp_bridge_funcs =3D { + .atomic_duplicate_state =3D dw_dp_bridge_atomic_duplicate_state, + .atomic_destroy_state =3D drm_atomic_helper_bridge_destroy_state, + .atomic_reset =3D drm_atomic_helper_bridge_reset, + .atomic_get_input_bus_fmts =3D drm_atomic_helper_bridge_propagate_bus_fmt, + .atomic_get_output_bus_fmts =3D dw_dp_bridge_atomic_get_output_bus_fmts, + .atomic_check =3D dw_dp_bridge_atomic_check, + .mode_valid =3D dw_dp_bridge_mode_valid, + .atomic_enable =3D dw_dp_bridge_atomic_enable, + .atomic_disable =3D dw_dp_bridge_atomic_disable, + .detect =3D dw_dp_bridge_detect, + .edid_read =3D dw_dp_bridge_edid_read, +}; + +static int dw_dp_link_retrain(struct dw_dp *dp) +{ + struct drm_device *dev =3D dp->bridge.dev; + struct drm_modeset_acquire_ctx ctx; + int ret; + + if (!dw_dp_needs_link_retrain(dp)) + return 0; + + dev_dbg(dp->dev, "Retraining link\n"); + + drm_modeset_acquire_init(&ctx, 0); + for (;;) { + ret =3D drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx); + if (ret !=3D -EDEADLK) + break; + + drm_modeset_backoff(&ctx); + } + + if (!ret) + ret =3D dw_dp_link_train(dp); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; +} + +static void dw_dp_hpd_work(struct work_struct *work) +{ + struct dw_dp *dp =3D container_of(work, struct dw_dp, hpd_work); + bool long_hpd; + int ret; + + mutex_lock(&dp->irq_lock); + long_hpd =3D dp->hotplug.long_hpd; + mutex_unlock(&dp->irq_lock); + + dev_dbg(dp->dev, "[drm] Get hpd irq - %s\n", long_hpd ? "long" : "short"); + + if (!long_hpd) { + if (dw_dp_needs_link_retrain(dp)) { + ret =3D dw_dp_link_retrain(dp); + if (ret) + dev_warn(dp->dev, "Retrain link failed\n"); + } + } else { + drm_helper_hpd_irq_event(dp->bridge.dev); + } +} + +static void dw_dp_handle_hpd_event(struct dw_dp *dp) +{ + u32 value; + + mutex_lock(&dp->irq_lock); + regmap_read(dp->regmap, DW_DP_HPD_STATUS, &value); + + if (value & HPD_IRQ) { + dev_dbg(dp->dev, "IRQ from the HPD\n"); + dp->hotplug.long_hpd =3D false; + regmap_write(dp->regmap, DW_DP_HPD_STATUS, HPD_IRQ); + } + + if (value & HPD_HOT_PLUG) { + dev_dbg(dp->dev, "Hot plug detected\n"); + dp->hotplug.long_hpd =3D true; + regmap_write(dp->regmap, DW_DP_HPD_STATUS, HPD_HOT_PLUG); + } + + if (value & HPD_HOT_UNPLUG) { + dev_dbg(dp->dev, "Unplug detected\n"); + dp->hotplug.long_hpd =3D true; + regmap_write(dp->regmap, DW_DP_HPD_STATUS, HPD_HOT_UNPLUG); + } + mutex_unlock(&dp->irq_lock); + + schedule_work(&dp->hpd_work); +} + +static irqreturn_t dw_dp_irq(int irq, void *data) +{ + struct dw_dp *dp =3D data; + u32 value; + + regmap_read(dp->regmap, DW_DP_GENERAL_INTERRUPT, &value); + if (!value) + return IRQ_NONE; + + if (value & HPD_EVENT) + dw_dp_handle_hpd_event(dp); + + if (value & AUX_REPLY_EVENT) { + regmap_write(dp->regmap, DW_DP_GENERAL_INTERRUPT, AUX_REPLY_EVENT); + complete(&dp->complete); + } + + return IRQ_HANDLED; +} + +static const struct regmap_range dw_dp_readable_ranges[] =3D { + regmap_reg_range(DW_DP_VERSION_NUMBER, DW_DP_ID), + regmap_reg_range(DW_DP_CONFIG_REG1, DW_DP_CONFIG_REG3), + regmap_reg_range(DW_DP_CCTL, DW_DP_SOFT_RESET_CTRL), + regmap_reg_range(DW_DP_VSAMPLE_CTRL, DW_DP_VIDEO_HBLANK_INTERVAL), + regmap_reg_range(DW_DP_AUD_CONFIG1, DW_DP_AUD_CONFIG1), + regmap_reg_range(DW_DP_SDP_VERTICAL_CTRL, DW_DP_SDP_STATUS_EN), + regmap_reg_range(DW_DP_PHYIF_CTRL, DW_DP_PHYIF_PWRDOWN_CTRL), + regmap_reg_range(DW_DP_AUX_CMD, DW_DP_AUX_DATA3), + regmap_reg_range(DW_DP_GENERAL_INTERRUPT, DW_DP_HPD_INTERRUPT_ENABLE), +}; + +static const struct regmap_access_table dw_dp_readable_table =3D { + .yes_ranges =3D dw_dp_readable_ranges, + .n_yes_ranges =3D ARRAY_SIZE(dw_dp_readable_ranges), +}; + +static const struct regmap_config dw_dp_regmap_config =3D { + .reg_bits =3D 32, + .reg_stride =3D 4, + .val_bits =3D 32, + .fast_io =3D true, + .max_register =3D DW_DP_MAX_REGISTER, + .rd_table =3D &dw_dp_readable_table, +}; + +static void dw_dp_phy_exit(void *data) +{ + struct dw_dp *dp =3D data; + + phy_exit(dp->phy); +} + +struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder, + const struct dw_dp_plat_data *plat_data) +{ + struct platform_device *pdev =3D to_platform_device(dev); + struct dw_dp *dp; + struct drm_bridge *bridge; + void __iomem *res; + int ret; + + dp =3D devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); + if (!dp) + return ERR_PTR(-ENOMEM); + + dp =3D devm_drm_bridge_alloc(dev, struct dw_dp, bridge, &dw_dp_bridge_fun= cs); + if (IS_ERR(dp)) + return ERR_CAST(dp); + + dp->dev =3D dev; + dp->pixel_mode =3D DW_DP_MP_QUAD_PIXEL; + + dp->plat_data.max_link_rate =3D plat_data->max_link_rate; + bridge =3D &dp->bridge; + mutex_init(&dp->irq_lock); + INIT_WORK(&dp->hpd_work, dw_dp_hpd_work); + init_completion(&dp->complete); + + res =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(res)) + return ERR_CAST(res); + + dp->regmap =3D devm_regmap_init_mmio(dev, res, &dw_dp_regmap_config); + if (IS_ERR(dp->regmap)) { + dev_err_probe(dev, PTR_ERR(dp->regmap), "failed to create regmap\n"); + return ERR_CAST(dp->regmap); + } + + dp->phy =3D devm_of_phy_get(dev, dev->of_node, NULL); + if (IS_ERR(dp->phy)) { + dev_err_probe(dev, PTR_ERR(dp->phy), "failed to get phy\n"); + return ERR_CAST(dp->phy); + } + + dp->apb_clk =3D devm_clk_get_enabled(dev, "apb"); + if (IS_ERR(dp->apb_clk)) { + dev_err_probe(dev, PTR_ERR(dp->apb_clk), "failed to get apb clock\n"); + return ERR_CAST(dp->apb_clk); + } + + dp->aux_clk =3D devm_clk_get_enabled(dev, "aux"); + if (IS_ERR(dp->aux_clk)) { + dev_err_probe(dev, PTR_ERR(dp->aux_clk), "failed to get aux clock\n"); + return ERR_CAST(dp->aux_clk); + } + + dp->i2s_clk =3D devm_clk_get(dev, "i2s"); + if (IS_ERR(dp->i2s_clk)) { + dev_err_probe(dev, PTR_ERR(dp->i2s_clk), "failed to get i2s clock\n"); + return ERR_CAST(dp->i2s_clk); + } + + dp->spdif_clk =3D devm_clk_get(dev, "spdif"); + if (IS_ERR(dp->spdif_clk)) { + dev_err_probe(dev, PTR_ERR(dp->spdif_clk), "failed to get spdif clock\n"= ); + return ERR_CAST(dp->spdif_clk); + } + + dp->hdcp_clk =3D devm_clk_get(dev, "hdcp"); + if (IS_ERR(dp->hdcp_clk)) { + dev_err_probe(dev, PTR_ERR(dp->hdcp_clk), "failed to get hdcp clock\n"); + return ERR_CAST(dp->hdcp_clk); + } + + dp->rstc =3D devm_reset_control_get(dev, NULL); + if (IS_ERR(dp->rstc)) { + dev_err_probe(dev, PTR_ERR(dp->rstc), "failed to get reset control\n"); + return ERR_CAST(dp->rstc); + } + + bridge->of_node =3D dev->of_node; + bridge->ops =3D DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP= _HPD; + bridge->type =3D DRM_MODE_CONNECTOR_DisplayPort; + bridge->ycbcr_420_allowed =3D true; + + dp->aux.dev =3D dev; + dp->aux.drm_dev =3D encoder->dev; + dp->aux.name =3D dev_name(dev); + dp->aux.transfer =3D dw_dp_aux_transfer; + ret =3D drm_dp_aux_register(&dp->aux); + if (ret) { + dev_err_probe(dev, ret, "Aux register failed\n"); + return ERR_PTR(ret); + } + + ret =3D drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CON= NECTOR); + if (ret) + dev_err_probe(dev, ret, "Failed to attach bridge\n"); + + dw_dp_init_hw(dp); + + ret =3D phy_init(dp->phy); + if (ret) { + dev_err_probe(dev, ret, "phy init failed\n"); + return ERR_PTR(ret); + } + + ret =3D devm_add_action_or_reset(dev, dw_dp_phy_exit, dp); + if (ret) + return ERR_PTR(ret); + + dp->irq =3D platform_get_irq(pdev, 0); + if (dp->irq < 0) + return ERR_PTR(ret); + + ret =3D devm_request_threaded_irq(dev, dp->irq, NULL, dw_dp_irq, + IRQF_ONESHOT, dev_name(dev), dp); + if (ret) { + dev_err_probe(dev, ret, "failed to request irq\n"); + return ERR_PTR(ret); + } + + return dp; +} +EXPORT_SYMBOL_GPL(dw_dp_bind); + +MODULE_AUTHOR("Andy Yan "); +MODULE_DESCRIPTION("DW DP Core Library"); +MODULE_LICENSE("GPL"); diff --git a/include/drm/bridge/dw_dp.h b/include/drm/bridge/dw_dp.h new file mode 100644 index 0000000000000..d05df49fd8846 --- /dev/null +++ b/include/drm/bridge/dw_dp.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + */ + +#ifndef __DW_DP__ +#define __DW_DP__ + +#include + +struct drm_encoder; +struct dw_dp; + +struct dw_dp_plat_data { + u32 max_link_rate; +}; + +struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder, + const struct dw_dp_plat_data *plat_data); +#endif /* __DW_DP__ */ --=20 2.43.0 From nobody Sat Oct 4 00:32:10 2025 Received: from m16.mail.163.com (m16.mail.163.com [117.135.210.5]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 04BFF2E54CC; Fri, 22 Aug 2025 06:41:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=117.135.210.5 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844865; cv=none; b=Jd7WMgT8FGM22eTmIZO5pvnzvhGCoe2Q6i19BAvIriXOehSJ947wuUnrmlcy8pNT+Mj9S3nt3xnH8zPHy+obAbfCPGn9LlgdA3s+qazpA1NgT0G0gKeywD9QC7lA2tjZwMJG3MmyqVWoYLT6kII5/3+IYYZmS+i4I0uXhfE0tLM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844865; c=relaxed/simple; bh=3BZnGpfGS80rjkt03ILe7U1ImBSuSfEvMCCNC6ZTq40=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UmJnoAwy2SesW7G4sQZdESOP+fAEEsgxALAOS8Mh1IFoC+o1srEPxBfW/SJ+4ZME0tnK6vO02+ki0+xrt5ww2wGIAaBxaq3iYqSgbXiuGv5EJGB9WSX0CY1HFHGeqLO45K8lLbZr5lLq5Fm2h6RcpfXeQWzURPVTSiTENRe8T8k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=RDWaAsFN; arc=none smtp.client-ip=117.135.210.5 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="RDWaAsFN" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=Fu 2I9I0K62mO9f2lY4d01rL8jispecH5XRwzqIEZ658=; b=RDWaAsFNfL5tLve9J7 23n6lUtUjWvE76duPN5kWnO/bLST8/qwd/AFUGzLEOLkBQZuQGEMk6TX1FywectU 4f5IGgWSltBAzJhW8+4kKaE91wglQPSRXXTLzOmLSssr1siTr30r7eP+24HeeBW4 5MsV3hm5dSslwHCmC2obvFrxo= Received: from ProDesk.. (unknown []) by gzsmtp3 (Coremail) with SMTP id PigvCgAn9_zCEKhoYtibAA--.23257S5; Fri, 22 Aug 2025 14:40:19 +0800 (CST) From: Andy Yan To: dmitry.baryshkov@oss.qualcomm.com, heiko@sntech.de Cc: hjc@rock-chips.com, mripard@kernel.org, naoki@radxa.com, stephen@radxa.com, cristian.ciocaltea@collabora.com, neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, yubing.zhang@rock-chips.com, krzk+dt@kernel.org, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, robh@kernel.org, sebastian.reichel@collabora.com, Andy Yan , Dmitry Baryshkov , Nicolas Frattaroli Subject: [PATCH v7 03/10] drm/rockchip: Add RK3588 DPTX output support Date: Fri, 22 Aug 2025 14:39:47 +0800 Message-ID: <20250822063959.692098-4-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822063959.692098-1-andyshrk@163.com> References: <20250822063959.692098-1-andyshrk@163.com> 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: PigvCgAn9_zCEKhoYtibAA--.23257S5 X-Coremail-Antispam: 1Uf129KBjvJXoW3XrWxJF18Kw4ftr18Kw17Jrb_yoWfCFyrpa 1DAFWYyrW8Gr4Yq3s7AF4kCFs0yanFyayxXrZ7C3Wa9a4IkryDG3sxWr1DAr9xJFW7uF13 CwsrJ3yUZF47ur7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jPtxhUUUUU= X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/xtbB0gqxXmioDHlwywAAs5 Content-Type: text/plain; charset="utf-8" From: Andy Yan Add driver extension for Synopsys DesignWare DPTX IP used on Rockchip RK3588 SoC. Signed-off-by: Andy Yan Acked-by: Dmitry Baryshkov Tested-by: Nicolas Frattaroli Reviewed-by: Heiko Stuebner --- (no changes since v4) Changes in v4: - Drop unused function - Add platform_set_drvdata Changes in v2: - no include uapi path - switch to drmm_encoder_init drivers/gpu/drm/rockchip/Kconfig | 9 ++ drivers/gpu/drm/rockchip/Makefile | 1 + drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 150 ++++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 1 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 + 5 files changed, 162 insertions(+) create mode 100644 drivers/gpu/drm/rockchip/dw_dp-rockchip.c diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kc= onfig index ab525668939a7..616c0bc1ccee0 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -10,6 +10,7 @@ config DRM_ROCKCHIP select VIDEOMODE_HELPERS select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP select DRM_DISPLAY_DP_AUX_BUS if ROCKCHIP_ANALOGIX_DP + select DRM_DW_DP if ROCKCHIP_DW_DP select DRM_DW_HDMI if ROCKCHIP_DW_HDMI select DRM_DW_HDMI_QP if ROCKCHIP_DW_HDMI_QP select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI @@ -60,6 +61,14 @@ config ROCKCHIP_CDN_DP RK3399 based SoC, you should select this option. =20 +config ROCKCHIP_DW_DP + bool "Rockchip specific extensions for Synopsys DW DP" + help + This selects support for Rockchip SoC specific extensions + to enable Synopsys DesignWare Cores based DisplayPort transmit + controller support on Rockchip SoC, If you want to enable DP on + rk3588 based SoC, you should select this option. + config ROCKCHIP_DW_HDMI bool "Rockchip specific extensions for Synopsys DW HDMI" help diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/M= akefile index 2b867cebbc121..097f062399c7a 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -14,6 +14,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) +=3D dw_hdmi-rockc= hip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI_QP) +=3D dw_hdmi_qp-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) +=3D dw-mipi-dsi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI2) +=3D dw-mipi-dsi2-rockchip.o +rockchipdrm-$(CONFIG_ROCKCHIP_DW_DP) +=3D dw_dp-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) +=3D inno_hdmi.o rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) +=3D rockchip_lvds.o rockchipdrm-$(CONFIG_ROCKCHIP_RGB) +=3D rockchip_rgb.o diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/ro= ckchip/dw_dp-rockchip.c new file mode 100644 index 0000000000000..25ab4e46301e8 --- /dev/null +++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Rockchip Electronics Co., Ltd. + * + * Author: Zhang Yubing + * Author: Andy Yan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "rockchip_drm_drv.h" +#include "rockchip_drm_vop.h" + +struct rockchip_dw_dp { + struct dw_dp *base; + struct device *dev; + struct rockchip_encoder encoder; +}; + +static int dw_dp_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct rockchip_crtc_state *s =3D to_rockchip_crtc_state(crtc_state); + struct drm_atomic_state *state =3D conn_state->state; + struct drm_display_info *di =3D &conn_state->connector->display_info; + struct drm_bridge *bridge =3D drm_bridge_chain_get_first_bridge(encoder); + struct drm_bridge_state *bridge_state =3D drm_atomic_get_new_bridge_state= (state, bridge); + u32 bus_format =3D bridge_state->input_bus_cfg.format; + + switch (bus_format) { + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + s->output_mode =3D ROCKCHIP_OUT_MODE_YUV420; + break; + case MEDIA_BUS_FMT_YUYV10_1X20: + case MEDIA_BUS_FMT_YUYV8_1X16: + s->output_mode =3D ROCKCHIP_OUT_MODE_S888_DUMMY; + break; + case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_YUV8_1X24: + default: + s->output_mode =3D ROCKCHIP_OUT_MODE_AAAA; + break; + } + + s->output_type =3D DRM_MODE_CONNECTOR_DisplayPort; + s->bus_format =3D bus_format; + s->bus_flags =3D di->bus_flags; + s->color_space =3D V4L2_COLORSPACE_DEFAULT; + + return 0; +} + +static const struct drm_encoder_helper_funcs dw_dp_encoder_helper_funcs = =3D { + .atomic_check =3D dw_dp_encoder_atomic_check, +}; + +static int dw_dp_rockchip_bind(struct device *dev, struct device *master, = void *data) +{ + struct platform_device *pdev =3D to_platform_device(dev); + struct dw_dp_plat_data plat_data; + struct drm_device *drm_dev =3D data; + struct rockchip_dw_dp *dp; + struct drm_encoder *encoder; + struct drm_connector *connector; + int ret; + + dp =3D devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); + if (!dp) + return -ENOMEM; + + dp->dev =3D dev; + platform_set_drvdata(pdev, dp); + + plat_data.max_link_rate =3D 810000; + encoder =3D &dp->encoder.encoder; + encoder->possible_crtcs =3D drm_of_find_possible_crtcs(drm_dev, dev->of_n= ode); + rockchip_drm_encoder_set_crtc_endpoint_id(&dp->encoder, dev->of_node, 0, = 0); + + ret =3D drmm_encoder_init(drm_dev, encoder, NULL, DRM_MODE_ENCODER_TMDS, = NULL); + if (ret) + return ret; + drm_encoder_helper_add(encoder, &dw_dp_encoder_helper_funcs); + + dp->base =3D dw_dp_bind(dev, encoder, &plat_data); + if (IS_ERR(dp->base)) { + ret =3D PTR_ERR(dp->base); + return ret; + } + + connector =3D drm_bridge_connector_init(drm_dev, encoder); + if (IS_ERR(connector)) { + ret =3D PTR_ERR(connector); + return dev_err_probe(dev, ret, "Failed to init bridge connector"); + } + + drm_connector_attach_encoder(connector, encoder); + + return 0; +} + +static const struct component_ops dw_dp_rockchip_component_ops =3D { + .bind =3D dw_dp_rockchip_bind, +}; + +static int dw_dp_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + + return component_add(dev, &dw_dp_rockchip_component_ops); +} + +static void dw_dp_remove(struct platform_device *pdev) +{ + struct rockchip_dw_dp *dp =3D platform_get_drvdata(pdev); + + component_del(dp->dev, &dw_dp_rockchip_component_ops); +} + +static const struct of_device_id dw_dp_of_match[] =3D { + { .compatible =3D "rockchip,rk3588-dp", }, + {} +}; +MODULE_DEVICE_TABLE(of, dw_dp_of_match); + +struct platform_driver dw_dp_driver =3D { + .probe =3D dw_dp_probe, + .remove =3D dw_dp_remove, + .driver =3D { + .name =3D "dw-dp", + .of_match_table =3D dw_dp_of_match, + }, +}; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/= rockchip/rockchip_drm_drv.c index ed88788e04dd2..687bb7b252e8e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -531,6 +531,7 @@ static int __init rockchip_drm_init(void) ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver, CONFIG_ROCKCHIP_ANALOGIX_DP); ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); + ADD_ROCKCHIP_SUB_DRIVER(dw_dp_driver, CONFIG_ROCKCHIP_DW_DP); ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver, CONFIG_ROCKCHIP_DW_HDMI); ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_qp_rockchip_pltfm_driver, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/= rockchip/rockchip_drm_drv.h index c183e82a42a51..2e86ad00979c4 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -87,6 +87,7 @@ int rockchip_drm_encoder_set_crtc_endpoint_id(struct rock= chip_encoder *rencoder, struct device_node *np, int port, int reg); int rockchip_drm_endpoint_is_subdriver(struct device_node *ep); extern struct platform_driver cdn_dp_driver; +extern struct platform_driver dw_dp_driver; extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; extern struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver; extern struct platform_driver dw_mipi_dsi_rockchip_driver; --=20 2.43.0 From nobody Sat Oct 4 00:32:10 2025 Received: from m16.mail.163.com (m16.mail.163.com [117.135.210.2]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 09CC927A10F; Fri, 22 Aug 2025 06:40:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=117.135.210.2 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844859; cv=none; b=PyDkFEoAwBZt7EDNTRyTPassF6xHMKGB/IzSTGezKm7QRQq91qP1KOT+vvogUwRxElhIJjLggP6XcvEHshaY4yh4MFo4rlGFj0twGfSGYjcz+CqW1taFzwD4Wme8GmBkfZSMwajHYoqYE9Bomn2QebLmQWKds/omY5P092l8JzU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844859; c=relaxed/simple; bh=cFeFPw2AOfUV+rJZRz8G8+bgedVftP3bXl+eO4/1QXk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VDWegTan7/Pt4+foBNpraht+lfDjRtMgp7eyDekIOu3RLIbdhQplzpgsWPOYwfl1ub2eWgBt3fk5Tzt7bjMMYo+RAcPv+uUpGkaYpjHrGRq5HfbPqdxE2BYVaRqm2p9VLjK4P8frURYoG3VZXkk+VadssP+nUCqOet7xndzFg2g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=EIoPWMMv; arc=none smtp.client-ip=117.135.210.2 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="EIoPWMMv" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=tP y4GqAOn9NjYCgd7E8mSk+A/Y65Vwnn+Qoudmsz9DA=; b=EIoPWMMvjCX2csB6LR DakDX+jLnKlOqmFiczf4GNsbb7WBHVSO0H7ETd0JRr2r6Uc1dJ2537iYMJSbbEIY N01aIcttvLsyAsPbmgVePsoBhlkh8jIsXYXDpsav9RQbjdaPusV8dKTXBXVFwAck cFdZOtB2ZDdsKiLUZF2JDjKrk= Received: from ProDesk.. (unknown []) by gzsmtp3 (Coremail) with SMTP id PigvCgAn9_zCEKhoYtibAA--.23257S6; Fri, 22 Aug 2025 14:40:20 +0800 (CST) From: Andy Yan To: dmitry.baryshkov@oss.qualcomm.com, heiko@sntech.de Cc: hjc@rock-chips.com, mripard@kernel.org, naoki@radxa.com, stephen@radxa.com, cristian.ciocaltea@collabora.com, neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, yubing.zhang@rock-chips.com, krzk+dt@kernel.org, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, robh@kernel.org, sebastian.reichel@collabora.com, Andy Yan Subject: [PATCH v7 04/10] MAINTAINERS: Add entry for DW DPTX Controller bridge Date: Fri, 22 Aug 2025 14:39:48 +0800 Message-ID: <20250822063959.692098-5-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822063959.692098-1-andyshrk@163.com> References: <20250822063959.692098-1-andyshrk@163.com> 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: PigvCgAn9_zCEKhoYtibAA--.23257S6 X-Coremail-Antispam: 1Uf129KBjvdXoWrZrW5JF4DZry8Gw43CFWktFb_yoWkCrc_C3 WxZ3yxXr4rGF90krZ7Aan3Ga4Sya1IgFsxu3Wkt392yasYyrWUtFWvkryxGw15CF1fCFWD ua4fXFyakrnxujkaLaAFLSUrUUUUjb8apTn2vfkv8UJUUUU8Yxn0WfASr-VFAUDa7-sFnT 9fnUUvcSsGvfC2KfnxnUUI43ZEXa7IU8N_-PUUUUU== X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/xtbB0gqxXmioDHlwywABs4 Content-Type: text/plain; charset="utf-8" From: Andy Yan Add an entry for the DW DPTX Controller bridge driver. Signed-off-by: Andy Yan Reviewed-by: Dmitry Baryshkov Reviewed-by: Heiko Stuebner --- (no changes since v5) Changes in v5: - First included in this version. MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index cfa28b3470ab6..0ae7d13c2b3c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7999,6 +7999,14 @@ S: Maintained F: Documentation/devicetree/bindings/display/panel/synaptics,r63353.yaml F: drivers/gpu/drm/panel/panel-synaptics-r63353.c =20 +DRM DRIVER FOR SYNOPSYS DESIGNWARE DISPLAYPORT BRIDGE +M: Andy Yan +S: Maintained +T: git https://gitlab.freedesktop.org/drm/misc/kernel.git +F: Documentation/devicetree/bindings/display/rockchip/rockchip,dw-dp.yaml +F: drivers/gpu/drm/bridge/synopsys/dw-dp.c +F: include/drm/bridge/dw_dp.h + DRM DRIVER FOR TI DLPC3433 MIPI DSI TO DMD BRIDGE M: Jagan Teki S: Maintained --=20 2.43.0 From nobody Sat Oct 4 00:32:10 2025 Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.4]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 1156E2E54C5; Fri, 22 Aug 2025 06:40:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.31.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844860; cv=none; b=ddZhRdPsrFD9XSN+H6pQ1TW/ehMzrj5eIh2HAnW5Wytx9ykZ0NS3Opq8RLD0OWhhjzXp04flNt6dNkUyeQymfzoVT2HsmejFAh3HhjW2zTYMeJBwgOetZPM9wvuSXJ7Mkp0Z5e54IkNFlC8j4RGcmuePtKerUfuPkx9bop7FmwY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844860; c=relaxed/simple; bh=qGRc9yhLBLb/AMxs7EjYX9iByhqQp0GA6bDte/6ji2s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=B4gnsCK9qvmw8aTGTVBaNkHWZ7qbzZCSWurnnlw1r/RX6AyOzmsnk6wpAWZsq1ENAA8QBiGn3rHCeD4Ecmbxpj+nvQKvpLBLpMwsm17JDkKwfoNmfPgC4DheL6mut8y4p4b8IYU6VlODZbzA8uq2qLaQFvLReHut6LeINzIFmio= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=HbEYuUzW; arc=none smtp.client-ip=220.197.31.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="HbEYuUzW" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=vB 8wLIz0WHvujVMHowKC0Q/8HNa8Qgp3eo7drb5rVz4=; b=HbEYuUzWyYvZFnk9Ui Qr+ESbU85K/WGsI1ioQY8ekkpNtSJS6d3WKn17qa/aSmga29et++dqBhNNzn11o4 fbLMKB044YCb4QR8Z9KwkTd3h69ECyjYyXSWwH4ljNGW5JABnBBpLMM43uXKuYUb AnYrDHI++qt1TMYS+RL4tO47E= Received: from ProDesk.. (unknown []) by gzsmtp3 (Coremail) with SMTP id PigvCgAn9_zCEKhoYtibAA--.23257S7; Fri, 22 Aug 2025 14:40:22 +0800 (CST) From: Andy Yan To: dmitry.baryshkov@oss.qualcomm.com, heiko@sntech.de Cc: hjc@rock-chips.com, mripard@kernel.org, naoki@radxa.com, stephen@radxa.com, cristian.ciocaltea@collabora.com, neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, yubing.zhang@rock-chips.com, krzk+dt@kernel.org, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, robh@kernel.org, sebastian.reichel@collabora.com, Andy Yan , Krzysztof Kozlowski Subject: [PATCH v7 05/10] dt-bindings: display: simple-bridge: Add ra620 compatible Date: Fri, 22 Aug 2025 14:39:49 +0800 Message-ID: <20250822063959.692098-6-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822063959.692098-1-andyshrk@163.com> References: <20250822063959.692098-1-andyshrk@163.com> 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: PigvCgAn9_zCEKhoYtibAA--.23257S7 X-Coremail-Antispam: 1Uf129KBjvdXoWrZw1UZrWxKw4DCw4kKF18Grg_yoWDAFc_X3 Z7Aw1UJr1FqasYgFs8ZFs7Gry3Xw48KrWrCr10yrs7Ar4S934DKa97J34rGr1rAF1I9Fn7 ur1fW39rCwsrujkaLaAFLSUrUUUUjb8apTn2vfkv8UJUUUU8Yxn0WfASr-VFAUDa7-sFnT 9fnUUvcSsGvfC2KfnxnUUI43ZEXa7IU8NdbUUUUUU== X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiMx2xXmioB5f6TAAAsn Content-Type: text/plain; charset="utf-8" From: Andy Yan RA620 is a DP to HDMI bridge converter from RADXA, which first found be used on ROCK 5 ITX. This chip can be used without involving software. Signed-off-by: Andy Yan Acked-by: Krzysztof Kozlowski --- (no changes since v3) Changes in v3: - First introduced in this version. .../devicetree/bindings/display/bridge/simple-bridge.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/bridge/simple-bridge= .yaml b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml index 43cf4df9811a5..421f99ca42d9b 100644 --- a/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml +++ b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml @@ -28,6 +28,7 @@ properties: - enum: - adi,adv7123 - dumb-vga-dac + - radxa,ra620 - ti,opa362 - ti,ths8134 - ti,ths8135 --=20 2.43.0 From nobody Sat Oct 4 00:32:10 2025 Received: from m16.mail.163.com (m16.mail.163.com [117.135.210.4]) by smtp.subspace.kernel.org (Postfix) with ESMTP id BE1702E54D0; Fri, 22 Aug 2025 06:40:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=117.135.210.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844861; cv=none; b=Scx3cc4PceROVNMHrLwYs6itT6NnuS+8U2z0YNquS9XTC5RwmRGNDN/sNCptk6UDqX/mmzoOSymmX9Zf/YtbnduPFQZbEVgOi+cMfNNIYIQ+GYTAEWXgGttMdqMb0b31YUl1cE+IWZ6tDp6fsOGpoYpXKUuEysS07IjS8eYDQ4U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844861; c=relaxed/simple; bh=MI0EvgwnGCqqqaLGee0kziad6WH0JVTghagP3K8gkyQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=M4RB/RoT4m/Enly4DQjKGhN4nZ8WlAldY49ok4XXlGxo2/ZQlfilJKoDaytLnRUkloLSsPkyEQajIooavgG94YqRDSMJ+RV+LKLMlE9jHgOYfQyJOwbBSJuBCsYF0rJAMku6nLBk1RMl4KTYoIb9E9I7stx6MfoE1MYtAPZ/pjE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=SZXXeno0; arc=none smtp.client-ip=117.135.210.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="SZXXeno0" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=Ih Uhybn59/7JyTet/HSgHCP7nZWxnFr2AfvIvVQ/is4=; b=SZXXeno0JfZsDoyuKO xW0a66tP2f+rZ9CPGzvHVeHp3jTyzXvtSLZpTrSqsu//OKl9nAEJiNZg13gy3qUB qwIzJQ8hiySC6cf7KTRWXQqiEpuvrcM4+r7uDqJLf1zqzXrgjBAdhujyC9s91pnp U2p55RFf3Da4Mo9pY5m/+Pr34= Received: from ProDesk.. (unknown []) by gzsmtp3 (Coremail) with SMTP id PigvCgAn9_zCEKhoYtibAA--.23257S8; Fri, 22 Aug 2025 14:40:23 +0800 (CST) From: Andy Yan To: dmitry.baryshkov@oss.qualcomm.com, heiko@sntech.de Cc: hjc@rock-chips.com, mripard@kernel.org, naoki@radxa.com, stephen@radxa.com, cristian.ciocaltea@collabora.com, neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, yubing.zhang@rock-chips.com, krzk+dt@kernel.org, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, robh@kernel.org, sebastian.reichel@collabora.com, Andy Yan Subject: [PATCH v7 06/10] drm/bridge: simple-bridge: Add support for radxa ra620 Date: Fri, 22 Aug 2025 14:39:50 +0800 Message-ID: <20250822063959.692098-7-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822063959.692098-1-andyshrk@163.com> References: <20250822063959.692098-1-andyshrk@163.com> 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: PigvCgAn9_zCEKhoYtibAA--.23257S8 X-Coremail-Antispam: 1Uf129KBjvdXoW7Gw47tr48Jr4ftr4xKrWUtwb_yoWkKrc_ZF na9ryUJr45AF95KF43Zw43AryIva18urZ7Wr1vgrZ3Aws3Zr47GwnrZr9xZ34fAF10yF9F y3W3JFWayr17ujkaLaAFLSUrUUUUjb8apTn2vfkv8UJUUUU8Yxn0WfASr-VFAUDa7-sFnT 9fnUUvcSsGvfC2KfnxnUUI43ZEXa7IUnbAw7UUUUU== X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/xtbB0gqxXmioDHlxZQAAsW Content-Type: text/plain; charset="utf-8" From: Andy Yan The RA620 is an active DP to HDMI converter chip, basically no software is involved to drive it. Add it to simple bridge to make it can be find by the drm bridge chain. Signed-off-by: Andy Yan Reviewed-by: Dmitry Baryshkov --- Changes in v7: - Fix a typo in subject: s/birdge/bridge/ Changes in v3: - First introduced in this version. drivers/gpu/drm/bridge/simple-bridge.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridg= e/simple-bridge.c index 3d15ddd394703..1f16d568bcc4e 100644 --- a/drivers/gpu/drm/bridge/simple-bridge.c +++ b/drivers/gpu/drm/bridge/simple-bridge.c @@ -261,6 +261,11 @@ static const struct of_device_id simple_bridge_match[]= =3D { .timings =3D &default_bridge_timings, .connector_type =3D DRM_MODE_CONNECTOR_VGA, }, + }, { + .compatible =3D "radxa,ra620", + .data =3D &(const struct simple_bridge_info) { + .connector_type =3D DRM_MODE_CONNECTOR_HDMIA, + }, }, { .compatible =3D "ti,opa362", .data =3D &(const struct simple_bridge_info) { --=20 2.43.0 From nobody Sat Oct 4 00:32:10 2025 Received: from m16.mail.163.com (m16.mail.163.com [117.135.210.3]) by smtp.subspace.kernel.org (Postfix) with ESMTP id BD9DE2E763E; Fri, 22 Aug 2025 06:41:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=117.135.210.3 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844864; cv=none; b=pMAY5bEAwxvJTwfK05eN6nwvDt1HqqKKd+UA+YIv4BLW9mRRnxb5bCUWSXzCtlRyUXH4e3fzGjwijzbU+lfgdU7BdV0rS8u6pPhCiZd2QEnPVyHjwCe6Pf7aOE2THgJi9NqzQm5Gqc4slrEqDeYeV+cY0T8QMnfJRz+u+bqiaV0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844864; c=relaxed/simple; bh=FcumcV2Whbcu58LzChSEs7DamIEIn4LvHWaXu+hFJWA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LVKejzrcs08hJSolgD32OxViqOOm8mFimHuE9lWj3G3IS6Z8nF+QOFO2pkl2o0466NQTZnCngcTwvplvWV4EvcwYc8/ltRPbMT6iHSNHDiZziFl3BlXZR8jxYi0r7qgpa62iXoSGTLqsLglAqnhIpswUnsq2gMStzq+cSpkBSL0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=OyE6Pn5k; arc=none smtp.client-ip=117.135.210.3 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="OyE6Pn5k" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=R7 lVxMHBGqRXSFM3wkc9nmiY62qEr5W27qh0df8q1wc=; b=OyE6Pn5kjDPrTYHFiq HQ+QIf94JAj9um1+9Eb97peJCCI9cny0v2c1bjEPFCucr+eDwrp5nN7RxL/+sole M2ta5l5sC7WS4SJ0+fI/kDYPuapkm3Mfbs4TZ+IB+zfp5dvRQIxvEJ3KrIGDS2Qm aQXUwD2ZW8rRUOHUoJARbV+GI= Received: from ProDesk.. (unknown []) by gzsmtp3 (Coremail) with SMTP id PigvCgAn9_zCEKhoYtibAA--.23257S9; Fri, 22 Aug 2025 14:40:25 +0800 (CST) From: Andy Yan To: dmitry.baryshkov@oss.qualcomm.com, heiko@sntech.de Cc: hjc@rock-chips.com, mripard@kernel.org, naoki@radxa.com, stephen@radxa.com, cristian.ciocaltea@collabora.com, neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, yubing.zhang@rock-chips.com, krzk+dt@kernel.org, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, robh@kernel.org, sebastian.reichel@collabora.com, Andy Yan Subject: [PATCH v7 07/10] arm64: dts: rockchip: Add DP0 for rk3588 Date: Fri, 22 Aug 2025 14:39:51 +0800 Message-ID: <20250822063959.692098-8-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822063959.692098-1-andyshrk@163.com> References: <20250822063959.692098-1-andyshrk@163.com> 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: PigvCgAn9_zCEKhoYtibAA--.23257S9 X-Coremail-Antispam: 1Uf129KBjvJXoW7Kw18CFyUCFyxJF1kJw4DXFb_yoW8WrWrp3 ZrCrZ3XrW8uF12q39xK34ktrZ8Aan5CFZ5Kr17Gry0kr4Sqr9FkryfKr13C34DXr47ZwsF vFs3tryxKF4DAaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jwvtZUUUUU= X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/xtbBEhSxXmioCP3PbgAAs9 Content-Type: text/plain; charset="utf-8" From: Andy Yan The DP0 is compliant with the DisplayPort Specification Version 1.4, and share the USBDP combo PHY0 with USB 3.1 HOST0 controller. Signed-off-by: Andy Yan Reviewed-by: Sebastian Reichel --- (no changes since v1) arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boo= t/dts/rockchip/rk3588-base.dtsi index 70f03e68ba550..b8bcf450e9153 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi @@ -1472,6 +1472,36 @@ dsi1_out: port@1 { }; }; =20 + dp0: dp@fde50000 { + compatible =3D "rockchip,rk3588-dp"; + reg =3D <0x0 0xfde50000 0x0 0x4000>; + interrupts =3D ; + clocks =3D <&cru PCLK_DP0>, <&cru CLK_AUX16M_0>, + <&cru CLK_DP0>, <&cru MCLK_I2S4_8CH_TX>, + <&cru MCLK_SPDIF2_DP0>; + clock-names =3D "apb", "aux", "hdcp", "i2s", "spdif"; + assigned-clocks =3D <&cru CLK_AUX16M_0>; + assigned-clock-rates =3D <16000000>; + resets =3D <&cru SRST_DP0>; + phys =3D <&usbdp_phy0 PHY_TYPE_DP>; + power-domains =3D <&power RK3588_PD_VO0>; + #sound-dai-cells =3D <0>; + status =3D "disabled"; + + ports { + #address-cells =3D <1>; + #size-cells =3D <0>; + + dp0_in: port@0 { + reg =3D <0>; + }; + + dp0_out: port@1 { + reg =3D <1>; + }; + }; + }; + hdmi0: hdmi@fde80000 { compatible =3D "rockchip,rk3588-dw-hdmi-qp"; reg =3D <0x0 0xfde80000 0x0 0x20000>; --=20 2.43.0 From nobody Sat Oct 4 00:32:10 2025 Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.3]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 0CAAC2E54AD; Fri, 22 Aug 2025 06:40:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.31.3 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844859; cv=none; b=H0N5FtIVrKasSoLclepTnuRsmECkhU4+hbcWK/rFvB2ZNJV4dYvv6gqcED3d94elWCkyJNZKQV33ZgstgJQvM60hLeJCWVwqF5d2PSjR1+6NjayTioOdY0hhY9C5X2s7yHkclY5oi8lEw/p4VWjMVKOWIieAjwRkgInzPjKjAKI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844859; c=relaxed/simple; bh=+dXvdVQICycX5HfPEPflG9D0zT+BAKm3h2ZN1HkGhBA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CtinDAspLUmhFljBtsO4fgOo/0j3uI/z9Lvsvk09xYtLH8625mlBDDDGNB16zGwfE5v9HoQu90Wv2W2usGCv2HFQR00v5SUdyYxXOmzvNUAb0j5edns7MoWvbwb3jHopTghflUahg44soPqNFyw8fdRCIOZdU8x+HoXkCcuG1LU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=I8xITWGb; arc=none smtp.client-ip=220.197.31.3 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="I8xITWGb" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=/A 3ktddHCOVpJeZQNetYvzFzGrqcN09SXIXDuSyH2Zs=; b=I8xITWGbwewgMV+rbj 4ovTonhakdPJ+a+2GIqdXpI4RCutabnx+kPqAGkZvGY7diKMU1n3yfSJ3X4UJe3j 5/g7vLQjTHDeLnoiMx+8bYIB3jYOFZ0TbI0oGHrJ2bmy2l21WsJTvSx8xyZ4ycpw RrINmrGjAtpbrI1zGz7Bg+yjk= Received: from ProDesk.. (unknown []) by gzsmtp3 (Coremail) with SMTP id PigvCgAn9_zCEKhoYtibAA--.23257S10; Fri, 22 Aug 2025 14:40:26 +0800 (CST) From: Andy Yan To: dmitry.baryshkov@oss.qualcomm.com, heiko@sntech.de Cc: hjc@rock-chips.com, mripard@kernel.org, naoki@radxa.com, stephen@radxa.com, cristian.ciocaltea@collabora.com, neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, yubing.zhang@rock-chips.com, krzk+dt@kernel.org, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, robh@kernel.org, sebastian.reichel@collabora.com, Andy Yan Subject: [PATCH v7 08/10] arm64: dts: rockchip: Add DP1 for rk3588 Date: Fri, 22 Aug 2025 14:39:52 +0800 Message-ID: <20250822063959.692098-9-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822063959.692098-1-andyshrk@163.com> References: <20250822063959.692098-1-andyshrk@163.com> 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: PigvCgAn9_zCEKhoYtibAA--.23257S10 X-Coremail-Antispam: 1Uf129KBjvJXoW7ZrWDCry7Kr17CF4kXFy5urg_yoW8WF4Dpw nrurZ3WrW8uF1Sq3sxt34kXrZ8A3Z5CFZrKr1xK3W8Kr1Sqr92k34akrZ3C34UXr17XwsF kFsxtry8KF4qy3DanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jwvtZUUUUU= X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiMwWxXmioB5f6uQAAsK Content-Type: text/plain; charset="utf-8" From: Andy Yan The DP1 is compliant with the DisplayPort Specification Version 1.4, and share the USBDP combo PHY1 with USB 3.1 HOST1 controller. Signed-off-by: Andy Yan Reviewed-by: Sebastian Reichel --- (no changes since v1) .../arm64/boot/dts/rockchip/rk3588-extra.dtsi | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/bo= ot/dts/rockchip/rk3588-extra.dtsi index 90414486e466f..691fe941d53a1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi @@ -210,6 +210,36 @@ i2s10_8ch: i2s@fde00000 { status =3D "disabled"; }; =20 + dp1: dp@fde60000 { + compatible =3D "rockchip,rk3588-dp"; + reg =3D <0x0 0xfde60000 0x0 0x4000>; + interrupts =3D ; + clocks =3D <&cru PCLK_DP1>, <&cru CLK_AUX16M_1>, + <&cru CLK_DP1>, <&cru MCLK_I2S8_8CH_TX>, + <&cru MCLK_SPDIF5_DP1>; + clock-names =3D "apb", "aux", "hdcp", "i2s", "spdif"; + assigned-clocks =3D <&cru CLK_AUX16M_1>; + assigned-clock-rates =3D <16000000>; + resets =3D <&cru SRST_DP1>; + phys =3D <&usbdp_phy1 PHY_TYPE_DP>; + power-domains =3D <&power RK3588_PD_VO0>; + #sound-dai-cells =3D <0>; + status =3D "disabled"; + + ports { + #address-cells =3D <1>; + #size-cells =3D <0>; + + dp1_in: port@0 { + reg =3D <0>; + }; + + dp1_out: port@1 { + reg =3D <1>; + }; + }; + }; + hdmi1: hdmi@fdea0000 { compatible =3D "rockchip,rk3588-dw-hdmi-qp"; reg =3D <0x0 0xfdea0000 0x0 0x20000>; --=20 2.43.0 From nobody Sat Oct 4 00:32:10 2025 Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.3]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 92C002E54CC; Fri, 22 Aug 2025 06:40:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.31.3 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844859; cv=none; b=s7DCJhCB0rtEzvrvFrkIckjeNI4p/0Q6EDfmBpuQQpZp1QH7/KRTAQJdgOFPtFZjs9erU/Xsar4+BqziaI3jga3hvTKERWYYF90ztUrh1zplDSCdTmzdUmURBP1n3nA9hic2PZ9dViu3NdfvmYHGB4XkBY3B4bdwAh3nuKHHlDQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844859; c=relaxed/simple; bh=I+nprd4XKv9b7xxgKYJmPkEjWpC9unrbulKXwD4ZO+s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TVvPHYvSKrYNrUmWm85EBDQOAwJ4WpCM+3Nfn+335m0VRmSiCwt/SAhWqFbSeHBHx4S4MpJCxzZcCv6I8ot2xavdFuRHKOpcD35L+jSNtmqIcTH8K1s1MCwOc1L6Xj378ZXc/RLdr922aXtJVpwbhwQcvmSEGTsCfYosjFvrbN8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=OleJAlpX; arc=none smtp.client-ip=220.197.31.3 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="OleJAlpX" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=HA NX8SGyUYTMmygkXUKgrV9E1KMjquu/Hj3lDx24v3U=; b=OleJAlpXnekUIDBtyH Be7UdN73GWIk4WY8BPu/RFFWmg8rmJ4d5tDpua7GM0a8pjeiyvOLXIKap+HsMzr0 Kxm/i6ApnkeBP0TjJikkuvZnFpgvZFXGCfRGBrnKWRo2inLdlrz/eI9HelknoINw y9OJdAs+q+nL8M62ttc5T7cEQ= Received: from ProDesk.. (unknown []) by gzsmtp3 (Coremail) with SMTP id PigvCgAn9_zCEKhoYtibAA--.23257S11; Fri, 22 Aug 2025 14:40:27 +0800 (CST) From: Andy Yan To: dmitry.baryshkov@oss.qualcomm.com, heiko@sntech.de Cc: hjc@rock-chips.com, mripard@kernel.org, naoki@radxa.com, stephen@radxa.com, cristian.ciocaltea@collabora.com, neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, yubing.zhang@rock-chips.com, krzk+dt@kernel.org, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, robh@kernel.org, sebastian.reichel@collabora.com, Andy Yan Subject: [PATCH v7 09/10] arm64: dts: rockchip: Enable DisplayPort for rk3588s Cool Pi 4B Date: Fri, 22 Aug 2025 14:39:53 +0800 Message-ID: <20250822063959.692098-10-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822063959.692098-1-andyshrk@163.com> References: <20250822063959.692098-1-andyshrk@163.com> 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: PigvCgAn9_zCEKhoYtibAA--.23257S11 X-Coremail-Antispam: 1Uf129KBjvJXoW7ur48WF43Gr1rWFyfKrWUtwb_yoW8CryDp3 ZxArsYgFZ7urWUJ3sYyF4xJrZ8Crs5ua97Jr13Z34akF47Was3twn3GrnYkryjvFs3Xayr Kr4kZasF9F1DXaUanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jwHUDUUUUU= X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/xtbB0gCxXmioDHlx2wAAsi Content-Type: text/plain; charset="utf-8" From: Andy Yan Enable the Mini DisplayPort on this board. Note that ROCKCHIP_VOP2_EP_DP0 is defined as 10 in dt-binding header, but it will trigger a dtc warning like "graph node unit address error, expected "a"" if we use it directly after endpoint, so we use "a" instead here. Signed-off-by: Andy Yan Reviewed-by: Dmitry Baryshkov --- (no changes since v2) Changes in v2: - Sort in alphabetical order .../boot/dts/rockchip/rk3588s-coolpi-4b.dts | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts b/arch/arm6= 4/boot/dts/rockchip/rk3588s-coolpi-4b.dts index b2947b36fadaf..d7557e61390b9 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts @@ -39,6 +39,18 @@ chosen { stdout-path =3D "serial2:1500000n8"; }; =20 + dp-con { + compatible =3D "dp-connector"; + label =3D "DP OUT"; + type =3D "mini"; + + port { + dp_con_in: endpoint { + remote-endpoint =3D <&dp0_out_con>; + }; + }; + }; + hdmi-con { compatible =3D "hdmi-connector"; type =3D "d"; @@ -215,6 +227,24 @@ &cpu_b2 { cpu-supply =3D <&vdd_cpu_big1_s0>; }; =20 +&dp0 { + status =3D "okay"; + pinctrl-0 =3D <&dp0m0_pins>; + pinctrl-names =3D "default"; +}; + +&dp0_in { + dp0_in_vp2: endpoint { + remote-endpoint =3D <&vp2_out_dp0>; + }; +}; + +&dp0_out { + dp0_out_con: endpoint { + remote-endpoint =3D <&dp_con_in>; + }; +}; + &gpu { mali-supply =3D <&vdd_gpu_s0>; status =3D "okay"; @@ -890,3 +920,10 @@ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { remote-endpoint =3D <&hdmi0_in_vp0>; }; }; + +&vp2 { + vp2_out_dp0: endpoint@a { + reg =3D ; + remote-endpoint =3D <&dp0_in_vp2>; + }; +}; --=20 2.43.0 From nobody Sat Oct 4 00:32:10 2025 Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.2]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 499BE2E54C8; Fri, 22 Aug 2025 06:40:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.31.2 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844859; cv=none; b=TS0gjYFwS9b1ia4dNM2azPPvZjWI7zhBc7WlmYE25xC2Iyh5CtnCM5iGz99paUsg0qvVodAxsqVX+A7iB4YHVFDdkF0tTK9WqM8hRkgrqZ9bsVmwSInyehBHp9jJU9nIRkmjhHUaigQCuhOksvx1EKWj7olU7b1fROZTT/oXgLo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755844859; c=relaxed/simple; bh=zkIQ13/H9CnTVLK6A7Z4pxO6LqziG5oPt4Wp5fwiZIA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tzStmdmhr51HI+6Hoq+IQkV2GAQYR9C9Xy/CYOLjG4oLXiIT1du0kiVuVcchFCKzb9IRmlSb78io65HXpdjGTx0jd1xjSlg/VJQrzsmRgweM/oqXct1AUceUguKEsD09vtt9cBwStT0TTsIK6umZOElU0/qhNmdwVY7wlu9s2Og= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=lX79IJzn; arc=none smtp.client-ip=220.197.31.2 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="lX79IJzn" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=h8 8O4dZwxfFg63Pi6AQ85/YvjoNhwX4BJiQNP+yOVJw=; b=lX79IJznDtGZJ4/KpD vjNxpE4Si3NCrcoLhVQ8OmEX9vUSC0NMQYC5Ady/j0P0BhWwtcTeUGfmlycHFh3d mXQPTzVAlI3p7/BkUOLWC+n927tp+yrSX3mPdwLDKWTzcOl0njbhc+2AqWdBH3gk h2KzYceg6UGaZmEJuJVJxM5Ck= Received: from ProDesk.. (unknown []) by gzsmtp3 (Coremail) with SMTP id PigvCgAn9_zCEKhoYtibAA--.23257S12; Fri, 22 Aug 2025 14:40:28 +0800 (CST) From: Andy Yan To: dmitry.baryshkov@oss.qualcomm.com, heiko@sntech.de Cc: hjc@rock-chips.com, mripard@kernel.org, naoki@radxa.com, stephen@radxa.com, cristian.ciocaltea@collabora.com, neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, yubing.zhang@rock-chips.com, krzk+dt@kernel.org, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, robh@kernel.org, sebastian.reichel@collabora.com, Andy Yan Subject: [PATCH v7 10/10] arm64: dts: rockchip: Enable DP2HDMI for ROCK 5 ITX Date: Fri, 22 Aug 2025 14:39:54 +0800 Message-ID: <20250822063959.692098-11-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250822063959.692098-1-andyshrk@163.com> References: <20250822063959.692098-1-andyshrk@163.com> 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: PigvCgAn9_zCEKhoYtibAA--.23257S12 X-Coremail-Antispam: 1Uf129KBjvJXoW7CrykKw18Xw43uF4kCrWkXrb_yoW8KrWrpF nF9rs5GryxuryYqw1FvF1kZFs8Krs5ua93Jr1aqry0yFW7Xas5K3WrWr9YqFyjvF1xXw4a yr4kXa4j93WDXFJanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07j2iihUUUUU= X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiMxWxXmioB5f7BwAAsl Content-Type: text/plain; charset="utf-8" From: Andy Yan The HDMI0(Port next to Headphone Jack) is drived by DP1 on rk3588 via RA620(a dp2hdmi converter). Add related dt nodes to enable it. Note: ROCKCHIP_VOP2_EP_DP1 is defined as 11 in dt-binding header, but it will trigger a dtc warning like "graph node unit address error, expected "b"" if we use it directly after endpoint, so we use "b" instead here. Signed-off-by: Andy Yan Reviewed-by: Dmitry Baryshkov --- (no changes since v3) Changes in v3: - Add RA620 into bridge chain. .../boot/dts/rockchip/rk3588-rock-5-itx.dts | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts b/arch/arm6= 4/boot/dts/rockchip/rk3588-rock-5-itx.dts index 7de17117df7ae..903ad42f97177 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts @@ -57,6 +57,29 @@ analog-sound { "Headphone", "Headphones"; }; =20 + bridge { + compatible =3D "radxa,ra620"; + + ports { + #address-cells =3D <1>; + #size-cells =3D <0>; + port@0 { + reg =3D <0>; + hdmi_bridge_in: endpoint { + remote-endpoint =3D <&dp1_out_con>; + }; + }; + + port@1 { + reg =3D <1>; + + hdmi_bridge_out: endpoint { + remote-endpoint =3D <&hdmi_con_in>; + }; + }; + }; + }; + gpio-leds { compatible =3D "gpio-leds"; pinctrl-names =3D "default"; @@ -73,6 +96,17 @@ hdd-led2 { }; }; =20 + hdmi0-con { + compatible =3D "hdmi-connector"; + type =3D "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint =3D <&hdmi_bridge_out>; + }; + }; + }; + hdmi1-con { compatible =3D "hdmi-connector"; type =3D "a"; @@ -268,6 +302,24 @@ &cpu_l3 { cpu-supply =3D <&vdd_cpu_lit_s0>; }; =20 +&dp1 { + status =3D "okay"; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&dp1m0_pins>; +}; + +&dp1_in { + dp1_in_vp2: endpoint { + remote-endpoint =3D <&vp2_out_dp1>; + }; +}; + +&dp1_out { + dp1_out_con: endpoint { + remote-endpoint =3D <&hdmi_bridge_in>; + }; +}; + &gpu { mali-supply =3D <&vdd_gpu_s0>; status =3D "okay"; @@ -1261,3 +1313,10 @@ vp1_out_hdmi1: endpoint@ROCKCHIP_VOP2_EP_HDMI1 { remote-endpoint =3D <&hdmi1_in_vp1>; }; }; + +&vp2 { + vp2_out_dp1: endpoint@b { + reg =3D ; + remote-endpoint =3D <&dp1_in_vp2>; + }; +}; --=20 2.43.0