From c7d3f6b67e60b5c063eba78c55c38d560fe62daf Mon Sep 17 00:00:00 2001 From: Ricardo Pardini Date: Mon, 7 Apr 2025 12:15:45 -0300 Subject: [PATCH] rockchip64-6.15: HACK: drop stuff that doesnt apply to 6.15-rc1 (predatory) --- .../general-fix-inno-usb2-phy-init.patch | 28 - ...nopsys-designware-hdmi-rx-controller.patch | 4117 ----------------- .../rk3588-0130-add-hdmi1-support.patch | 123 - ...8-0131-vop2-hdmi0-disp-modes-support.patch | 252 - ...ix-label-name-of-hdptxphy-for-RK3588.patch | 318 -- ...8-0133-vop2-hdmi1-disp-modes-support.patch | 173 - ...sabled-clock-provider-in-of_clk_get_.patch | 52 - .../rk3588-0180-drm-bridge-dw-hdmi-qp.patch | 580 --- .../rk3588-1011-rock5b-hdmi1.patch | 97 - ...chip-add-hdmi1-support-to-ROCK-5-ITX.patch | 93 - ...hip-Add-HDMI-support-to-ArmSoM-Sige7.patch | 64 - ...ip-Add-ap6275p-wireless-support-to-A.patch | 39 - ...-dts-rockchip-Rock-5B-add-hdmi-sound.patch | 60 - 13 files changed, 5996 deletions(-) delete mode 100644 patch/kernel/archive/rockchip64-6.15/general-fix-inno-usb2-phy-init.patch delete mode 100644 patch/kernel/archive/rockchip64-6.15/rk3588-0113-add-synopsys-designware-hdmi-rx-controller.patch delete mode 100644 patch/kernel/archive/rockchip64-6.15/rk3588-0130-add-hdmi1-support.patch delete mode 100644 patch/kernel/archive/rockchip64-6.15/rk3588-0131-vop2-hdmi0-disp-modes-support.patch delete mode 100644 patch/kernel/archive/rockchip64-6.15/rk3588-0132-Fix-label-name-of-hdptxphy-for-RK3588.patch delete mode 100644 patch/kernel/archive/rockchip64-6.15/rk3588-0133-vop2-hdmi1-disp-modes-support.patch delete mode 100644 patch/kernel/archive/rockchip64-6.15/rk3588-0134-clk-check-for-disabled-clock-provider-in-of_clk_get_.patch delete mode 100644 patch/kernel/archive/rockchip64-6.15/rk3588-0180-drm-bridge-dw-hdmi-qp.patch delete mode 100644 patch/kernel/archive/rockchip64-6.15/rk3588-1011-rock5b-hdmi1.patch delete mode 100644 patch/kernel/archive/rockchip64-6.15/rk3588-1012-arm64-dts-rockchip-add-hdmi1-support-to-ROCK-5-ITX.patch delete mode 100644 patch/kernel/archive/rockchip64-6.15/rk3588-1031-arm64-dts-rockchip-Add-HDMI-support-to-ArmSoM-Sige7.patch delete mode 100644 patch/kernel/archive/rockchip64-6.15/rk3588-1032-arm64-dts-rockchip-Add-ap6275p-wireless-support-to-A.patch delete mode 100644 patch/kernel/archive/rockchip64-6.15/rk3588-1102-arm64-dts-rockchip-Rock-5B-add-hdmi-sound.patch diff --git a/patch/kernel/archive/rockchip64-6.15/general-fix-inno-usb2-phy-init.patch b/patch/kernel/archive/rockchip64-6.15/general-fix-inno-usb2-phy-init.patch deleted file mode 100644 index 6c608e4a69..0000000000 --- a/patch/kernel/archive/rockchip64-6.15/general-fix-inno-usb2-phy-init.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Paolo Sabatino -Date: Mon, 22 Aug 2022 20:51:22 +0000 -Subject: remove usb2phy extcon initialization causing kernel oops - ---- - drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c -index 111111111111..222222222222 100644 ---- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c -+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c -@@ -1323,11 +1323,6 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, - goto out; - } - -- if (!of_property_read_bool(rphy->dev->of_node, "extcon")) { -- /* do initial sync of usb state */ -- id = property_enabled(rphy->grf, &rport->port_cfg->utmi_id); -- extcon_set_state_sync(rphy->edev, EXTCON_USB_HOST, !id); -- } - } - - out: --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-0113-add-synopsys-designware-hdmi-rx-controller.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-0113-add-synopsys-designware-hdmi-rx-controller.patch deleted file mode 100644 index 23f04155b8..0000000000 --- a/patch/kernel/archive/rockchip64-6.15/rk3588-0113-add-synopsys-designware-hdmi-rx-controller.patch +++ /dev/null @@ -1,4117 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shreeya Patel -Date: Fri, 19 Jul 2024 18:10:30 +0530 -Subject: dt-bindings: media: Document bindings for HDMI RX Controller - -Document bindings for the Synopsys DesignWare HDMI RX Controller. - -Reviewed-by: Rob Herring -Reviewed-by: Dmitry Osipenko -Signed-off-by: Shreeya Patel -Reviewed-by: Sebastian Reichel -Reviewed-by: AngeloGioacchino Del Regno -Link: https://lore.kernel.org/r/20240719124032.26852-3-shreeya.patel@collabora.com -Signed-off-by: Sebastian Reichel ---- - Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml | 132 ++++++++++ - 1 file changed, 132 insertions(+) - -diff --git a/Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml b/Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml -@@ -0,0 +1,132 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+# Device Tree bindings for Synopsys DesignWare HDMI RX Controller -+ -+--- -+$id: http://devicetree.org/schemas/media/snps,dw-hdmi-rx.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Synopsys DesignWare HDMI RX Controller -+ -+maintainers: -+ - Shreeya Patel -+ -+description: -+ Synopsys DesignWare HDMI Input Controller preset on RK3588 SoCs -+ allowing devices to receive and decode high-resolution video streams -+ from external sources like media players, cameras, laptops, etc. -+ -+properties: -+ compatible: -+ items: -+ - const: rockchip,rk3588-hdmirx-ctrler -+ - const: snps,dw-hdmi-rx -+ -+ reg: -+ maxItems: 1 -+ -+ interrupts: -+ maxItems: 3 -+ -+ interrupt-names: -+ items: -+ - const: cec -+ - const: hdmi -+ - const: dma -+ -+ clocks: -+ maxItems: 7 -+ -+ clock-names: -+ items: -+ - const: aclk -+ - const: audio -+ - const: cr_para -+ - const: pclk -+ - const: ref -+ - const: hclk_s_hdmirx -+ - const: hclk_vo1 -+ -+ power-domains: -+ maxItems: 1 -+ -+ resets: -+ maxItems: 4 -+ -+ reset-names: -+ items: -+ - const: axi -+ - const: apb -+ - const: ref -+ - const: biu -+ -+ memory-region: -+ maxItems: 1 -+ -+ hpd-gpios: -+ description: GPIO specifier for HPD. -+ maxItems: 1 -+ -+ rockchip,grf: -+ $ref: /schemas/types.yaml#/definitions/phandle -+ description: -+ The phandle of the syscon node for the general register file -+ containing HDMIRX PHY status bits. -+ -+ rockchip,vo1-grf: -+ $ref: /schemas/types.yaml#/definitions/phandle -+ description: -+ The phandle of the syscon node for the Video Output GRF register -+ to enable EDID transfer through SDAIN and SCLIN. -+ -+required: -+ - compatible -+ - reg -+ - interrupts -+ - interrupt-names -+ - clocks -+ - clock-names -+ - power-domains -+ - resets -+ - pinctrl-0 -+ - hpd-gpios -+ -+additionalProperties: false -+ -+examples: -+ - | -+ #include -+ #include -+ #include -+ #include -+ #include -+ #include -+ hdmi_receiver: hdmi-receiver@fdee0000 { -+ compatible = "rockchip,rk3588-hdmirx-ctrler", "snps,dw-hdmi-rx"; -+ reg = <0xfdee0000 0x6000>; -+ interrupts = , -+ , -+ ; -+ interrupt-names = "cec", "hdmi", "dma"; -+ clocks = <&cru ACLK_HDMIRX>, -+ <&cru CLK_HDMIRX_AUD>, -+ <&cru CLK_CR_PARA>, -+ <&cru PCLK_HDMIRX>, -+ <&cru CLK_HDMIRX_REF>, -+ <&cru PCLK_S_HDMIRX>, -+ <&cru HCLK_VO1>; -+ clock-names = "aclk", -+ "audio", -+ "cr_para", -+ "pclk", -+ "ref", -+ "hclk_s_hdmirx", -+ "hclk_vo1"; -+ power-domains = <&power RK3588_PD_VO1>; -+ resets = <&cru SRST_A_HDMIRX>, <&cru SRST_P_HDMIRX>, -+ <&cru SRST_HDMIRX_REF>, <&cru SRST_A_HDMIRX_BIU>; -+ reset-names = "axi", "apb", "ref", "biu"; -+ memory-region = <&hdmi_receiver_cma>; -+ pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_5v_detection>; -+ pinctrl-names = "default"; -+ hpd-gpios = <&gpio1 22 GPIO_ACTIVE_LOW>; -+ }; --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shreeya Patel -Date: Fri, 19 Jul 2024 18:10:31 +0530 -Subject: arm64: dts: rockchip: Add device tree support for HDMI RX Controller - -Add device tree support for Synopsys DesignWare HDMI RX -Controller. - -Reviewed-by: Dmitry Osipenko -Tested-by: Dmitry Osipenko -Co-developed-by: Dingxian Wen -Signed-off-by: Dingxian Wen -Signed-off-by: Shreeya Patel -Link: https://lore.kernel.org/r/20240719124032.26852-4-shreeya.patel@collabora.com -Signed-off-by: Sebastian Reichel ---- - arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi | 14 +++ - arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 56 ++++++++++ - 2 files changed, 70 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi -@@ -594,6 +594,20 @@ hdmim0_tx1_hpd: hdmim0-tx1-hpd { - /* hdmim0_tx1_hpd */ - <1 RK_PA6 5 &pcfg_pull_none>; - }; -+ -+ /omit-if-no-ref/ -+ hdmim1_rx: hdmim1-rx { -+ rockchip,pins = -+ /* hdmim1_rx_cec */ -+ <3 RK_PD1 5 &pcfg_pull_none>, -+ /* hdmim1_rx_scl */ -+ <3 RK_PD2 5 &pcfg_pull_none_smt>, -+ /* hdmim1_rx_sda */ -+ <3 RK_PD3 5 &pcfg_pull_none_smt>, -+ /* hdmim1_rx_hpdin */ -+ <3 RK_PD4 5 &pcfg_pull_none>; -+ }; -+ - /omit-if-no-ref/ - hdmim1_rx_cec: hdmim1-rx-cec { - rockchip,pins = -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -@@ -7,6 +7,29 @@ - #include "rk3588-extra-pinctrl.dtsi" - - / { -+ reserved-memory { -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ -+ /* -+ * The 4k HDMI capture controller works only with 32bit -+ * phys addresses and doesn't support IOMMU. HDMI RX CMA -+ * must be reserved below 4GB. -+ * The size of 160MB was determined as follows: -+ * (3840 * 2160 pixels) * (4 bytes/pixel) * (2 frames/buffer) / 10^6 = 66MB -+ * To ensure sufficient support for practical use-cases, -+ * we doubled the 66MB value. -+ */ -+ hdmi_receiver_cma: hdmi-receiver-cma { -+ compatible = "shared-dma-pool"; -+ alloc-ranges = <0x0 0x0 0x0 0xffffffff>; -+ size = <0x0 (160 * 0x100000)>; /* 160MiB */ -+ no-map; -+ status = "disabled"; -+ }; -+ }; -+ - usb_host1_xhci: usb@fc400000 { - compatible = "rockchip,rk3588-dwc3", "snps,dwc3"; - reg = <0x0 0xfc400000 0x0 0x400000>; -@@ -135,6 +158,39 @@ i2s10_8ch: i2s@fde00000 { - status = "disabled"; - }; - -+ hdmi_receiver: hdmi_receiver@fdee0000 { -+ compatible = "rockchip,rk3588-hdmirx-ctrler", "snps,dw-hdmi-rx"; -+ reg = <0x0 0xfdee0000 0x0 0x6000>; -+ power-domains = <&power RK3588_PD_VO1>; -+ rockchip,grf = <&sys_grf>; -+ rockchip,vo1-grf = <&vo1_grf>; -+ interrupts = , -+ , -+ ; -+ interrupt-names = "cec", "hdmi", "dma"; -+ clocks = <&cru ACLK_HDMIRX>, -+ <&cru CLK_HDMIRX_AUD>, -+ <&cru CLK_CR_PARA>, -+ <&cru PCLK_HDMIRX>, -+ <&cru CLK_HDMIRX_REF>, -+ <&cru PCLK_S_HDMIRX>, -+ <&cru HCLK_VO1>; -+ clock-names = "aclk", -+ "audio", -+ "cr_para", -+ "pclk", -+ "ref", -+ "hclk_s_hdmirx", -+ "hclk_vo1"; -+ resets = <&cru SRST_A_HDMIRX>, <&cru SRST_P_HDMIRX>, -+ <&cru SRST_HDMIRX_REF>, <&cru SRST_A_HDMIRX_BIU>; -+ reset-names = "axi", "apb", "ref", "biu"; -+ memory-region = <&hdmi_receiver_cma>; -+ pinctrl-0 = <&hdmim1_rx>; -+ pinctrl-names = "default"; -+ status = "disabled"; -+ }; -+ - pcie3x4: pcie@fe150000 { - compatible = "rockchip,rk3588-pcie", "rockchip,rk3568-pcie"; - #address-cells = <3>; --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shreeya Patel -Date: Fri, 19 Jul 2024 18:10:32 +0530 -Subject: media: platform: synopsys: Add support for hdmi input driver - -Add initial support for the Synopsys DesignWare HDMI RX -Controller Driver used by Rockchip RK3588. The driver -supports: - - HDMI 1.4b and 2.0 modes (HDMI 4k@60Hz) - - RGB888, YUV422, YUV444 and YCC420 pixel formats - - CEC - - EDID configuration - -The hardware also has Audio and HDCP capabilities, but these are -not yet supported by the driver. - -Reviewed-by: Dmitry Osipenko -Tested-by: Dmitry Osipenko -Co-developed-by: Dingxian Wen -Signed-off-by: Dingxian Wen -Signed-off-by: Shreeya Patel -Link: https://lore.kernel.org/r/20240719124032.26852-5-shreeya.patel@collabora.com -Signed-off-by: Sebastian Reichel ---- - drivers/media/platform/Kconfig | 1 + - drivers/media/platform/Makefile | 1 + - drivers/media/platform/synopsys/Kconfig | 3 + - drivers/media/platform/synopsys/Makefile | 2 + - drivers/media/platform/synopsys/hdmirx/Kconfig | 27 + - drivers/media/platform/synopsys/hdmirx/Makefile | 4 + - drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 2763 ++++++++++ - drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h | 394 ++ - drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c | 285 + - drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.h | 44 + - 10 files changed, 3524 insertions(+) - -diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig -index 111111111111..222222222222 100644 ---- a/drivers/media/platform/Kconfig -+++ b/drivers/media/platform/Kconfig -@@ -85,6 +85,7 @@ source "drivers/media/platform/rockchip/Kconfig" - source "drivers/media/platform/samsung/Kconfig" - source "drivers/media/platform/st/Kconfig" - source "drivers/media/platform/sunxi/Kconfig" -+source "drivers/media/platform/synopsys/Kconfig" - source "drivers/media/platform/ti/Kconfig" - source "drivers/media/platform/verisilicon/Kconfig" - source "drivers/media/platform/via/Kconfig" -diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile -index 111111111111..222222222222 100644 ---- a/drivers/media/platform/Makefile -+++ b/drivers/media/platform/Makefile -@@ -28,6 +28,7 @@ obj-y += rockchip/ - obj-y += samsung/ - obj-y += st/ - obj-y += sunxi/ -+obj-y += synopsys/ - obj-y += ti/ - obj-y += verisilicon/ - obj-y += via/ -diff --git a/drivers/media/platform/synopsys/Kconfig b/drivers/media/platform/synopsys/Kconfig -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/Kconfig -@@ -0,0 +1,3 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+ -+source "drivers/media/platform/synopsys/hdmirx/Kconfig" -diff --git a/drivers/media/platform/synopsys/Makefile b/drivers/media/platform/synopsys/Makefile -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/Makefile -@@ -0,0 +1,2 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+obj-y += hdmirx/ -diff --git a/drivers/media/platform/synopsys/hdmirx/Kconfig b/drivers/media/platform/synopsys/hdmirx/Kconfig -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/Kconfig -@@ -0,0 +1,27 @@ -+# SPDX-License-Identifier: GPL-2.0 -+ -+config VIDEO_SYNOPSYS_HDMIRX -+ tristate "Synopsys DesignWare HDMI Receiver driver" -+ depends on VIDEO_DEV -+ depends on ARCH_ROCKCHIP -+ select MEDIA_CONTROLLER -+ select VIDEO_V4L2_SUBDEV_API -+ select VIDEOBUF2_DMA_CONTIG -+ select CEC_CORE -+ select CEC_NOTIFIER -+ select HDMI -+ help -+ Support for Synopsys HDMI HDMI RX Controller. -+ This driver supports HDMI 2.0 version. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called synopsys_hdmirx. -+ -+config HDMIRX_LOAD_DEFAULT_EDID -+ bool "Load default EDID" -+ depends on VIDEO_SYNOPSYS_HDMIRX -+ default "y" -+ help -+ Preload the default EDID (Extended Display Identification Data). -+ EDID contains information about the capabilities of the display, -+ such as supported resolutions, refresh rates, and audio formats. -diff --git a/drivers/media/platform/synopsys/hdmirx/Makefile b/drivers/media/platform/synopsys/hdmirx/Makefile -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/Makefile -@@ -0,0 +1,4 @@ -+# SPDX-License-Identifier: GPL-2.0 -+synopsys-hdmirx-objs := snps_hdmirx.o snps_hdmirx_cec.o -+ -+obj-$(CONFIG_VIDEO_SYNOPSYS_HDMIRX) += synopsys-hdmirx.o -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -@@ -0,0 +1,2763 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2024 Collabora, Ltd. -+ * Author: Shreeya Patel -+ * -+ * Copyright (c) 2021 Rockchip Electronics Co. Ltd. -+ * Author: Dingxian Wen -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "snps_hdmirx.h" -+#include "snps_hdmirx_cec.h" -+ -+static int debug; -+module_param(debug, int, 0644); -+MODULE_PARM_DESC(debug, "debug level (0-3)"); -+ -+#define EDID_NUM_BLOCKS_MAX 2 -+#define EDID_BLOCK_SIZE 128 -+#define HDMIRX_STORED_BIT_WIDTH 8 -+#define IREF_CLK_FREQ_HZ 428571429 -+#define MEMORY_ALIGN_ROUND_UP_BYTES 64 -+#define HDMIRX_PLANE_Y 0 -+#define HDMIRX_PLANE_CBCR 1 -+#define RK_IRQ_HDMIRX_HDMI 210 -+#define FILTER_FRAME_CNT 6 -+#define RK_SIP_FIQ_CTRL 0x82000024 -+#define SIP_WDT_CFG 0x82000026 -+#define DETECTION_THRESHOLD 7 -+ -+/* fiq control sub func */ -+enum { -+ RK_SIP_FIQ_CTRL_FIQ_EN = 1, -+ RK_SIP_FIQ_CTRL_FIQ_DIS, -+ RK_SIP_FIQ_CTRL_SET_AFF -+}; -+ -+/* SIP_WDT_CONFIG call types */ -+enum { -+ WDT_START = 0, -+ WDT_STOP = 1, -+ WDT_PING = 2, -+}; -+ -+enum hdmirx_pix_fmt { -+ HDMIRX_RGB888 = 0, -+ HDMIRX_YUV422 = 1, -+ HDMIRX_YUV444 = 2, -+ HDMIRX_YUV420 = 3, -+}; -+ -+enum ddr_store_fmt { -+ STORE_RGB888 = 0, -+ STORE_RGBA_ARGB, -+ STORE_YUV420_8BIT, -+ STORE_YUV420_10BIT, -+ STORE_YUV422_8BIT, -+ STORE_YUV422_10BIT, -+ STORE_YUV444_8BIT, -+ STORE_YUV420_16BIT = 8, -+ STORE_YUV422_16BIT = 9, -+}; -+ -+enum hdmirx_reg_attr { -+ HDMIRX_ATTR_RW = 0, -+ HDMIRX_ATTR_RO = 1, -+ HDMIRX_ATTR_WO = 2, -+ HDMIRX_ATTR_RE = 3, -+}; -+ -+enum { -+ HDMIRX_RST_A, -+ HDMIRX_RST_P, -+ HDMIRX_RST_REF, -+ HDMIRX_RST_BIU, -+ HDMIRX_NUM_RST, -+}; -+ -+static const char * const pix_fmt_str[] = { -+ "RGB888", -+ "YUV422", -+ "YUV444", -+ "YUV420", -+}; -+ -+struct hdmirx_buffer { -+ struct vb2_v4l2_buffer vb; -+ struct list_head queue; -+ u32 buff_addr[VIDEO_MAX_PLANES]; -+}; -+ -+struct hdmirx_stream { -+ struct snps_hdmirx_dev *hdmirx_dev; -+ struct video_device vdev; -+ struct vb2_queue buf_queue; -+ struct list_head buf_head; -+ struct hdmirx_buffer *curr_buf; -+ struct hdmirx_buffer *next_buf; -+ struct v4l2_pix_format_mplane pixm; -+ const struct v4l2_format_info *out_finfo; -+ struct mutex vlock; /* to lock resources associated with video buffer and video device */ -+ spinlock_t vbq_lock; /* to lock video buffer queue */ -+ bool stopping; -+ wait_queue_head_t wq_stopped; -+ u32 frame_idx; -+ u32 line_flag_int_cnt; -+ u32 irq_stat; -+}; -+ -+struct snps_hdmirx_dev { -+ struct device *dev; -+ struct device *codec_dev; -+ struct hdmirx_stream stream; -+ struct v4l2_device v4l2_dev; -+ struct v4l2_ctrl_handler hdl; -+ struct v4l2_ctrl *detect_tx_5v_ctrl; -+ struct v4l2_ctrl *rgb_range; -+ struct v4l2_dv_timings timings; -+ struct gpio_desc *detect_5v_gpio; -+ struct work_struct work_wdt_config; -+ struct delayed_work delayed_work_hotplug; -+ struct delayed_work delayed_work_res_change; -+ struct delayed_work delayed_work_heartbeat; -+ struct cec_notifier *cec_notifier; -+ struct hdmirx_cec *cec; -+ struct mutex stream_lock; /* to lock video stream capture */ -+ struct mutex work_lock; /* to lock the critical section of hotplug event */ -+ struct reset_control_bulk_data resets[HDMIRX_NUM_RST]; -+ struct clk_bulk_data *clks; -+ struct regmap *grf; -+ struct regmap *vo1_grf; -+ struct completion cr_write_done; -+ struct completion timer_base_lock; -+ struct completion avi_pkt_rcv; -+ enum hdmirx_pix_fmt pix_fmt; -+ void __iomem *regs; -+ int hdmi_irq; -+ int dma_irq; -+ int det_irq; -+ bool hpd_trigger_level; -+ bool tmds_clk_ratio; -+ bool is_dvi_mode; -+ bool got_timing; -+ u32 num_clks; -+ u32 edid_blocks_written; -+ u32 cur_vic; -+ u32 cur_fmt_fourcc; -+ u32 color_depth; -+ u8 edid[EDID_BLOCK_SIZE * 2]; -+ hdmi_codec_plugged_cb plugged_cb; -+ spinlock_t rst_lock; /* to lock register access */ -+}; -+ -+static u8 edid_init_data_340M[] = { -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, -+ 0x49, 0x70, 0x88, 0x35, 0x01, 0x00, 0x00, 0x00, -+ 0x2D, 0x1F, 0x01, 0x03, 0x80, 0x78, 0x44, 0x78, -+ 0x0A, 0xCF, 0x74, 0xA3, 0x57, 0x4C, 0xB0, 0x23, -+ 0x09, 0x48, 0x4C, 0x21, 0x08, 0x00, 0x61, 0x40, -+ 0x01, 0x01, 0x81, 0x00, 0x95, 0x00, 0xA9, 0xC0, -+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A, -+ 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, -+ 0x45, 0x00, 0x20, 0xC2, 0x31, 0x00, 0x00, 0x1E, -+ 0x01, 0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, -+ 0x6E, 0x28, 0x55, 0x00, 0x20, 0xC2, 0x31, 0x00, -+ 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x52, -+ 0x4B, 0x2D, 0x55, 0x48, 0x44, 0x0A, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFD, -+ 0x00, 0x3B, 0x46, 0x1F, 0x8C, 0x3C, 0x00, 0x0A, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xA7, -+ -+ 0x02, 0x03, 0x2F, 0xD1, 0x51, 0x07, 0x16, 0x14, -+ 0x05, 0x01, 0x03, 0x12, 0x13, 0x84, 0x22, 0x1F, -+ 0x90, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x23, 0x09, -+ 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x67, 0x03, -+ 0x0C, 0x00, 0x30, 0x00, 0x10, 0x44, 0xE3, 0x05, -+ 0x03, 0x01, 0xE4, 0x0F, 0x00, 0x80, 0x01, 0x02, -+ 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, -+ 0x2C, 0x45, 0x00, 0x20, 0xC2, 0x31, 0x00, 0x00, -+ 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, -+}; -+ -+static const struct v4l2_dv_timings cea640x480 = V4L2_DV_BT_CEA_640X480P59_94; -+ -+static const struct v4l2_dv_timings_cap hdmirx_timings_cap = { -+ .type = V4L2_DV_BT_656_1120, -+ .reserved = { 0 }, -+ V4L2_INIT_BT_TIMINGS(640, 4096, /* min/max width */ -+ 480, 2160, /* min/max height */ -+ 20000000, 600000000, /* min/max pixelclock */ -+ /* standards */ -+ V4L2_DV_BT_STD_CEA861, -+ /* capabilities */ -+ V4L2_DV_BT_CAP_PROGRESSIVE | -+ V4L2_DV_BT_CAP_INTERLACED) -+}; -+ -+static void hdmirx_writel(struct snps_hdmirx_dev *hdmirx_dev, int reg, u32 val) -+{ -+ unsigned long lock_flags = 0; -+ -+ spin_lock_irqsave(&hdmirx_dev->rst_lock, lock_flags); -+ writel(val, hdmirx_dev->regs + reg); -+ spin_unlock_irqrestore(&hdmirx_dev->rst_lock, lock_flags); -+} -+ -+static u32 hdmirx_readl(struct snps_hdmirx_dev *hdmirx_dev, int reg) -+{ -+ unsigned long lock_flags = 0; -+ u32 val; -+ -+ spin_lock_irqsave(&hdmirx_dev->rst_lock, lock_flags); -+ val = readl(hdmirx_dev->regs + reg); -+ spin_unlock_irqrestore(&hdmirx_dev->rst_lock, lock_flags); -+ return val; -+} -+ -+static void hdmirx_reset_dma(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ unsigned long lock_flags = 0; -+ -+ spin_lock_irqsave(&hdmirx_dev->rst_lock, lock_flags); -+ reset_control_reset(hdmirx_dev->resets[0].rstc); -+ spin_unlock_irqrestore(&hdmirx_dev->rst_lock, lock_flags); -+} -+ -+static void hdmirx_update_bits(struct snps_hdmirx_dev *hdmirx_dev, int reg, -+ u32 mask, u32 data) -+{ -+ unsigned long lock_flags = 0; -+ u32 val; -+ -+ spin_lock_irqsave(&hdmirx_dev->rst_lock, lock_flags); -+ val = readl(hdmirx_dev->regs + reg) & ~mask; -+ val |= (data & mask); -+ writel(val, hdmirx_dev->regs + reg); -+ spin_unlock_irqrestore(&hdmirx_dev->rst_lock, lock_flags); -+} -+ -+static int hdmirx_subscribe_event(struct v4l2_fh *fh, -+ const struct v4l2_event_subscription *sub) -+{ -+ switch (sub->type) { -+ case V4L2_EVENT_SOURCE_CHANGE: -+ if (fh->vdev->vfl_dir == VFL_DIR_RX) -+ return v4l2_src_change_event_subscribe(fh, sub); -+ break; -+ case V4L2_EVENT_CTRL: -+ return v4l2_ctrl_subscribe_event(fh, sub); -+ default: -+ break; -+ } -+ -+ return -EINVAL; -+} -+ -+static bool tx_5v_power_present(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ bool ret; -+ int val, i, cnt; -+ -+ cnt = 0; -+ for (i = 0; i < 10; i++) { -+ usleep_range(1000, 1100); -+ val = gpiod_get_value(hdmirx_dev->detect_5v_gpio); -+ if (val > 0) -+ cnt++; -+ if (cnt >= DETECTION_THRESHOLD) -+ break; -+ } -+ -+ ret = (cnt >= DETECTION_THRESHOLD) ? true : false; -+ v4l2_dbg(3, debug, &hdmirx_dev->v4l2_dev, "%s: %d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static bool signal_not_lock(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ u32 mu_status, dma_st10, cmu_st; -+ -+ mu_status = hdmirx_readl(hdmirx_dev, MAINUNIT_STATUS); -+ dma_st10 = hdmirx_readl(hdmirx_dev, DMA_STATUS10); -+ cmu_st = hdmirx_readl(hdmirx_dev, CMU_STATUS); -+ -+ if ((mu_status & TMDSVALID_STABLE_ST) && -+ (dma_st10 & HDMIRX_LOCK) && -+ (cmu_st & TMDSQPCLK_LOCKED_ST)) -+ return false; -+ -+ return true; -+} -+ -+static void hdmirx_get_colordepth(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 val, color_depth_reg; -+ -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS11); -+ color_depth_reg = (val & HDMIRX_COLOR_DEPTH_MASK) >> 3; -+ -+ switch (color_depth_reg) { -+ case 0x4: -+ hdmirx_dev->color_depth = 24; -+ break; -+ case 0x5: -+ hdmirx_dev->color_depth = 30; -+ break; -+ case 0x6: -+ hdmirx_dev->color_depth = 36; -+ break; -+ case 0x7: -+ hdmirx_dev->color_depth = 48; -+ break; -+ default: -+ hdmirx_dev->color_depth = 24; -+ break; -+ } -+ -+ v4l2_dbg(1, debug, v4l2_dev, "%s: color_depth: %d, reg_val:%d\n", -+ __func__, hdmirx_dev->color_depth, color_depth_reg); -+} -+ -+static void hdmirx_get_pix_fmt(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 val; -+ -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS11); -+ hdmirx_dev->pix_fmt = val & HDMIRX_FORMAT_MASK; -+ -+ switch (hdmirx_dev->pix_fmt) { -+ case HDMIRX_RGB888: -+ hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_BGR24; -+ break; -+ case HDMIRX_YUV422: -+ hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_NV16; -+ break; -+ case HDMIRX_YUV444: -+ hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_NV24; -+ break; -+ case HDMIRX_YUV420: -+ hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_NV12; -+ break; -+ default: -+ v4l2_err(v4l2_dev, -+ "%s: err pix_fmt: %d, set RGB888 as default\n", -+ __func__, hdmirx_dev->pix_fmt); -+ hdmirx_dev->pix_fmt = HDMIRX_RGB888; -+ hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_BGR24; -+ break; -+ } -+ -+ v4l2_dbg(1, debug, v4l2_dev, "%s: pix_fmt: %s\n", __func__, -+ pix_fmt_str[hdmirx_dev->pix_fmt]); -+} -+ -+static void hdmirx_get_timings(struct snps_hdmirx_dev *hdmirx_dev, -+ struct v4l2_bt_timings *bt, bool from_dma) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 hact, vact, htotal, vtotal, fps; -+ u32 hfp, hs, hbp, vfp, vs, vbp; -+ u32 val; -+ -+ if (from_dma) { -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS2); -+ hact = (val >> 16) & 0xffff; -+ vact = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS3); -+ htotal = (val >> 16) & 0xffff; -+ vtotal = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS4); -+ hs = (val >> 16) & 0xffff; -+ vs = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS5); -+ hbp = (val >> 16) & 0xffff; -+ vbp = val & 0xffff; -+ hfp = htotal - hact - hs - hbp; -+ vfp = vtotal - vact - vs - vbp; -+ } else { -+ val = hdmirx_readl(hdmirx_dev, VMON_STATUS1); -+ hs = (val >> 16) & 0xffff; -+ hfp = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, VMON_STATUS2); -+ hbp = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, VMON_STATUS3); -+ htotal = (val >> 16) & 0xffff; -+ hact = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, VMON_STATUS4); -+ vs = (val >> 16) & 0xffff; -+ vfp = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, VMON_STATUS5); -+ vbp = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, VMON_STATUS6); -+ vtotal = (val >> 16) & 0xffff; -+ vact = val & 0xffff; -+ if (hdmirx_dev->pix_fmt == HDMIRX_YUV420) -+ hact *= 2; -+ } -+ if (hdmirx_dev->pix_fmt == HDMIRX_YUV420) -+ htotal *= 2; -+ fps = (bt->pixelclock + (htotal * vtotal) / 2) / (htotal * vtotal); -+ if (hdmirx_dev->pix_fmt == HDMIRX_YUV420) -+ fps *= 2; -+ bt->width = hact; -+ bt->height = vact; -+ bt->hfrontporch = hfp; -+ bt->hsync = hs; -+ bt->hbackporch = hbp; -+ bt->vfrontporch = vfp; -+ bt->vsync = vs; -+ bt->vbackporch = vbp; -+ -+ v4l2_dbg(1, debug, v4l2_dev, "get timings from %s\n", from_dma ? "dma" : "ctrl"); -+ v4l2_dbg(1, debug, v4l2_dev, "act:%ux%u, total:%ux%u, fps:%u, pixclk:%llu\n", -+ bt->width, bt->height, htotal, vtotal, fps, bt->pixelclock); -+ -+ v4l2_dbg(2, debug, v4l2_dev, "hfp:%u, hs:%u, hbp:%u, vfp:%u, vs:%u, vbp:%u\n", -+ bt->hfrontporch, bt->hsync, bt->hbackporch, -+ bt->vfrontporch, bt->vsync, bt->vbackporch); -+} -+ -+static bool hdmirx_check_timing_valid(struct v4l2_bt_timings *bt) -+{ -+ if (bt->width < 100 || bt->width > 5000 || -+ bt->height < 100 || bt->height > 5000) -+ return false; -+ -+ if (!bt->hsync || bt->hsync > 200 || -+ !bt->vsync || bt->vsync > 100) -+ return false; -+ -+ if (!bt->hbackporch || bt->hbackporch > 2000 || -+ !bt->vbackporch || bt->vbackporch > 2000) -+ return false; -+ -+ if (!bt->hfrontporch || bt->hfrontporch > 2000 || -+ !bt->vfrontporch || bt->vfrontporch > 2000) -+ return false; -+ -+ return true; -+} -+ -+static void hdmirx_get_avi_infoframe(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ union hdmi_infoframe frame = {}; -+ int err, i, b, itr = 0; -+ u8 aviif[3 + 7 * 4]; -+ u32 val; -+ -+ aviif[itr++] = HDMI_INFOFRAME_TYPE_AVI; -+ val = hdmirx_readl(hdmirx_dev, PKTDEC_AVIIF_PH2_1); -+ aviif[itr++] = val & 0xff; -+ aviif[itr++] = (val >> 8) & 0xff; -+ -+ for (i = 0; i < 7; i++) { -+ val = hdmirx_readl(hdmirx_dev, PKTDEC_AVIIF_PB3_0 + 4 * i); -+ -+ for (b = 0; b < 4; b++) -+ aviif[itr++] = (val >> (8 * b)) & 0xff; -+ } -+ -+ err = hdmi_infoframe_unpack(&frame, aviif, sizeof(aviif)); -+ if (err) { -+ v4l2_err(v4l2_dev, "failed to unpack AVI infoframe\n"); -+ return; -+ } -+ -+ v4l2_ctrl_s_ctrl(hdmirx_dev->rgb_range, frame.avi.quantization_range); -+} -+ -+/* -+ * When querying DV timings during preview, if the DMA's timing is stable, -+ * we retrieve the timings directly from the DMA. However, if the current -+ * resolution is negative, obtaining the timing from CTRL may require a -+ * change in the sync polarity, potentially leading to DMA errors. -+ */ -+static int hdmirx_get_detected_timings(struct snps_hdmirx_dev *hdmirx_dev, -+ struct v4l2_dv_timings *timings, -+ bool from_dma) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct v4l2_bt_timings *bt = &timings->bt; -+ u32 field_type, color_depth, deframer_st; -+ u32 val, tmdsqpclk_freq, pix_clk; -+ u64 tmp_data, tmds_clk; -+ -+ memset(timings, 0, sizeof(struct v4l2_dv_timings)); -+ timings->type = V4L2_DV_BT_656_1120; -+ -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS11); -+ field_type = (val & HDMIRX_TYPE_MASK) >> 7; -+ hdmirx_get_pix_fmt(hdmirx_dev); -+ bt->interlaced = field_type & BIT(0) ? V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; -+ val = hdmirx_readl(hdmirx_dev, PKTDEC_AVIIF_PB7_4); -+ hdmirx_dev->cur_vic = val | VIC_VAL_MASK; -+ hdmirx_get_colordepth(hdmirx_dev); -+ color_depth = hdmirx_dev->color_depth; -+ deframer_st = hdmirx_readl(hdmirx_dev, DEFRAMER_STATUS); -+ hdmirx_dev->is_dvi_mode = deframer_st & OPMODE_STS_MASK ? false : true; -+ tmdsqpclk_freq = hdmirx_readl(hdmirx_dev, CMU_TMDSQPCLK_FREQ); -+ tmds_clk = tmdsqpclk_freq * 4 * 1000; -+ tmp_data = tmds_clk * 24; -+ do_div(tmp_data, color_depth); -+ pix_clk = tmp_data; -+ bt->pixelclock = pix_clk; -+ -+ hdmirx_get_avi_infoframe(hdmirx_dev); -+ -+ hdmirx_get_timings(hdmirx_dev, bt, from_dma); -+ if (bt->interlaced == V4L2_DV_INTERLACED) { -+ bt->height *= 2; -+ bt->il_vsync = bt->vsync + 1; -+ } -+ -+ v4l2_dbg(2, debug, v4l2_dev, "tmds_clk:%llu\n", tmds_clk); -+ v4l2_dbg(1, debug, v4l2_dev, "interlace:%d, fmt:%d, vic:%d, color:%d, mode:%s\n", -+ bt->interlaced, hdmirx_dev->pix_fmt, -+ hdmirx_dev->cur_vic, hdmirx_dev->color_depth, -+ hdmirx_dev->is_dvi_mode ? "dvi" : "hdmi"); -+ v4l2_dbg(2, debug, v4l2_dev, "deframer_st:%#x\n", deframer_st); -+ -+ if (!hdmirx_check_timing_valid(bt)) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static bool port_no_link(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ return !tx_5v_power_present(hdmirx_dev); -+} -+ -+static int hdmirx_query_dv_timings(struct file *file, void *_fh, -+ struct v4l2_dv_timings *timings) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ int ret; -+ -+ if (port_no_link(hdmirx_dev)) { -+ v4l2_err(v4l2_dev, "%s: port has no link\n", __func__); -+ return -ENOLINK; -+ } -+ -+ if (signal_not_lock(hdmirx_dev)) { -+ v4l2_err(v4l2_dev, "%s: signal is not locked\n", __func__); -+ return -ENOLCK; -+ } -+ -+ ret = hdmirx_get_detected_timings(hdmirx_dev, timings, true); -+ if (ret) -+ return ret; -+ -+ if (debug) -+ v4l2_print_dv_timings(hdmirx_dev->v4l2_dev.name, -+ "query_dv_timings: ", timings, false); -+ -+ if (!v4l2_valid_dv_timings(timings, &hdmirx_timings_cap, NULL, NULL)) { -+ v4l2_dbg(1, debug, v4l2_dev, "%s: timings out of range\n", __func__); -+ return -ERANGE; -+ } -+ -+ return 0; -+} -+ -+static void hdmirx_hpd_ctrl(struct snps_hdmirx_dev *hdmirx_dev, bool en) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ v4l2_dbg(1, debug, v4l2_dev, "%s: %sable, hpd_trigger_level:%d\n", -+ __func__, en ? "en" : "dis", -+ hdmirx_dev->hpd_trigger_level); -+ hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, HPDLOW, en ? 0 : HPDLOW); -+ en = hdmirx_dev->hpd_trigger_level ? en : !en; -+ hdmirx_writel(hdmirx_dev, CORE_CONFIG, en); -+} -+ -+static int hdmirx_write_edid(struct snps_hdmirx_dev *hdmirx_dev, -+ struct v4l2_edid *edid, bool hpd_up) -+{ -+ u32 edid_len = edid->blocks * EDID_BLOCK_SIZE; -+ char data[300]; -+ u32 i; -+ -+ memset(edid->reserved, 0, sizeof(edid->reserved)); -+ if (edid->pad) -+ return -EINVAL; -+ -+ if (edid->start_block) -+ return -EINVAL; -+ -+ if (edid->blocks > EDID_NUM_BLOCKS_MAX) { -+ edid->blocks = EDID_NUM_BLOCKS_MAX; -+ return -E2BIG; -+ } -+ -+ if (!edid->blocks) { -+ hdmirx_dev->edid_blocks_written = 0; -+ return 0; -+ } -+ -+ cec_s_phys_addr_from_edid(hdmirx_dev->cec->adap, -+ (const struct edid *)edid->edid); -+ -+ memset(&hdmirx_dev->edid, 0, sizeof(hdmirx_dev->edid)); -+ hdmirx_hpd_ctrl(hdmirx_dev, false); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG11, -+ EDID_READ_EN_MASK | -+ EDID_WRITE_EN_MASK | -+ EDID_SLAVE_ADDR_MASK, -+ EDID_READ_EN(0) | -+ EDID_WRITE_EN(1) | -+ EDID_SLAVE_ADDR(0x50)); -+ for (i = 0; i < edid_len; i++) -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG10, edid->edid[i]); -+ -+ /* read out for debug */ -+ if (debug >= 2) { -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG11, -+ EDID_READ_EN_MASK | -+ EDID_WRITE_EN_MASK, -+ EDID_READ_EN(1) | -+ EDID_WRITE_EN(0)); -+ edid_len = edid_len > sizeof(data) ? sizeof(data) : edid_len; -+ memset(data, 0, sizeof(data)); -+ for (i = 0; i < edid_len; i++) -+ data[i] = hdmirx_readl(hdmirx_dev, DMA_STATUS14); -+ -+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, data, -+ edid_len, false); -+ } -+ -+ /* -+ * You must set EDID_READ_EN & EDID_WRITE_EN bit to 0, -+ * when the read/write edid operation is completed.Otherwise, it -+ * will affect the reading and writing of other registers -+ */ -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG11, -+ EDID_READ_EN_MASK | EDID_WRITE_EN_MASK, -+ EDID_READ_EN(0) | EDID_WRITE_EN(0)); -+ -+ hdmirx_dev->edid_blocks_written = edid->blocks; -+ memcpy(&hdmirx_dev->edid, edid->edid, edid->blocks * EDID_BLOCK_SIZE); -+ if (hpd_up) { -+ if (tx_5v_power_present(hdmirx_dev)) { -+ /* Add 100ms delay after updating the EDID as per HDMI specs */ -+ msleep(100); -+ hdmirx_hpd_ctrl(hdmirx_dev, true); -+ } -+ } -+ -+ return 0; -+} -+ -+/* -+ * Before clearing interrupt, we need to read the interrupt status. -+ */ -+static inline void hdmirx_clear_interrupt(struct snps_hdmirx_dev *hdmirx_dev, -+ u32 reg, u32 val) -+{ -+ /* (interrupt status register) = (interrupt clear register) - 0x8 */ -+ hdmirx_readl(hdmirx_dev, reg - 0x8); -+ hdmirx_writel(hdmirx_dev, reg, val); -+} -+ -+static void hdmirx_interrupts_setup(struct snps_hdmirx_dev *hdmirx_dev, bool en) -+{ -+ v4l2_dbg(1, debug, &hdmirx_dev->v4l2_dev, "%s: %sable\n", -+ __func__, en ? "en" : "dis"); -+ -+ /* Note: In DVI mode, it needs to be written twice to take effect. */ -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, AVPUNIT_0_INT_CLEAR, 0xffffffff); -+ -+ if (en) { -+ hdmirx_update_bits(hdmirx_dev, MAINUNIT_0_INT_MASK_N, -+ TMDSQPCLK_OFF_CHG | TMDSQPCLK_LOCKED_CHG, -+ TMDSQPCLK_OFF_CHG | TMDSQPCLK_LOCKED_CHG); -+ hdmirx_update_bits(hdmirx_dev, MAINUNIT_2_INT_MASK_N, -+ TMDSVALID_STABLE_CHG, TMDSVALID_STABLE_CHG); -+ hdmirx_update_bits(hdmirx_dev, AVPUNIT_0_INT_MASK_N, -+ CED_DYN_CNT_CH2_IRQ | -+ CED_DYN_CNT_CH1_IRQ | -+ CED_DYN_CNT_CH0_IRQ, -+ CED_DYN_CNT_CH2_IRQ | -+ CED_DYN_CNT_CH1_IRQ | -+ CED_DYN_CNT_CH0_IRQ); -+ } else { -+ hdmirx_writel(hdmirx_dev, MAINUNIT_0_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, MAINUNIT_2_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, AVPUNIT_0_INT_MASK_N, 0); -+ } -+} -+ -+static void hdmirx_plugout(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct arm_smccc_res res; -+ -+ hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, POWERPROVIDED, 0); -+ hdmirx_interrupts_setup(hdmirx_dev, false); -+ hdmirx_hpd_ctrl(hdmirx_dev, false); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, 0); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, -+ LINE_FLAG_INT_EN | -+ HDMIRX_DMA_IDLE_INT | -+ HDMIRX_LOCK_DISABLE_INT | -+ LAST_FRAME_AXI_UNFINISH_INT_EN | -+ FIFO_OVERFLOW_INT_EN | -+ FIFO_UNDERFLOW_INT_EN | -+ HDMIRX_AXI_ERROR_INT_EN, 0); -+ hdmirx_reset_dma(hdmirx_dev); -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, HDMI_DISABLE | PHY_RESET | -+ PHY_PDDQ, HDMI_DISABLE); -+ hdmirx_writel(hdmirx_dev, PHYCREG_CONFIG0, 0x0); -+ cancel_delayed_work(&hdmirx_dev->delayed_work_res_change); -+ cancel_delayed_work_sync(&hdmirx_dev->delayed_work_heartbeat); -+ flush_work(&hdmirx_dev->work_wdt_config); -+ arm_smccc_smc(SIP_WDT_CFG, WDT_STOP, 0, 0, 0, 0, 0, 0, &res); -+} -+ -+static int hdmirx_set_edid(struct file *file, void *fh, struct v4l2_edid *edid) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct arm_smccc_res res; -+ int ret; -+ -+ disable_irq(hdmirx_dev->hdmi_irq); -+ disable_irq(hdmirx_dev->dma_irq); -+ arm_smccc_smc(RK_SIP_FIQ_CTRL, RK_SIP_FIQ_CTRL_FIQ_DIS, -+ RK_IRQ_HDMIRX_HDMI, 0, 0, 0, 0, 0, &res); -+ -+ if (tx_5v_power_present(hdmirx_dev)) -+ hdmirx_plugout(hdmirx_dev); -+ ret = hdmirx_write_edid(hdmirx_dev, edid, false); -+ if (ret) -+ return ret; -+ -+ enable_irq(hdmirx_dev->hdmi_irq); -+ enable_irq(hdmirx_dev->dma_irq); -+ arm_smccc_smc(RK_SIP_FIQ_CTRL, RK_SIP_FIQ_CTRL_FIQ_EN, -+ RK_IRQ_HDMIRX_HDMI, 0, 0, 0, 0, 0, &res); -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_hotplug, -+ msecs_to_jiffies(500)); -+ return 0; -+} -+ -+static int hdmirx_get_edid(struct file *file, void *fh, struct v4l2_edid *edid) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ memset(edid->reserved, 0, sizeof(edid->reserved)); -+ -+ if (edid->pad) -+ return -EINVAL; -+ -+ if (!edid->start_block && !edid->blocks) { -+ edid->blocks = hdmirx_dev->edid_blocks_written; -+ return 0; -+ } -+ -+ if (!hdmirx_dev->edid_blocks_written) -+ return -ENODATA; -+ -+ if (edid->start_block >= hdmirx_dev->edid_blocks_written || !edid->blocks) -+ return -EINVAL; -+ -+ if (edid->start_block + edid->blocks > hdmirx_dev->edid_blocks_written) -+ edid->blocks = hdmirx_dev->edid_blocks_written - edid->start_block; -+ -+ memcpy(edid->edid, &hdmirx_dev->edid, edid->blocks * EDID_BLOCK_SIZE); -+ -+ v4l2_dbg(1, debug, v4l2_dev, "%s: read EDID:\n", __func__); -+ if (debug > 0) -+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, -+ edid->edid, edid->blocks * EDID_BLOCK_SIZE, false); -+ -+ return 0; -+} -+ -+static int hdmirx_g_parm(struct file *file, void *priv, -+ struct v4l2_streamparm *parm) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_fract fps; -+ -+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) -+ return -EINVAL; -+ -+ fps = v4l2_calc_timeperframe(&hdmirx_dev->timings); -+ parm->parm.capture.timeperframe.numerator = fps.numerator; -+ parm->parm.capture.timeperframe.denominator = fps.denominator; -+ -+ return 0; -+} -+ -+static int hdmirx_dv_timings_cap(struct file *file, void *fh, -+ struct v4l2_dv_timings_cap *cap) -+{ -+ *cap = hdmirx_timings_cap; -+ return 0; -+} -+ -+static int hdmirx_enum_dv_timings(struct file *file, void *_fh, -+ struct v4l2_enum_dv_timings *timings) -+{ -+ return v4l2_enum_dv_timings_cap(timings, &hdmirx_timings_cap, NULL, NULL); -+} -+ -+static void hdmirx_scdc_init(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ hdmirx_update_bits(hdmirx_dev, I2C_SLAVE_CONFIG1, -+ I2C_SDA_OUT_HOLD_VALUE_QST_MASK | -+ I2C_SDA_IN_HOLD_VALUE_QST_MASK, -+ I2C_SDA_OUT_HOLD_VALUE_QST(0x80) | -+ I2C_SDA_IN_HOLD_VALUE_QST(0x15)); -+ hdmirx_update_bits(hdmirx_dev, SCDC_REGBANK_CONFIG0, -+ SCDC_SINKVERSION_QST_MASK, -+ SCDC_SINKVERSION_QST(1)); -+} -+ -+static int wait_reg_bit_status(struct snps_hdmirx_dev *hdmirx_dev, u32 reg, -+ u32 bit_mask, u32 expect_val, bool is_grf, -+ u32 ms) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 i, val; -+ -+ for (i = 0; i < ms; i++) { -+ if (is_grf) -+ regmap_read(hdmirx_dev->grf, reg, &val); -+ else -+ val = hdmirx_readl(hdmirx_dev, reg); -+ -+ if ((val & bit_mask) == expect_val) { -+ v4l2_dbg(2, debug, v4l2_dev, -+ "%s: i:%d, time: %dms\n", __func__, i, ms); -+ break; -+ } -+ usleep_range(1000, 1010); -+ } -+ -+ if (i == ms) -+ return -1; -+ -+ return 0; -+} -+ -+static int hdmirx_phy_register_write(struct snps_hdmirx_dev *hdmirx_dev, -+ u32 phy_reg, u32 val) -+{ -+ struct device *dev = hdmirx_dev->dev; -+ -+ reinit_completion(&hdmirx_dev->cr_write_done); -+ /* clear irq status */ -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); -+ /* en irq */ -+ hdmirx_update_bits(hdmirx_dev, MAINUNIT_2_INT_MASK_N, -+ PHYCREG_CR_WRITE_DONE, PHYCREG_CR_WRITE_DONE); -+ /* write phy reg addr */ -+ hdmirx_writel(hdmirx_dev, PHYCREG_CONFIG1, phy_reg); -+ /* write phy reg val */ -+ hdmirx_writel(hdmirx_dev, PHYCREG_CONFIG2, val); -+ /* config write enable */ -+ hdmirx_writel(hdmirx_dev, PHYCREG_CONTROL, PHYCREG_CR_PARA_WRITE_P); -+ -+ if (!wait_for_completion_timeout(&hdmirx_dev->cr_write_done, -+ msecs_to_jiffies(20))) { -+ dev_err(dev, "%s wait cr write done failed\n", __func__); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static void hdmirx_tmds_clk_ratio_config(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 val; -+ -+ val = hdmirx_readl(hdmirx_dev, SCDC_REGBANK_STATUS1); -+ v4l2_dbg(3, debug, v4l2_dev, "%s: scdc_regbank_st:%#x\n", __func__, val); -+ hdmirx_dev->tmds_clk_ratio = (val & SCDC_TMDSBITCLKRATIO) > 0; -+ -+ if (hdmirx_dev->tmds_clk_ratio) { -+ v4l2_dbg(3, debug, v4l2_dev, "%s: HDMITX greater than 3.4Gbps\n", __func__); -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, -+ TMDS_CLOCK_RATIO, TMDS_CLOCK_RATIO); -+ } else { -+ v4l2_dbg(3, debug, v4l2_dev, "%s: HDMITX less than 3.4Gbps\n", __func__); -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, -+ TMDS_CLOCK_RATIO, 0); -+ } -+} -+ -+static void hdmirx_phy_config(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct device *dev = hdmirx_dev->dev; -+ -+ hdmirx_clear_interrupt(hdmirx_dev, SCDC_INT_CLEAR, 0xffffffff); -+ hdmirx_update_bits(hdmirx_dev, SCDC_INT_MASK_N, SCDCTMDSCCFG_CHG, -+ SCDCTMDSCCFG_CHG); -+ /* cr_para_clk 24M */ -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, REFFREQ_SEL_MASK, REFFREQ_SEL(0)); -+ /* rx data width 40bit valid */ -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, RXDATA_WIDTH, RXDATA_WIDTH); -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, PHY_RESET, PHY_RESET); -+ usleep_range(100, 110); -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, PHY_RESET, 0); -+ usleep_range(100, 110); -+ /* select cr para interface */ -+ hdmirx_writel(hdmirx_dev, PHYCREG_CONFIG0, 0x3); -+ -+ if (wait_reg_bit_status(hdmirx_dev, SYS_GRF_SOC_STATUS1, -+ HDMIRXPHY_SRAM_INIT_DONE, -+ HDMIRXPHY_SRAM_INIT_DONE, true, 10)) -+ dev_err(dev, "%s: phy SRAM init failed\n", __func__); -+ -+ regmap_write(hdmirx_dev->grf, SYS_GRF_SOC_CON1, -+ (HDMIRXPHY_SRAM_EXT_LD_DONE << 16) | -+ HDMIRXPHY_SRAM_EXT_LD_DONE); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 2); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 3); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 2); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 2); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 3); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 2); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 0); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 1); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 0); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 0); -+ -+ hdmirx_phy_register_write(hdmirx_dev, -+ HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_3_REG, -+ CDR_SETTING_BOUNDARY_3_DEFAULT); -+ hdmirx_phy_register_write(hdmirx_dev, -+ HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_4_REG, -+ CDR_SETTING_BOUNDARY_4_DEFAULT); -+ hdmirx_phy_register_write(hdmirx_dev, -+ HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_5_REG, -+ CDR_SETTING_BOUNDARY_5_DEFAULT); -+ hdmirx_phy_register_write(hdmirx_dev, -+ HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_6_REG, -+ CDR_SETTING_BOUNDARY_6_DEFAULT); -+ hdmirx_phy_register_write(hdmirx_dev, -+ HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_7_REG, -+ CDR_SETTING_BOUNDARY_7_DEFAULT); -+ -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, PHY_PDDQ, 0); -+ if (wait_reg_bit_status(hdmirx_dev, PHY_STATUS, PDDQ_ACK, 0, false, 10)) -+ dev_err(dev, "%s: wait pddq ack failed\n", __func__); -+ -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, HDMI_DISABLE, 0); -+ if (wait_reg_bit_status(hdmirx_dev, PHY_STATUS, HDMI_DISABLE_ACK, 0, -+ false, 50)) -+ dev_err(dev, "%s: wait hdmi disable ack failed\n", __func__); -+ -+ hdmirx_tmds_clk_ratio_config(hdmirx_dev); -+} -+ -+static void hdmirx_controller_init(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct device *dev = hdmirx_dev->dev; -+ -+ reinit_completion(&hdmirx_dev->timer_base_lock); -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); -+ /* en irq */ -+ hdmirx_update_bits(hdmirx_dev, MAINUNIT_0_INT_MASK_N, -+ TIMER_BASE_LOCKED_IRQ, TIMER_BASE_LOCKED_IRQ); -+ /* write irefclk freq */ -+ hdmirx_writel(hdmirx_dev, GLOBAL_TIMER_REF_BASE, IREF_CLK_FREQ_HZ); -+ -+ if (!wait_for_completion_timeout(&hdmirx_dev->timer_base_lock, -+ msecs_to_jiffies(20))) -+ dev_err(dev, "%s wait timer base lock failed\n", __func__); -+ -+ hdmirx_update_bits(hdmirx_dev, CMU_CONFIG0, -+ TMDSQPCLK_STABLE_FREQ_MARGIN_MASK | -+ AUDCLK_STABLE_FREQ_MARGIN_MASK, -+ TMDSQPCLK_STABLE_FREQ_MARGIN(2) | -+ AUDCLK_STABLE_FREQ_MARGIN(1)); -+ hdmirx_update_bits(hdmirx_dev, DESCRAND_EN_CONTROL, -+ SCRAMB_EN_SEL_QST_MASK, SCRAMB_EN_SEL_QST(1)); -+ hdmirx_update_bits(hdmirx_dev, CED_CONFIG, -+ CED_VIDDATACHECKEN_QST | -+ CED_DATAISCHECKEN_QST | -+ CED_GBCHECKEN_QST | -+ CED_CTRLCHECKEN_QST | -+ CED_CHLOCKMAXER_QST_MASK, -+ CED_VIDDATACHECKEN_QST | -+ CED_GBCHECKEN_QST | -+ CED_CTRLCHECKEN_QST | -+ CED_CHLOCKMAXER_QST(0x10)); -+ hdmirx_update_bits(hdmirx_dev, DEFRAMER_CONFIG0, -+ VS_REMAPFILTER_EN_QST | VS_FILTER_ORDER_QST_MASK, -+ VS_REMAPFILTER_EN_QST | VS_FILTER_ORDER_QST(0x3)); -+} -+ -+static void hdmirx_set_negative_pol(struct snps_hdmirx_dev *hdmirx_dev, bool en) -+{ -+ if (en) { -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, -+ VSYNC_TOGGLE_EN | HSYNC_TOGGLE_EN, -+ VSYNC_TOGGLE_EN | HSYNC_TOGGLE_EN); -+ hdmirx_update_bits(hdmirx_dev, VIDEO_CONFIG2, -+ VPROC_VSYNC_POL_OVR_VALUE | -+ VPROC_VSYNC_POL_OVR_EN | -+ VPROC_HSYNC_POL_OVR_VALUE | -+ VPROC_HSYNC_POL_OVR_EN, -+ VPROC_VSYNC_POL_OVR_EN | -+ VPROC_HSYNC_POL_OVR_EN); -+ return; -+ } -+ -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, -+ VSYNC_TOGGLE_EN | HSYNC_TOGGLE_EN, 0); -+ -+ hdmirx_update_bits(hdmirx_dev, VIDEO_CONFIG2, -+ VPROC_VSYNC_POL_OVR_VALUE | -+ VPROC_VSYNC_POL_OVR_EN | -+ VPROC_HSYNC_POL_OVR_VALUE | -+ VPROC_HSYNC_POL_OVR_EN, 0); -+} -+ -+static int hdmirx_try_to_get_timings(struct snps_hdmirx_dev *hdmirx_dev, -+ struct v4l2_dv_timings *timings, -+ int try_cnt) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ int i, cnt = 0, fail_cnt = 0, ret = 0; -+ bool from_dma = false; -+ -+ hdmirx_set_negative_pol(hdmirx_dev, false); -+ for (i = 0; i < try_cnt; i++) { -+ ret = hdmirx_get_detected_timings(hdmirx_dev, timings, from_dma); -+ if (ret) { -+ cnt = 0; -+ fail_cnt++; -+ if (fail_cnt > 3) { -+ hdmirx_set_negative_pol(hdmirx_dev, true); -+ from_dma = true; -+ } -+ } else { -+ cnt++; -+ } -+ if (cnt >= 5) -+ break; -+ -+ usleep_range(10 * 1000, 10 * 1100); -+ } -+ -+ if (try_cnt > 8 && cnt < 5) -+ v4l2_dbg(1, debug, v4l2_dev, "%s: res not stable\n", __func__); -+ -+ return ret; -+} -+ -+static void hdmirx_format_change(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_dv_timings timings; -+ struct hdmirx_stream *stream = &hdmirx_dev->stream; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ const struct v4l2_event ev_src_chg = { -+ .type = V4L2_EVENT_SOURCE_CHANGE, -+ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, -+ }; -+ -+ if (hdmirx_try_to_get_timings(hdmirx_dev, &timings, 20)) { -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_hotplug, -+ msecs_to_jiffies(20)); -+ return; -+ } -+ -+ hdmirx_dev->got_timing = true; -+ v4l2_dbg(1, debug, v4l2_dev, "%s: queue res_chg_event\n", __func__); -+ v4l2_event_queue(&stream->vdev, &ev_src_chg); -+} -+ -+static void hdmirx_set_ddr_store_fmt(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ enum ddr_store_fmt store_fmt; -+ u32 dma_cfg1; -+ -+ switch (hdmirx_dev->pix_fmt) { -+ case HDMIRX_RGB888: -+ store_fmt = STORE_RGB888; -+ break; -+ case HDMIRX_YUV444: -+ store_fmt = STORE_YUV444_8BIT; -+ break; -+ case HDMIRX_YUV422: -+ store_fmt = STORE_YUV422_8BIT; -+ break; -+ case HDMIRX_YUV420: -+ store_fmt = STORE_YUV420_8BIT; -+ break; -+ default: -+ store_fmt = STORE_RGB888; -+ break; -+ } -+ -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG1, -+ DDR_STORE_FORMAT_MASK, DDR_STORE_FORMAT(store_fmt)); -+ dma_cfg1 = hdmirx_readl(hdmirx_dev, DMA_CONFIG1); -+ v4l2_dbg(1, debug, v4l2_dev, "%s: pix_fmt: %s, DMA_CONFIG1:%#x\n", -+ __func__, pix_fmt_str[hdmirx_dev->pix_fmt], dma_cfg1); -+} -+ -+static int hdmirx_wait_lock_and_get_timing(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 mu_status, scdc_status, dma_st10, cmu_st; -+ u32 i; -+ -+ for (i = 0; i < 300; i++) { -+ mu_status = hdmirx_readl(hdmirx_dev, MAINUNIT_STATUS); -+ scdc_status = hdmirx_readl(hdmirx_dev, SCDC_REGBANK_STATUS3); -+ dma_st10 = hdmirx_readl(hdmirx_dev, DMA_STATUS10); -+ cmu_st = hdmirx_readl(hdmirx_dev, CMU_STATUS); -+ -+ if ((mu_status & TMDSVALID_STABLE_ST) && -+ (dma_st10 & HDMIRX_LOCK) && -+ (cmu_st & TMDSQPCLK_LOCKED_ST)) -+ break; -+ -+ if (!tx_5v_power_present(hdmirx_dev)) { -+ v4l2_err(v4l2_dev, "%s: HDMI pull out, return\n", __func__); -+ return -1; -+ } -+ -+ hdmirx_tmds_clk_ratio_config(hdmirx_dev); -+ } -+ -+ if (i == 300) { -+ v4l2_err(v4l2_dev, "%s: signal not lock, tmds_clk_ratio:%d\n", -+ __func__, hdmirx_dev->tmds_clk_ratio); -+ v4l2_err(v4l2_dev, "%s: mu_st:%#x, scdc_st:%#x, dma_st10:%#x\n", -+ __func__, mu_status, scdc_status, dma_st10); -+ return -1; -+ } -+ -+ v4l2_info(v4l2_dev, "%s: signal lock ok, i:%d\n", __func__, i); -+ hdmirx_writel(hdmirx_dev, GLOBAL_SWRESET_REQUEST, DATAPATH_SWRESETREQ); -+ -+ reinit_completion(&hdmirx_dev->avi_pkt_rcv); -+ hdmirx_clear_interrupt(hdmirx_dev, PKT_2_INT_CLEAR, 0xffffffff); -+ hdmirx_update_bits(hdmirx_dev, PKT_2_INT_MASK_N, -+ PKTDEC_AVIIF_RCV_IRQ, PKTDEC_AVIIF_RCV_IRQ); -+ -+ if (!wait_for_completion_timeout(&hdmirx_dev->avi_pkt_rcv, -+ msecs_to_jiffies(300))) { -+ v4l2_err(v4l2_dev, "%s wait avi_pkt_rcv failed\n", __func__); -+ hdmirx_update_bits(hdmirx_dev, PKT_2_INT_MASK_N, -+ PKTDEC_AVIIF_RCV_IRQ, 0); -+ } -+ -+ usleep_range(50 * 1000, 50 * 1010); -+ hdmirx_format_change(hdmirx_dev); -+ -+ return 0; -+} -+ -+static void hdmirx_dma_config(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ hdmirx_set_ddr_store_fmt(hdmirx_dev); -+ -+ /* Note: uv_swap, rb can not swap, doc err*/ -+ if (hdmirx_dev->cur_fmt_fourcc != V4L2_PIX_FMT_NV16) -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, RB_SWAP_EN, RB_SWAP_EN); -+ else -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, RB_SWAP_EN, 0); -+ -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG7, -+ LOCK_FRAME_NUM_MASK, -+ LOCK_FRAME_NUM(2)); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG1, -+ UV_WID_MASK | Y_WID_MASK | ABANDON_EN, -+ UV_WID(1) | Y_WID(2) | ABANDON_EN); -+} -+ -+static void hdmirx_submodule_init(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ /* Note: if not config HDCP2_CONFIG, there will be some errors; */ -+ hdmirx_update_bits(hdmirx_dev, HDCP2_CONFIG, -+ HDCP2_SWITCH_OVR_VALUE | -+ HDCP2_SWITCH_OVR_EN, -+ HDCP2_SWITCH_OVR_EN); -+ hdmirx_scdc_init(hdmirx_dev); -+ hdmirx_controller_init(hdmirx_dev); -+} -+ -+static int hdmirx_enum_input(struct file *file, void *priv, -+ struct v4l2_input *input) -+{ -+ if (input->index > 0) -+ return -EINVAL; -+ -+ input->type = V4L2_INPUT_TYPE_CAMERA; -+ input->std = 0; -+ strscpy(input->name, "HDMI IN", sizeof(input->name)); -+ input->capabilities = V4L2_IN_CAP_DV_TIMINGS; -+ -+ return 0; -+} -+ -+static int hdmirx_get_input(struct file *file, void *priv, unsigned int *i) -+{ -+ *i = 0; -+ return 0; -+} -+ -+static int hdmirx_set_input(struct file *file, void *priv, unsigned int i) -+{ -+ if (i) -+ return -EINVAL; -+ return 0; -+} -+ -+static void hdmirx_set_fmt(struct hdmirx_stream *stream, -+ struct v4l2_pix_format_mplane *pixm, bool try) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct v4l2_bt_timings *bt = &hdmirx_dev->timings.bt; -+ const struct v4l2_format_info *finfo; -+ unsigned int imagesize = 0; -+ int i; -+ -+ memset(&pixm->plane_fmt[0], 0, sizeof(struct v4l2_plane_pix_format)); -+ finfo = v4l2_format_info(pixm->pixelformat); -+ if (!finfo) { -+ finfo = v4l2_format_info(V4L2_PIX_FMT_BGR24); -+ v4l2_dbg(1, debug, v4l2_dev, -+ "%s: set_fmt:%#x not supported, use def_fmt:%x\n", -+ __func__, pixm->pixelformat, finfo->format); -+ } -+ -+ if (!bt->width || !bt->height) -+ v4l2_dbg(1, debug, v4l2_dev, "%s: invalid resolution:%#xx%#x\n", -+ __func__, bt->width, bt->height); -+ -+ pixm->pixelformat = finfo->format; -+ pixm->width = bt->width; -+ pixm->height = bt->height; -+ pixm->num_planes = finfo->mem_planes; -+ pixm->quantization = V4L2_QUANTIZATION_DEFAULT; -+ pixm->colorspace = V4L2_COLORSPACE_SRGB; -+ pixm->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; -+ -+ if (bt->interlaced == V4L2_DV_INTERLACED) -+ pixm->field = V4L2_FIELD_INTERLACED_TB; -+ else -+ pixm->field = V4L2_FIELD_NONE; -+ -+ memset(pixm->reserved, 0, sizeof(pixm->reserved)); -+ -+ v4l2_fill_pixfmt_mp(pixm, finfo->format, pixm->width, pixm->height); -+ -+ for (i = 0; i < pixm->num_planes; i++) { -+ struct v4l2_plane_pix_format *plane_fmt; -+ int width, height, bpl, size, bpp = 0; -+ -+ if (!i) { -+ width = pixm->width; -+ height = pixm->height; -+ } else { -+ width = pixm->width / finfo->hdiv; -+ height = pixm->height / finfo->vdiv; -+ } -+ -+ switch (finfo->format) { -+ case V4L2_PIX_FMT_NV24: -+ case V4L2_PIX_FMT_NV16: -+ case V4L2_PIX_FMT_NV12: -+ case V4L2_PIX_FMT_BGR24: -+ bpp = finfo->bpp[i]; -+ break; -+ default: -+ v4l2_dbg(1, debug, v4l2_dev, -+ "fourcc: %#x is not supported\n", -+ finfo->format); -+ break; -+ } -+ -+ bpl = ALIGN(width * bpp, MEMORY_ALIGN_ROUND_UP_BYTES); -+ size = bpl * height; -+ imagesize += size; -+ -+ if (finfo->mem_planes > i) { -+ /* Set bpl and size for each mplane */ -+ plane_fmt = pixm->plane_fmt + i; -+ plane_fmt->bytesperline = bpl; -+ plane_fmt->sizeimage = size; -+ } -+ -+ v4l2_dbg(1, debug, v4l2_dev, -+ "C-Plane %i size: %d, Total imagesize: %d\n", -+ i, size, imagesize); -+ } -+ -+ /* Convert to non-MPLANE format as we want to unify non-MPLANE and MPLANE */ -+ if (finfo->mem_planes == 1) -+ pixm->plane_fmt[0].sizeimage = imagesize; -+ -+ if (!try) { -+ stream->out_finfo = finfo; -+ stream->pixm = *pixm; -+ v4l2_dbg(1, debug, v4l2_dev, -+ "%s: req(%d, %d), out(%d, %d), fmt:%#x\n", __func__, -+ pixm->width, pixm->height, stream->pixm.width, -+ stream->pixm.height, finfo->format); -+ } -+} -+ -+static int hdmirx_enum_fmt_vid_cap_mplane(struct file *file, void *priv, -+ struct v4l2_fmtdesc *f) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ -+ if (f->index >= 1) -+ return -EINVAL; -+ -+ f->pixelformat = hdmirx_dev->cur_fmt_fourcc; -+ -+ return 0; -+} -+ -+static int hdmirx_s_fmt_vid_cap_mplane(struct file *file, -+ void *priv, struct v4l2_format *f) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ if (vb2_is_busy(&stream->buf_queue)) { -+ v4l2_err(v4l2_dev, "%s: queue busy\n", __func__); -+ return -EBUSY; -+ } -+ -+ hdmirx_set_fmt(stream, &f->fmt.pix_mp, false); -+ -+ return 0; -+} -+ -+static int hdmirx_g_fmt_vid_cap_mplane(struct file *file, void *fh, -+ struct v4l2_format *f) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_pix_format_mplane pixm = {}; -+ -+ pixm.pixelformat = hdmirx_dev->cur_fmt_fourcc; -+ hdmirx_set_fmt(stream, &pixm, true); -+ f->fmt.pix_mp = pixm; -+ -+ return 0; -+} -+ -+static int hdmirx_g_dv_timings(struct file *file, void *_fh, -+ struct v4l2_dv_timings *timings) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 dma_cfg1; -+ -+ *timings = hdmirx_dev->timings; -+ dma_cfg1 = hdmirx_readl(hdmirx_dev, DMA_CONFIG1); -+ v4l2_dbg(1, debug, v4l2_dev, "%s: pix_fmt: %s, DMA_CONFIG1:%#x\n", -+ __func__, pix_fmt_str[hdmirx_dev->pix_fmt], dma_cfg1); -+ -+ return 0; -+} -+ -+static int hdmirx_s_dv_timings(struct file *file, void *_fh, -+ struct v4l2_dv_timings *timings) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ if (!timings) -+ return -EINVAL; -+ -+ if (debug) -+ v4l2_print_dv_timings(hdmirx_dev->v4l2_dev.name, -+ "s_dv_timings: ", timings, false); -+ -+ if (!v4l2_valid_dv_timings(timings, &hdmirx_timings_cap, NULL, NULL)) { -+ v4l2_dbg(1, debug, v4l2_dev, -+ "%s: timings out of range\n", __func__); -+ return -ERANGE; -+ } -+ -+ /* Check if the timings are part of the CEA-861 timings. */ -+ v4l2_find_dv_timings_cap(timings, &hdmirx_timings_cap, 0, NULL, NULL); -+ -+ if (v4l2_match_dv_timings(&hdmirx_dev->timings, timings, 0, false)) { -+ v4l2_dbg(1, debug, v4l2_dev, "%s: no change\n", __func__); -+ return 0; -+ } -+ -+ /* -+ * Changing the timings implies a format change, which is not allowed -+ * while buffers for use with streaming have already been allocated. -+ */ -+ if (vb2_is_busy(&stream->buf_queue)) -+ return -EBUSY; -+ -+ hdmirx_dev->timings = *timings; -+ /* Update the internal format */ -+ hdmirx_set_fmt(stream, &stream->pixm, false); -+ -+ return 0; -+} -+ -+static int hdmirx_querycap(struct file *file, void *priv, -+ struct v4l2_capability *cap) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct device *dev = stream->hdmirx_dev->dev; -+ -+ strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); -+ strscpy(cap->card, dev->driver->name, sizeof(cap->card)); -+ -+ return 0; -+} -+ -+static int hdmirx_queue_setup(struct vb2_queue *queue, -+ unsigned int *num_buffers, -+ unsigned int *num_planes, -+ unsigned int sizes[], -+ struct device *alloc_ctxs[]) -+{ -+ struct hdmirx_stream *stream = vb2_get_drv_priv(queue); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ const struct v4l2_pix_format_mplane *pixm = NULL; -+ const struct v4l2_format_info *out_finfo; -+ u32 i, height; -+ -+ pixm = &stream->pixm; -+ out_finfo = stream->out_finfo; -+ -+ if (!num_planes || !out_finfo) { -+ v4l2_err(v4l2_dev, "%s: out_fmt not set\n", __func__); -+ return -EINVAL; -+ } -+ -+ if (*num_planes) { -+ if (*num_planes != pixm->num_planes) -+ return -EINVAL; -+ -+ for (i = 0; i < *num_planes; i++) -+ if (sizes[i] < pixm->plane_fmt[i].sizeimage) -+ return -EINVAL; -+ return 0; -+ } -+ -+ *num_planes = out_finfo->mem_planes; -+ height = pixm->height; -+ -+ for (i = 0; i < out_finfo->mem_planes; i++) -+ sizes[i] = pixm->plane_fmt[i].sizeimage; -+ -+ v4l2_dbg(1, debug, v4l2_dev, "%s: count %d, size %d\n", -+ v4l2_type_names[queue->type], *num_buffers, sizes[0]); -+ -+ return 0; -+} -+ -+/* -+ * The vb2_buffer are stored in hdmirx_buffer, in order to unify -+ * mplane buffer and none-mplane buffer. -+ */ -+static void hdmirx_buf_queue(struct vb2_buffer *vb) -+{ -+ const struct v4l2_format_info *out_finfo; -+ struct vb2_v4l2_buffer *vbuf; -+ struct hdmirx_buffer *hdmirx_buf; -+ struct vb2_queue *queue; -+ struct hdmirx_stream *stream; -+ const struct v4l2_pix_format_mplane *pixm; -+ unsigned long lock_flags = 0; -+ int i; -+ -+ vbuf = to_vb2_v4l2_buffer(vb); -+ hdmirx_buf = container_of(vbuf, struct hdmirx_buffer, vb); -+ queue = vb->vb2_queue; -+ stream = vb2_get_drv_priv(queue); -+ pixm = &stream->pixm; -+ out_finfo = stream->out_finfo; -+ -+ memset(hdmirx_buf->buff_addr, 0, sizeof(hdmirx_buf->buff_addr)); -+ -+ /* -+ * If mplanes > 1, every c-plane has its own m-plane, -+ * otherwise, multiple c-planes are in the same m-plane -+ */ -+ for (i = 0; i < out_finfo->mem_planes; i++) -+ hdmirx_buf->buff_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); -+ -+ if (out_finfo->mem_planes == 1) { -+ if (out_finfo->comp_planes == 1) { -+ hdmirx_buf->buff_addr[HDMIRX_PLANE_CBCR] = -+ hdmirx_buf->buff_addr[HDMIRX_PLANE_Y]; -+ } else { -+ for (i = 0; i < out_finfo->comp_planes - 1; i++) -+ hdmirx_buf->buff_addr[i + 1] = -+ hdmirx_buf->buff_addr[i] + -+ pixm->plane_fmt[i].bytesperline * -+ pixm->height; -+ } -+ } -+ -+ spin_lock_irqsave(&stream->vbq_lock, lock_flags); -+ list_add_tail(&hdmirx_buf->queue, &stream->buf_head); -+ spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); -+} -+ -+static void return_all_buffers(struct hdmirx_stream *stream, -+ enum vb2_buffer_state state) -+{ -+ struct hdmirx_buffer *buf; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&stream->vbq_lock, flags); -+ if (stream->curr_buf) -+ list_add_tail(&stream->curr_buf->queue, &stream->buf_head); -+ if (stream->next_buf && stream->next_buf != stream->curr_buf) -+ list_add_tail(&stream->next_buf->queue, &stream->buf_head); -+ stream->curr_buf = NULL; -+ stream->next_buf = NULL; -+ -+ while (!list_empty(&stream->buf_head)) { -+ buf = list_first_entry(&stream->buf_head, -+ struct hdmirx_buffer, queue); -+ list_del(&buf->queue); -+ spin_unlock_irqrestore(&stream->vbq_lock, flags); -+ vb2_buffer_done(&buf->vb.vb2_buf, state); -+ spin_lock_irqsave(&stream->vbq_lock, flags); -+ } -+ spin_unlock_irqrestore(&stream->vbq_lock, flags); -+} -+ -+static void hdmirx_stop_streaming(struct vb2_queue *queue) -+{ -+ struct hdmirx_stream *stream = vb2_get_drv_priv(queue); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ int ret; -+ -+ v4l2_info(v4l2_dev, "stream start stopping\n"); -+ mutex_lock(&hdmirx_dev->stream_lock); -+ WRITE_ONCE(stream->stopping, true); -+ -+ /* wait last irq to return the buffer */ -+ ret = wait_event_timeout(stream->wq_stopped, !stream->stopping, -+ msecs_to_jiffies(500)); -+ if (!ret) { -+ v4l2_err(v4l2_dev, "%s: timeout waiting last irq\n", -+ __func__); -+ WRITE_ONCE(stream->stopping, false); -+ } -+ -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, 0); -+ return_all_buffers(stream, VB2_BUF_STATE_ERROR); -+ mutex_unlock(&hdmirx_dev->stream_lock); -+ v4l2_info(v4l2_dev, "stream stopping finished\n"); -+} -+ -+static int hdmirx_start_streaming(struct vb2_queue *queue, unsigned int count) -+{ -+ struct hdmirx_stream *stream = vb2_get_drv_priv(queue); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct v4l2_dv_timings timings = hdmirx_dev->timings; -+ struct v4l2_bt_timings *bt = &timings.bt; -+ unsigned long lock_flags = 0; -+ int line_flag; -+ -+ if (!hdmirx_dev->got_timing) { -+ v4l2_dbg(1, debug, v4l2_dev, "timing is invalid\n"); -+ return 0; -+ } -+ -+ mutex_lock(&hdmirx_dev->stream_lock); -+ stream->frame_idx = 0; -+ stream->line_flag_int_cnt = 0; -+ stream->curr_buf = NULL; -+ stream->next_buf = NULL; -+ stream->irq_stat = 0; -+ queue->min_queued_buffers = 1; -+ -+ WRITE_ONCE(stream->stopping, false); -+ -+ spin_lock_irqsave(&stream->vbq_lock, lock_flags); -+ if (!stream->curr_buf) { -+ if (!list_empty(&stream->buf_head)) { -+ stream->curr_buf = list_first_entry(&stream->buf_head, -+ struct hdmirx_buffer, -+ queue); -+ list_del(&stream->curr_buf->queue); -+ } else { -+ stream->curr_buf = NULL; -+ } -+ } -+ spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); -+ -+ v4l2_dbg(2, debug, v4l2_dev, -+ "%s: start_stream cur_buf y_addr:%#x, uv_addr:%#x\n", -+ __func__, stream->curr_buf->buff_addr[HDMIRX_PLANE_Y], -+ stream->curr_buf->buff_addr[HDMIRX_PLANE_CBCR]); -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG2, -+ stream->curr_buf->buff_addr[HDMIRX_PLANE_Y]); -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG3, -+ stream->curr_buf->buff_addr[HDMIRX_PLANE_CBCR]); -+ -+ if (bt->height) { -+ if (bt->interlaced == V4L2_DV_INTERLACED) -+ line_flag = bt->height / 4; -+ else -+ line_flag = bt->height / 2; -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG7, -+ LINE_FLAG_NUM_MASK, -+ LINE_FLAG_NUM(line_flag)); -+ } else { -+ v4l2_err(v4l2_dev, "height err: %d\n", bt->height); -+ } -+ -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG5, 0xffffffff); -+ hdmirx_writel(hdmirx_dev, CED_DYN_CONTROL, 0x1); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, -+ LINE_FLAG_INT_EN | -+ HDMIRX_DMA_IDLE_INT | -+ HDMIRX_LOCK_DISABLE_INT | -+ LAST_FRAME_AXI_UNFINISH_INT_EN | -+ FIFO_OVERFLOW_INT_EN | -+ FIFO_UNDERFLOW_INT_EN | -+ HDMIRX_AXI_ERROR_INT_EN, -+ LINE_FLAG_INT_EN | -+ HDMIRX_DMA_IDLE_INT | -+ HDMIRX_LOCK_DISABLE_INT | -+ LAST_FRAME_AXI_UNFINISH_INT_EN | -+ FIFO_OVERFLOW_INT_EN | -+ FIFO_UNDERFLOW_INT_EN | -+ HDMIRX_AXI_ERROR_INT_EN); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, HDMIRX_DMA_EN); -+ v4l2_dbg(1, debug, v4l2_dev, "%s: enable dma", __func__); -+ mutex_unlock(&hdmirx_dev->stream_lock); -+ -+ return 0; -+} -+ -+/* vb2 queue */ -+static const struct vb2_ops hdmirx_vb2_ops = { -+ .queue_setup = hdmirx_queue_setup, -+ .buf_queue = hdmirx_buf_queue, -+ .wait_prepare = vb2_ops_wait_prepare, -+ .wait_finish = vb2_ops_wait_finish, -+ .stop_streaming = hdmirx_stop_streaming, -+ .start_streaming = hdmirx_start_streaming, -+}; -+ -+static int hdmirx_init_vb2_queue(struct vb2_queue *q, -+ struct hdmirx_stream *stream, -+ enum v4l2_buf_type buf_type) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ -+ q->type = buf_type; -+ q->io_modes = VB2_MMAP | VB2_DMABUF; -+ q->drv_priv = stream; -+ q->ops = &hdmirx_vb2_ops; -+ q->mem_ops = &vb2_dma_contig_memops; -+ q->buf_struct_size = sizeof(struct hdmirx_buffer); -+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; -+ q->lock = &stream->vlock; -+ q->dev = hdmirx_dev->dev; -+ /* -+ * rk3588 doesn't use iommu and works only with dma buffers -+ * that are physically contiguous in memory. -+ */ -+ q->dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS; -+ return vb2_queue_init(q); -+} -+ -+/* video device */ -+static const struct v4l2_ioctl_ops hdmirx_v4l2_ioctl_ops = { -+ .vidioc_querycap = hdmirx_querycap, -+ .vidioc_try_fmt_vid_cap_mplane = hdmirx_g_fmt_vid_cap_mplane, -+ .vidioc_s_fmt_vid_cap_mplane = hdmirx_s_fmt_vid_cap_mplane, -+ .vidioc_g_fmt_vid_cap_mplane = hdmirx_g_fmt_vid_cap_mplane, -+ .vidioc_enum_fmt_vid_cap = hdmirx_enum_fmt_vid_cap_mplane, -+ -+ .vidioc_s_dv_timings = hdmirx_s_dv_timings, -+ .vidioc_g_dv_timings = hdmirx_g_dv_timings, -+ .vidioc_enum_dv_timings = hdmirx_enum_dv_timings, -+ .vidioc_query_dv_timings = hdmirx_query_dv_timings, -+ .vidioc_dv_timings_cap = hdmirx_dv_timings_cap, -+ .vidioc_enum_input = hdmirx_enum_input, -+ .vidioc_g_input = hdmirx_get_input, -+ .vidioc_s_input = hdmirx_set_input, -+ .vidioc_g_edid = hdmirx_get_edid, -+ .vidioc_s_edid = hdmirx_set_edid, -+ .vidioc_g_parm = hdmirx_g_parm, -+ -+ .vidioc_reqbufs = vb2_ioctl_reqbufs, -+ .vidioc_querybuf = vb2_ioctl_querybuf, -+ .vidioc_create_bufs = vb2_ioctl_create_bufs, -+ .vidioc_qbuf = vb2_ioctl_qbuf, -+ .vidioc_expbuf = vb2_ioctl_expbuf, -+ .vidioc_dqbuf = vb2_ioctl_dqbuf, -+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf, -+ .vidioc_streamon = vb2_ioctl_streamon, -+ .vidioc_streamoff = vb2_ioctl_streamoff, -+ -+ .vidioc_log_status = v4l2_ctrl_log_status, -+ .vidioc_subscribe_event = hdmirx_subscribe_event, -+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -+}; -+ -+static const struct v4l2_file_operations hdmirx_fops = { -+ .owner = THIS_MODULE, -+ .open = v4l2_fh_open, -+ .release = vb2_fop_release, -+ .unlocked_ioctl = video_ioctl2, -+ .poll = vb2_fop_poll, -+ .mmap = vb2_fop_mmap, -+}; -+ -+static int hdmirx_register_stream_vdev(struct hdmirx_stream *stream) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct video_device *vdev = &stream->vdev; -+ int ret = 0; -+ -+ strscpy(vdev->name, "stream_hdmirx", sizeof(vdev->name)); -+ INIT_LIST_HEAD(&stream->buf_head); -+ spin_lock_init(&stream->vbq_lock); -+ mutex_init(&stream->vlock); -+ init_waitqueue_head(&stream->wq_stopped); -+ stream->curr_buf = NULL; -+ stream->next_buf = NULL; -+ -+ vdev->ioctl_ops = &hdmirx_v4l2_ioctl_ops; -+ vdev->release = video_device_release_empty; -+ vdev->fops = &hdmirx_fops; -+ vdev->minor = -1; -+ vdev->v4l2_dev = v4l2_dev; -+ vdev->lock = &stream->vlock; -+ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | -+ V4L2_CAP_STREAMING; -+ video_set_drvdata(vdev, stream); -+ vdev->vfl_dir = VFL_DIR_RX; -+ -+ hdmirx_init_vb2_queue(&stream->buf_queue, stream, -+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); -+ vdev->queue = &stream->buf_queue; -+ -+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); -+ if (ret < 0) { -+ v4l2_err(v4l2_dev, "video_register_device failed: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void process_signal_change(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, 0); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, -+ LINE_FLAG_INT_EN | -+ HDMIRX_DMA_IDLE_INT | -+ HDMIRX_LOCK_DISABLE_INT | -+ LAST_FRAME_AXI_UNFINISH_INT_EN | -+ FIFO_OVERFLOW_INT_EN | -+ FIFO_UNDERFLOW_INT_EN | -+ HDMIRX_AXI_ERROR_INT_EN, 0); -+ hdmirx_reset_dma(hdmirx_dev); -+ hdmirx_dev->got_timing = false; -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_res_change, -+ msecs_to_jiffies(50)); -+} -+ -+static void avpunit_0_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ int status, bool *handled) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ if (status & (CED_DYN_CNT_CH2_IRQ | -+ CED_DYN_CNT_CH1_IRQ | -+ CED_DYN_CNT_CH0_IRQ)) { -+ process_signal_change(hdmirx_dev); -+ v4l2_dbg(2, debug, v4l2_dev, "%s: avp0_st:%#x\n", -+ __func__, status); -+ *handled = true; -+ } -+ -+ hdmirx_clear_interrupt(hdmirx_dev, AVPUNIT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_writel(hdmirx_dev, AVPUNIT_0_INT_FORCE, 0x0); -+} -+ -+static void avpunit_1_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ int status, bool *handled) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ if (status & DEFRAMER_VSYNC_THR_REACHED_IRQ) { -+ v4l2_info(v4l2_dev, "Vertical Sync threshold reached interrupt %#x", status); -+ hdmirx_update_bits(hdmirx_dev, AVPUNIT_1_INT_MASK_N, -+ DEFRAMER_VSYNC_THR_REACHED_MASK_N, 0); -+ *handled = true; -+ } -+} -+ -+static void mainunit_0_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ int status, bool *handled) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ v4l2_dbg(2, debug, v4l2_dev, "mu0_st:%#x\n", status); -+ if (status & TIMER_BASE_LOCKED_IRQ) { -+ hdmirx_update_bits(hdmirx_dev, MAINUNIT_0_INT_MASK_N, -+ TIMER_BASE_LOCKED_IRQ, 0); -+ complete(&hdmirx_dev->timer_base_lock); -+ *handled = true; -+ } -+ -+ if (status & TMDSQPCLK_OFF_CHG) { -+ process_signal_change(hdmirx_dev); -+ v4l2_dbg(2, debug, v4l2_dev, "%s: TMDSQPCLK_OFF_CHG\n", __func__); -+ *handled = true; -+ } -+ -+ if (status & TMDSQPCLK_LOCKED_CHG) { -+ process_signal_change(hdmirx_dev); -+ v4l2_dbg(2, debug, v4l2_dev, "%s: TMDSQPCLK_LOCKED_CHG\n", __func__); -+ *handled = true; -+ } -+ -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_writel(hdmirx_dev, MAINUNIT_0_INT_FORCE, 0x0); -+} -+ -+static void mainunit_2_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ int status, bool *handled) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ v4l2_dbg(2, debug, v4l2_dev, "mu2_st:%#x\n", status); -+ if (status & PHYCREG_CR_WRITE_DONE) { -+ hdmirx_update_bits(hdmirx_dev, MAINUNIT_2_INT_MASK_N, -+ PHYCREG_CR_WRITE_DONE, 0); -+ complete(&hdmirx_dev->cr_write_done); -+ *handled = true; -+ } -+ -+ if (status & TMDSVALID_STABLE_CHG) { -+ process_signal_change(hdmirx_dev); -+ v4l2_dbg(2, debug, v4l2_dev, "%s: TMDSVALID_STABLE_CHG\n", __func__); -+ *handled = true; -+ } -+ -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); -+ hdmirx_writel(hdmirx_dev, MAINUNIT_2_INT_FORCE, 0x0); -+} -+ -+static void pkt_2_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ int status, bool *handled) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ v4l2_dbg(2, debug, v4l2_dev, "%s: pk2_st:%#x\n", __func__, status); -+ if (status & PKTDEC_AVIIF_RCV_IRQ) { -+ hdmirx_update_bits(hdmirx_dev, PKT_2_INT_MASK_N, -+ PKTDEC_AVIIF_RCV_IRQ, 0); -+ complete(&hdmirx_dev->avi_pkt_rcv); -+ v4l2_dbg(2, debug, v4l2_dev, "%s: AVIIF_RCV_IRQ\n", __func__); -+ *handled = true; -+ } -+ -+ hdmirx_clear_interrupt(hdmirx_dev, PKT_2_INT_CLEAR, 0xffffffff); -+} -+ -+static void scdc_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ int status, bool *handled) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ v4l2_dbg(2, debug, v4l2_dev, "%s: scdc_st:%#x\n", __func__, status); -+ if (status & SCDCTMDSCCFG_CHG) { -+ hdmirx_tmds_clk_ratio_config(hdmirx_dev); -+ *handled = true; -+ } -+ -+ hdmirx_clear_interrupt(hdmirx_dev, SCDC_INT_CLEAR, 0xffffffff); -+} -+ -+static irqreturn_t hdmirx_hdmi_irq_handler(int irq, void *dev_id) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_id; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct arm_smccc_res res; -+ u32 mu0_st, mu2_st, pk2_st, scdc_st, avp1_st, avp0_st; -+ u32 mu0_mask, mu2_mask, pk2_mask, scdc_mask, avp1_msk, avp0_msk; -+ bool handled = false; -+ -+ mu0_mask = hdmirx_readl(hdmirx_dev, MAINUNIT_0_INT_MASK_N); -+ mu2_mask = hdmirx_readl(hdmirx_dev, MAINUNIT_2_INT_MASK_N); -+ pk2_mask = hdmirx_readl(hdmirx_dev, PKT_2_INT_MASK_N); -+ scdc_mask = hdmirx_readl(hdmirx_dev, SCDC_INT_MASK_N); -+ mu0_st = hdmirx_readl(hdmirx_dev, MAINUNIT_0_INT_STATUS); -+ mu2_st = hdmirx_readl(hdmirx_dev, MAINUNIT_2_INT_STATUS); -+ pk2_st = hdmirx_readl(hdmirx_dev, PKT_2_INT_STATUS); -+ scdc_st = hdmirx_readl(hdmirx_dev, SCDC_INT_STATUS); -+ avp0_st = hdmirx_readl(hdmirx_dev, AVPUNIT_0_INT_STATUS); -+ avp1_st = hdmirx_readl(hdmirx_dev, AVPUNIT_1_INT_STATUS); -+ avp0_msk = hdmirx_readl(hdmirx_dev, AVPUNIT_0_INT_MASK_N); -+ avp1_msk = hdmirx_readl(hdmirx_dev, AVPUNIT_1_INT_MASK_N); -+ mu0_st &= mu0_mask; -+ mu2_st &= mu2_mask; -+ pk2_st &= pk2_mask; -+ avp1_st &= avp1_msk; -+ avp0_st &= avp0_msk; -+ scdc_st &= scdc_mask; -+ -+ if (avp0_st) -+ avpunit_0_int_handler(hdmirx_dev, avp0_st, &handled); -+ if (avp1_st) -+ avpunit_1_int_handler(hdmirx_dev, avp1_st, &handled); -+ if (mu0_st) -+ mainunit_0_int_handler(hdmirx_dev, mu0_st, &handled); -+ if (mu2_st) -+ mainunit_2_int_handler(hdmirx_dev, mu2_st, &handled); -+ if (pk2_st) -+ pkt_2_int_handler(hdmirx_dev, pk2_st, &handled); -+ if (scdc_st) -+ scdc_int_handler(hdmirx_dev, scdc_st, &handled); -+ -+ if (!handled) { -+ v4l2_dbg(2, debug, v4l2_dev, "%s: hdmi irq not handled", __func__); -+ v4l2_dbg(2, debug, v4l2_dev, -+ "avp0:%#x, avp1:%#x, mu0:%#x, mu2:%#x, pk2:%#x, scdc:%#x\n", -+ avp0_st, avp1_st, mu0_st, mu2_st, pk2_st, scdc_st); -+ } -+ -+ v4l2_dbg(2, debug, v4l2_dev, "%s: en_fiq", __func__); -+ arm_smccc_smc(RK_SIP_FIQ_CTRL, RK_SIP_FIQ_CTRL_FIQ_EN, -+ RK_IRQ_HDMIRX_HDMI, 0, 0, 0, 0, 0, &res); -+ -+ return handled ? IRQ_HANDLED : IRQ_NONE; -+} -+ -+static void hdmirx_vb_done(struct hdmirx_stream *stream, -+ struct vb2_v4l2_buffer *vb_done) -+{ -+ const struct v4l2_format_info *finfo = stream->out_finfo; -+ u32 i; -+ -+ /* Dequeue a filled buffer */ -+ for (i = 0; i < finfo->mem_planes; i++) { -+ vb2_set_plane_payload(&vb_done->vb2_buf, i, -+ stream->pixm.plane_fmt[i].sizeimage); -+ } -+ -+ vb_done->vb2_buf.timestamp = ktime_get_ns(); -+ vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE); -+} -+ -+static void dma_idle_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ bool *handled) -+{ -+ struct hdmirx_stream *stream = &hdmirx_dev->stream; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct v4l2_dv_timings timings = hdmirx_dev->timings; -+ struct v4l2_bt_timings *bt = &timings.bt; -+ struct vb2_v4l2_buffer *vb_done = NULL; -+ -+ if (!(stream->irq_stat) && !(stream->irq_stat & LINE_FLAG_INT_EN)) -+ v4l2_dbg(1, debug, v4l2_dev, -+ "%s: last time have no line_flag_irq\n", __func__); -+ -+ if (stream->line_flag_int_cnt <= FILTER_FRAME_CNT) -+ goto DMA_IDLE_OUT; -+ -+ if (bt->interlaced != V4L2_DV_INTERLACED || -+ !(stream->line_flag_int_cnt % 2)) { -+ if (stream->next_buf) { -+ if (stream->curr_buf) -+ vb_done = &stream->curr_buf->vb; -+ -+ if (vb_done) { -+ vb_done->vb2_buf.timestamp = ktime_get_ns(); -+ vb_done->sequence = stream->frame_idx; -+ hdmirx_vb_done(stream, vb_done); -+ stream->frame_idx++; -+ if (stream->frame_idx == 30) -+ v4l2_info(v4l2_dev, "rcv frames\n"); -+ } -+ -+ stream->curr_buf = NULL; -+ if (stream->next_buf) { -+ stream->curr_buf = stream->next_buf; -+ stream->next_buf = NULL; -+ } -+ } else { -+ v4l2_dbg(3, debug, v4l2_dev, -+ "%s: next_buf NULL, skip vb_done\n", __func__); -+ } -+ } -+ -+DMA_IDLE_OUT: -+ *handled = true; -+} -+ -+static void line_flag_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ bool *handled) -+{ -+ struct hdmirx_stream *stream = &hdmirx_dev->stream; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct v4l2_dv_timings timings = hdmirx_dev->timings; -+ struct v4l2_bt_timings *bt = &timings.bt; -+ u32 dma_cfg6; -+ -+ stream->line_flag_int_cnt++; -+ if (!(stream->irq_stat) && !(stream->irq_stat & HDMIRX_DMA_IDLE_INT)) -+ v4l2_dbg(1, debug, v4l2_dev, -+ "%s: last have no dma_idle_irq\n", __func__); -+ dma_cfg6 = hdmirx_readl(hdmirx_dev, DMA_CONFIG6); -+ if (!(dma_cfg6 & HDMIRX_DMA_EN)) { -+ v4l2_dbg(2, debug, v4l2_dev, "%s: dma not on\n", __func__); -+ goto LINE_FLAG_OUT; -+ } -+ -+ if (stream->line_flag_int_cnt <= FILTER_FRAME_CNT) -+ goto LINE_FLAG_OUT; -+ -+ if (bt->interlaced != V4L2_DV_INTERLACED || -+ !(stream->line_flag_int_cnt % 2)) { -+ if (!stream->next_buf) { -+ spin_lock(&stream->vbq_lock); -+ if (!list_empty(&stream->buf_head)) { -+ stream->next_buf = list_first_entry(&stream->buf_head, -+ struct hdmirx_buffer, -+ queue); -+ list_del(&stream->next_buf->queue); -+ } else { -+ stream->next_buf = NULL; -+ } -+ spin_unlock(&stream->vbq_lock); -+ -+ if (stream->next_buf) { -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG2, -+ stream->next_buf->buff_addr[HDMIRX_PLANE_Y]); -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG3, -+ stream->next_buf->buff_addr[HDMIRX_PLANE_CBCR]); -+ } else { -+ v4l2_dbg(3, debug, v4l2_dev, -+ "%s: no buffer is available\n", __func__); -+ } -+ } -+ } else { -+ v4l2_dbg(3, debug, v4l2_dev, "%s: interlace:%d, line_flag_int_cnt:%d\n", -+ __func__, bt->interlaced, stream->line_flag_int_cnt); -+ } -+ -+LINE_FLAG_OUT: -+ *handled = true; -+} -+ -+static irqreturn_t hdmirx_dma_irq_handler(int irq, void *dev_id) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_id; -+ struct hdmirx_stream *stream = &hdmirx_dev->stream; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 dma_stat1, dma_stat13; -+ bool handled = false; -+ -+ dma_stat1 = hdmirx_readl(hdmirx_dev, DMA_STATUS1); -+ dma_stat13 = hdmirx_readl(hdmirx_dev, DMA_STATUS13); -+ v4l2_dbg(3, debug, v4l2_dev, "dma_irq st1:%#x, st13:%d\n", -+ dma_stat1, dma_stat13); -+ -+ if (READ_ONCE(stream->stopping)) { -+ v4l2_dbg(1, debug, v4l2_dev, "%s: stop stream\n", __func__); -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG5, 0xffffffff); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, -+ LINE_FLAG_INT_EN | -+ HDMIRX_DMA_IDLE_INT | -+ HDMIRX_LOCK_DISABLE_INT | -+ LAST_FRAME_AXI_UNFINISH_INT_EN | -+ FIFO_OVERFLOW_INT_EN | -+ FIFO_UNDERFLOW_INT_EN | -+ HDMIRX_AXI_ERROR_INT_EN, 0); -+ WRITE_ONCE(stream->stopping, false); -+ wake_up(&stream->wq_stopped); -+ return IRQ_HANDLED; -+ } -+ -+ if (dma_stat1 & HDMIRX_DMA_IDLE_INT) -+ dma_idle_int_handler(hdmirx_dev, &handled); -+ -+ if (dma_stat1 & LINE_FLAG_INT_EN) -+ line_flag_int_handler(hdmirx_dev, &handled); -+ -+ if (!handled) -+ v4l2_dbg(3, debug, v4l2_dev, -+ "%s: dma irq not handled, dma_stat1:%#x\n", -+ __func__, dma_stat1); -+ -+ stream->irq_stat = dma_stat1; -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG5, 0xffffffff); -+ -+ return IRQ_HANDLED; -+} -+ -+static void hdmirx_plugin(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct arm_smccc_res res; -+ int ret; -+ -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_heartbeat, -+ msecs_to_jiffies(10)); -+ arm_smccc_smc(SIP_WDT_CFG, WDT_START, 0, 0, 0, 0, 0, 0, &res); -+ hdmirx_submodule_init(hdmirx_dev); -+ hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, POWERPROVIDED, -+ POWERPROVIDED); -+ hdmirx_hpd_ctrl(hdmirx_dev, true); -+ hdmirx_phy_config(hdmirx_dev); -+ ret = hdmirx_wait_lock_and_get_timing(hdmirx_dev); -+ if (ret) { -+ hdmirx_plugout(hdmirx_dev); -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_hotplug, -+ msecs_to_jiffies(200)); -+ return; -+ } -+ hdmirx_dma_config(hdmirx_dev); -+ hdmirx_interrupts_setup(hdmirx_dev, true); -+} -+ -+static void hdmirx_delayed_work_hotplug(struct work_struct *work) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev; -+ bool plugin; -+ -+ hdmirx_dev = container_of(work, struct snps_hdmirx_dev, -+ delayed_work_hotplug.work); -+ -+ mutex_lock(&hdmirx_dev->work_lock); -+ hdmirx_dev->got_timing = false; -+ plugin = tx_5v_power_present(hdmirx_dev); -+ v4l2_ctrl_s_ctrl(hdmirx_dev->detect_tx_5v_ctrl, plugin); -+ v4l2_dbg(1, debug, &hdmirx_dev->v4l2_dev, "%s: plugin:%d\n", -+ __func__, plugin); -+ -+ if (plugin) -+ hdmirx_plugin(hdmirx_dev); -+ else -+ hdmirx_plugout(hdmirx_dev); -+ -+ mutex_unlock(&hdmirx_dev->work_lock); -+} -+ -+static void hdmirx_delayed_work_res_change(struct work_struct *work) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev; -+ bool plugin; -+ -+ hdmirx_dev = container_of(work, struct snps_hdmirx_dev, -+ delayed_work_res_change.work); -+ -+ mutex_lock(&hdmirx_dev->work_lock); -+ plugin = tx_5v_power_present(hdmirx_dev); -+ v4l2_dbg(1, debug, &hdmirx_dev->v4l2_dev, "%s: plugin:%d\n", -+ __func__, plugin); -+ if (plugin) { -+ hdmirx_interrupts_setup(hdmirx_dev, false); -+ hdmirx_submodule_init(hdmirx_dev); -+ hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, POWERPROVIDED, -+ POWERPROVIDED); -+ hdmirx_hpd_ctrl(hdmirx_dev, true); -+ hdmirx_phy_config(hdmirx_dev); -+ -+ if (hdmirx_wait_lock_and_get_timing(hdmirx_dev)) { -+ hdmirx_plugout(hdmirx_dev); -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_hotplug, -+ msecs_to_jiffies(200)); -+ } else { -+ hdmirx_dma_config(hdmirx_dev); -+ hdmirx_interrupts_setup(hdmirx_dev, true); -+ } -+ } -+ mutex_unlock(&hdmirx_dev->work_lock); -+} -+ -+static void hdmirx_delayed_work_heartbeat(struct work_struct *work) -+{ -+ struct delayed_work *dwork = to_delayed_work(work); -+ struct snps_hdmirx_dev *hdmirx_dev = container_of(dwork, -+ struct snps_hdmirx_dev, -+ delayed_work_heartbeat); -+ -+ queue_work(system_highpri_wq, &hdmirx_dev->work_wdt_config); -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_heartbeat, HZ); -+} -+ -+static void hdmirx_work_wdt_config(struct work_struct *work) -+{ -+ struct arm_smccc_res res; -+ struct snps_hdmirx_dev *hdmirx_dev = container_of(work, -+ struct snps_hdmirx_dev, -+ work_wdt_config); -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ arm_smccc_smc(SIP_WDT_CFG, WDT_PING, 0, 0, 0, 0, 0, 0, &res); -+ v4l2_dbg(3, debug, v4l2_dev, "hb\n"); -+} -+ -+static irqreturn_t hdmirx_5v_det_irq_handler(int irq, void *dev_id) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_id; -+ u32 val; -+ -+ val = gpiod_get_value(hdmirx_dev->detect_5v_gpio); -+ v4l2_dbg(3, debug, &hdmirx_dev->v4l2_dev, "%s: 5v:%d\n", __func__, val); -+ -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_hotplug, -+ msecs_to_jiffies(10)); -+ -+ return IRQ_HANDLED; -+} -+ -+static const struct hdmirx_cec_ops hdmirx_cec_ops = { -+ .write = hdmirx_writel, -+ .read = hdmirx_readl, -+}; -+ -+static int hdmirx_parse_dt(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct device *dev = hdmirx_dev->dev; -+ int ret; -+ -+ hdmirx_dev->num_clks = devm_clk_bulk_get_all(dev, &hdmirx_dev->clks); -+ if (hdmirx_dev->num_clks < 1) -+ return -ENODEV; -+ -+ hdmirx_dev->resets[HDMIRX_RST_A].id = "axi"; -+ hdmirx_dev->resets[HDMIRX_RST_P].id = "apb"; -+ hdmirx_dev->resets[HDMIRX_RST_REF].id = "ref"; -+ hdmirx_dev->resets[HDMIRX_RST_BIU].id = "biu"; -+ -+ ret = devm_reset_control_bulk_get_exclusive(dev, HDMIRX_NUM_RST, -+ hdmirx_dev->resets); -+ if (ret < 0) { -+ dev_err(dev, "failed to get reset controls\n"); -+ return ret; -+ } -+ -+ hdmirx_dev->detect_5v_gpio = -+ devm_gpiod_get_optional(dev, "hpd", GPIOD_IN); -+ -+ if (IS_ERR(hdmirx_dev->detect_5v_gpio)) { -+ dev_err(dev, "failed to get hdmirx hot plug detection gpio\n"); -+ return PTR_ERR(hdmirx_dev->detect_5v_gpio); -+ } -+ -+ hdmirx_dev->grf = syscon_regmap_lookup_by_phandle(dev->of_node, -+ "rockchip,grf"); -+ if (IS_ERR(hdmirx_dev->grf)) { -+ dev_err(dev, "failed to get rockchip,grf\n"); -+ return PTR_ERR(hdmirx_dev->grf); -+ } -+ -+ hdmirx_dev->vo1_grf = syscon_regmap_lookup_by_phandle(dev->of_node, -+ "rockchip,vo1-grf"); -+ if (IS_ERR(hdmirx_dev->vo1_grf)) { -+ dev_err(dev, "failed to get rockchip,vo1-grf\n"); -+ return PTR_ERR(hdmirx_dev->vo1_grf); -+ } -+ -+ hdmirx_dev->hpd_trigger_level = !device_property_read_bool(dev, "hpd-is-active-low"); -+ -+ ret = of_reserved_mem_device_init(dev); -+ if (ret) -+ dev_warn(dev, "No reserved memory for HDMIRX, use default CMA\n"); -+ -+ return 0; -+} -+ -+static void hdmirx_disable_all_interrupts(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ hdmirx_writel(hdmirx_dev, MAINUNIT_0_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, MAINUNIT_1_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, MAINUNIT_2_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, AVPUNIT_0_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, AVPUNIT_1_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, PKT_0_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, PKT_1_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, PKT_2_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, SCDC_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, CEC_INT_MASK_N, 0); -+ -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_1_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, AVPUNIT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, AVPUNIT_1_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, PKT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, PKT_1_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, PKT_2_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, SCDC_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, HDCP_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, HDCP_1_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, CEC_INT_CLEAR, 0xffffffff); -+} -+ -+static int hdmirx_init(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, PHY_RESET | PHY_PDDQ, 0); -+ -+ regmap_write(hdmirx_dev->vo1_grf, VO1_GRF_VO1_CON2, -+ (HDMIRX_SDAIN_MSK | HDMIRX_SCLIN_MSK) | -+ ((HDMIRX_SDAIN_MSK | HDMIRX_SCLIN_MSK) << 16)); -+ /* -+ * Some interrupts are enabled by default, so we disable -+ * all interrupts and clear interrupts status first. -+ */ -+ hdmirx_disable_all_interrupts(hdmirx_dev); -+ -+ return 0; -+} -+ -+static void hdmirx_load_default_edid(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ int ret; -+ struct v4l2_edid def_edid; -+ -+ hdmirx_hpd_ctrl(hdmirx_dev, false); -+ -+ /* disable hpd and write edid */ -+ def_edid.pad = 0; -+ def_edid.start_block = 0; -+ def_edid.blocks = EDID_NUM_BLOCKS_MAX; -+ -+ if (IS_ENABLED(CONFIG_HDMIRX_LOAD_DEFAULT_EDID)) -+ def_edid.edid = edid_init_data_340M; -+ else -+ def_edid.edid = hdmirx_dev->edid; -+ -+ ret = hdmirx_write_edid(hdmirx_dev, &def_edid, true); -+ if (ret) -+ dev_err(hdmirx_dev->dev, "%s: write edid failed\n", __func__); -+} -+ -+static void hdmirx_disable_irq(struct device *dev) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); -+ struct arm_smccc_res res; -+ -+ disable_irq(hdmirx_dev->hdmi_irq); -+ disable_irq(hdmirx_dev->dma_irq); -+ disable_irq(hdmirx_dev->det_irq); -+ -+ arm_smccc_smc(RK_SIP_FIQ_CTRL, RK_SIP_FIQ_CTRL_FIQ_DIS, -+ RK_IRQ_HDMIRX_HDMI, 0, 0, 0, 0, 0, &res); -+ -+ cancel_delayed_work_sync(&hdmirx_dev->delayed_work_hotplug); -+ cancel_delayed_work_sync(&hdmirx_dev->delayed_work_res_change); -+ cancel_delayed_work_sync(&hdmirx_dev->delayed_work_heartbeat); -+ flush_work(&hdmirx_dev->work_wdt_config); -+ -+ arm_smccc_smc(SIP_WDT_CFG, WDT_STOP, 0, 0, 0, 0, 0, 0, &res); -+} -+ -+static int hdmirx_disable(struct device *dev) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ clk_bulk_disable_unprepare(hdmirx_dev->num_clks, hdmirx_dev->clks); -+ -+ v4l2_dbg(2, debug, v4l2_dev, "%s: suspend\n", __func__); -+ -+ return pinctrl_pm_select_sleep_state(dev); -+} -+ -+static void hdmirx_enable_irq(struct device *dev) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); -+ struct arm_smccc_res res; -+ -+ enable_irq(hdmirx_dev->hdmi_irq); -+ enable_irq(hdmirx_dev->dma_irq); -+ enable_irq(hdmirx_dev->det_irq); -+ -+ arm_smccc_smc(RK_SIP_FIQ_CTRL, RK_SIP_FIQ_CTRL_FIQ_EN, -+ RK_IRQ_HDMIRX_HDMI, 0, 0, 0, 0, 0, &res); -+ -+ queue_delayed_work(system_unbound_wq, &hdmirx_dev->delayed_work_hotplug, -+ msecs_to_jiffies(20)); -+} -+ -+static int hdmirx_enable(struct device *dev) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ int ret; -+ -+ v4l2_dbg(2, debug, v4l2_dev, "%s: resume\n", __func__); -+ ret = pinctrl_pm_select_default_state(dev); -+ if (ret < 0) -+ return ret; -+ -+ ret = clk_bulk_prepare_enable(hdmirx_dev->num_clks, hdmirx_dev->clks); -+ if (ret) { -+ dev_err(dev, "failed to enable hdmirx bulk clks: %d\n", ret); -+ return ret; -+ } -+ -+ reset_control_bulk_assert(HDMIRX_NUM_RST, hdmirx_dev->resets); -+ usleep_range(150, 160); -+ reset_control_bulk_deassert(HDMIRX_NUM_RST, hdmirx_dev->resets); -+ usleep_range(150, 160); -+ -+ return 0; -+} -+ -+static int hdmirx_suspend(struct device *dev) -+{ -+ hdmirx_disable_irq(dev); -+ -+ return hdmirx_disable(dev); -+} -+ -+static int hdmirx_resume(struct device *dev) -+{ -+ int ret = hdmirx_enable(dev); -+ -+ if (ret) -+ return ret; -+ -+ hdmirx_enable_irq(dev); -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops snps_hdmirx_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(hdmirx_suspend, hdmirx_resume) -+}; -+ -+static int hdmirx_setup_irq(struct snps_hdmirx_dev *hdmirx_dev, -+ struct platform_device *pdev) -+{ -+ struct device *dev = hdmirx_dev->dev; -+ int ret, irq; -+ -+ irq = platform_get_irq_byname(pdev, "hdmi"); -+ if (irq < 0) { -+ dev_err_probe(dev, irq, "failed to get hdmi irq\n"); -+ return irq; -+ } -+ -+ irq_set_status_flags(irq, IRQ_NOAUTOEN); -+ -+ hdmirx_dev->hdmi_irq = irq; -+ ret = devm_request_irq(dev, irq, hdmirx_hdmi_irq_handler, 0, -+ "rk_hdmirx-hdmi", hdmirx_dev); -+ if (ret) { -+ dev_err_probe(dev, ret, "failed to request hdmi irq\n"); -+ return ret; -+ } -+ -+ irq = platform_get_irq_byname(pdev, "dma"); -+ if (irq < 0) { -+ dev_err_probe(dev, irq, "failed to get dma irq\n"); -+ return irq; -+ } -+ -+ irq_set_status_flags(irq, IRQ_NOAUTOEN); -+ -+ hdmirx_dev->dma_irq = irq; -+ ret = devm_request_threaded_irq(dev, irq, NULL, hdmirx_dma_irq_handler, -+ IRQF_ONESHOT, "rk_hdmirx-dma", -+ hdmirx_dev); -+ if (ret) { -+ dev_err_probe(dev, ret, "failed to request dma irq\n"); -+ return ret; -+ } -+ -+ irq = gpiod_to_irq(hdmirx_dev->detect_5v_gpio); -+ if (irq < 0) { -+ dev_err_probe(dev, irq, "failed to get hdmirx-5v irq\n"); -+ return irq; -+ } -+ -+ irq_set_status_flags(irq, IRQ_NOAUTOEN); -+ -+ hdmirx_dev->det_irq = irq; -+ ret = devm_request_irq(dev, irq, hdmirx_5v_det_irq_handler, -+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, -+ "rk_hdmirx-5v", hdmirx_dev); -+ if (ret) { -+ dev_err_probe(dev, ret, "failed to request hdmirx-5v irq\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int hdmirx_register_cec(struct snps_hdmirx_dev *hdmirx_dev, -+ struct platform_device *pdev) -+{ -+ struct device *dev = hdmirx_dev->dev; -+ struct hdmirx_cec_data cec_data; -+ int irq; -+ -+ irq = platform_get_irq_byname(pdev, "cec"); -+ if (irq < 0) { -+ dev_err_probe(dev, irq, "failed to get cec irq\n"); -+ return irq; -+ } -+ -+ hdmirx_dev->cec_notifier = cec_notifier_conn_register(dev, NULL, NULL); -+ if (!hdmirx_dev->cec_notifier) -+ return -EINVAL; -+ -+ cec_data.hdmirx = hdmirx_dev; -+ cec_data.dev = hdmirx_dev->dev; -+ cec_data.ops = &hdmirx_cec_ops; -+ cec_data.irq = irq; -+ -+ hdmirx_dev->cec = snps_hdmirx_cec_register(&cec_data); -+ if (!hdmirx_dev->cec) { -+ cec_notifier_conn_unregister(hdmirx_dev->cec_notifier); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int hdmirx_probe(struct platform_device *pdev) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev; -+ struct device *dev = &pdev->dev; -+ struct v4l2_ctrl_handler *hdl; -+ struct hdmirx_stream *stream; -+ struct v4l2_device *v4l2_dev; -+ int ret; -+ -+ hdmirx_dev = devm_kzalloc(dev, sizeof(*hdmirx_dev), GFP_KERNEL); -+ if (!hdmirx_dev) -+ return -ENOMEM; -+ -+ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); -+ if (ret) -+ return ret; -+ -+ hdmirx_dev->dev = dev; -+ dev_set_drvdata(dev, hdmirx_dev); -+ -+ ret = hdmirx_parse_dt(hdmirx_dev); -+ if (ret) -+ return ret; -+ -+ ret = hdmirx_setup_irq(hdmirx_dev, pdev); -+ if (ret) -+ return ret; -+ -+ hdmirx_dev->regs = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(hdmirx_dev->regs)) -+ return dev_err_probe(dev, PTR_ERR(hdmirx_dev->regs), -+ "failed to remap regs resource\n"); -+ -+ mutex_init(&hdmirx_dev->stream_lock); -+ mutex_init(&hdmirx_dev->work_lock); -+ spin_lock_init(&hdmirx_dev->rst_lock); -+ -+ init_completion(&hdmirx_dev->cr_write_done); -+ init_completion(&hdmirx_dev->timer_base_lock); -+ init_completion(&hdmirx_dev->avi_pkt_rcv); -+ -+ INIT_WORK(&hdmirx_dev->work_wdt_config, hdmirx_work_wdt_config); -+ INIT_DELAYED_WORK(&hdmirx_dev->delayed_work_hotplug, -+ hdmirx_delayed_work_hotplug); -+ INIT_DELAYED_WORK(&hdmirx_dev->delayed_work_res_change, -+ hdmirx_delayed_work_res_change); -+ INIT_DELAYED_WORK(&hdmirx_dev->delayed_work_heartbeat, -+ hdmirx_delayed_work_heartbeat); -+ -+ hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_BGR24; -+ hdmirx_dev->timings = cea640x480; -+ -+ hdmirx_enable(dev); -+ hdmirx_init(hdmirx_dev); -+ -+ v4l2_dev = &hdmirx_dev->v4l2_dev; -+ strscpy(v4l2_dev->name, dev_name(dev), sizeof(v4l2_dev->name)); -+ -+ hdl = &hdmirx_dev->hdl; -+ v4l2_ctrl_handler_init(hdl, 1); -+ -+ hdmirx_dev->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, -+ V4L2_CID_DV_RX_POWER_PRESENT, -+ 0, 1, 0, 0); -+ -+ hdmirx_dev->rgb_range = v4l2_ctrl_new_std_menu(hdl, 0, -+ V4L2_CID_DV_RX_RGB_RANGE, -+ V4L2_DV_RGB_RANGE_FULL, 0, -+ V4L2_DV_RGB_RANGE_AUTO); -+ -+ hdmirx_dev->rgb_range->flags |= V4L2_CTRL_FLAG_READ_ONLY; -+ -+ if (hdl->error) { -+ dev_err(dev, "v4l2 ctrl handler init failed\n"); -+ ret = hdl->error; -+ goto err_pm; -+ } -+ hdmirx_dev->v4l2_dev.ctrl_handler = hdl; -+ -+ ret = v4l2_device_register(dev, &hdmirx_dev->v4l2_dev); -+ if (ret < 0) { -+ dev_err(dev, "register v4l2 device failed\n"); -+ goto err_hdl; -+ } -+ -+ stream = &hdmirx_dev->stream; -+ stream->hdmirx_dev = hdmirx_dev; -+ ret = hdmirx_register_stream_vdev(stream); -+ if (ret < 0) { -+ dev_err(dev, "register video device failed\n"); -+ goto err_unreg_v4l2_dev; -+ } -+ -+ ret = hdmirx_register_cec(hdmirx_dev, pdev); -+ if (ret) -+ goto err_unreg_video_dev; -+ -+ hdmirx_load_default_edid(hdmirx_dev); -+ -+ hdmirx_enable_irq(dev); -+ -+ return 0; -+ -+err_unreg_video_dev: -+ video_unregister_device(&hdmirx_dev->stream.vdev); -+err_unreg_v4l2_dev: -+ v4l2_device_unregister(&hdmirx_dev->v4l2_dev); -+err_hdl: -+ v4l2_ctrl_handler_free(&hdmirx_dev->hdl); -+err_pm: -+ hdmirx_disable(dev); -+ -+ return ret; -+} -+ -+static void hdmirx_remove(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); -+ -+ snps_hdmirx_cec_unregister(hdmirx_dev->cec); -+ cec_notifier_conn_unregister(hdmirx_dev->cec_notifier); -+ -+ hdmirx_disable_irq(dev); -+ -+ video_unregister_device(&hdmirx_dev->stream.vdev); -+ v4l2_ctrl_handler_free(&hdmirx_dev->hdl); -+ v4l2_device_unregister(&hdmirx_dev->v4l2_dev); -+ -+ hdmirx_disable(dev); -+ -+ reset_control_bulk_assert(HDMIRX_NUM_RST, hdmirx_dev->resets); -+ -+ of_reserved_mem_device_release(dev); -+} -+ -+static const struct of_device_id hdmirx_id[] = { -+ { .compatible = "rockchip,rk3588-hdmirx-ctrler" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, hdmirx_id); -+ -+static struct platform_driver hdmirx_driver = { -+ .probe = hdmirx_probe, -+ .remove = hdmirx_remove, -+ .driver = { -+ .name = "snps_hdmirx", -+ .of_match_table = hdmirx_id, -+ .pm = &snps_hdmirx_pm_ops, -+ } -+}; -+module_platform_driver(hdmirx_driver); -+ -+MODULE_DESCRIPTION("Rockchip HDMI Receiver Driver"); -+MODULE_AUTHOR("Dingxian Wen "); -+MODULE_AUTHOR("Shreeya Patel "); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h -@@ -0,0 +1,394 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2021 Rockchip Electronics Co. Ltd. -+ * -+ * Author: Dingxian Wen -+ */ -+ -+#ifndef DW_HDMIRX_H -+#define DW_HDMIRX_H -+ -+#include -+ -+#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) -+#define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK((h), (l)) << 16)) -+ -+/* SYS_GRF */ -+#define SYS_GRF_SOC_CON1 0x0304 -+#define HDMIRXPHY_SRAM_EXT_LD_DONE BIT(1) -+#define HDMIRXPHY_SRAM_BYPASS BIT(0) -+#define SYS_GRF_SOC_STATUS1 0x0384 -+#define HDMIRXPHY_SRAM_INIT_DONE BIT(10) -+#define SYS_GRF_CHIP_ID 0x0600 -+ -+/* VO1_GRF */ -+#define VO1_GRF_VO1_CON2 0x0008 -+#define HDMIRX_SDAIN_MSK BIT(2) -+#define HDMIRX_SCLIN_MSK BIT(1) -+ -+/* HDMIRX PHY */ -+#define SUP_DIG_ANA_CREGS_SUP_ANA_NC 0x004f -+ -+#define LANE0_DIG_ASIC_RX_OVRD_OUT_0 0x100f -+#define LANE1_DIG_ASIC_RX_OVRD_OUT_0 0x110f -+#define LANE2_DIG_ASIC_RX_OVRD_OUT_0 0x120f -+#define LANE3_DIG_ASIC_RX_OVRD_OUT_0 0x130f -+#define ASIC_ACK_OVRD_EN BIT(1) -+#define ASIC_ACK BIT(0) -+ -+#define LANE0_DIG_RX_VCOCAL_RX_VCO_CAL_CTRL_2 0x104a -+#define LANE1_DIG_RX_VCOCAL_RX_VCO_CAL_CTRL_2 0x114a -+#define LANE2_DIG_RX_VCOCAL_RX_VCO_CAL_CTRL_2 0x124a -+#define LANE3_DIG_RX_VCOCAL_RX_VCO_CAL_CTRL_2 0x134a -+#define FREQ_TUNE_START_VAL_MASK GENMASK(9, 0) -+#define FREQ_TUNE_START_VAL(x) UPDATE(x, 9, 0) -+ -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_FSM_CONFIG 0x20c4 -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_ADAPT_REF_FOM 0x20c7 -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_3_REG 0x20e9 -+#define CDR_SETTING_BOUNDARY_3_DEFAULT 0x52da -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_4_REG 0x20ea -+#define CDR_SETTING_BOUNDARY_4_DEFAULT 0x43cd -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_5_REG 0x20eb -+#define CDR_SETTING_BOUNDARY_5_DEFAULT 0x35b3 -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_6_REG 0x20fb -+#define CDR_SETTING_BOUNDARY_6_DEFAULT 0x2799 -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_7_REG 0x20fc -+#define CDR_SETTING_BOUNDARY_7_DEFAULT 0x1b65 -+ -+#define RAWLANE0_DIG_PCS_XF_RX_OVRD_OUT 0x300e -+#define RAWLANE1_DIG_PCS_XF_RX_OVRD_OUT 0x310e -+#define RAWLANE2_DIG_PCS_XF_RX_OVRD_OUT 0x320e -+#define RAWLANE3_DIG_PCS_XF_RX_OVRD_OUT 0x330e -+#define PCS_ACK_WRITE_SELECT BIT(14) -+#define PCS_EN_CTL BIT(1) -+#define PCS_ACK BIT(0) -+ -+#define RAWLANE0_DIG_AON_FAST_FLAGS 0x305c -+#define RAWLANE1_DIG_AON_FAST_FLAGS 0x315c -+#define RAWLANE2_DIG_AON_FAST_FLAGS 0x325c -+#define RAWLANE3_DIG_AON_FAST_FLAGS 0x335c -+ -+/* HDMIRX Ctrler */ -+#define GLOBAL_SWRESET_REQUEST 0x0020 -+#define DATAPATH_SWRESETREQ BIT(12) -+#define GLOBAL_SWENABLE 0x0024 -+#define PHYCTRL_ENABLE BIT(21) -+#define CEC_ENABLE BIT(16) -+#define TMDS_ENABLE BIT(13) -+#define DATAPATH_ENABLE BIT(12) -+#define PKTFIFO_ENABLE BIT(11) -+#define AVPUNIT_ENABLE BIT(8) -+#define MAIN_ENABLE BIT(0) -+#define GLOBAL_TIMER_REF_BASE 0x0028 -+#define CORE_CONFIG 0x0050 -+#define CMU_CONFIG0 0x0060 -+#define TMDSQPCLK_STABLE_FREQ_MARGIN_MASK GENMASK(30, 16) -+#define TMDSQPCLK_STABLE_FREQ_MARGIN(x) UPDATE(x, 30, 16) -+#define AUDCLK_STABLE_FREQ_MARGIN_MASK GENMASK(11, 9) -+#define AUDCLK_STABLE_FREQ_MARGIN(x) UPDATE(x, 11, 9) -+#define CMU_STATUS 0x007c -+#define TMDSQPCLK_LOCKED_ST BIT(4) -+#define CMU_TMDSQPCLK_FREQ 0x0084 -+#define PHY_CONFIG 0x00c0 -+#define LDO_AFE_PROG_MASK GENMASK(24, 23) -+#define LDO_AFE_PROG(x) UPDATE(x, 24, 23) -+#define LDO_PWRDN BIT(21) -+#define TMDS_CLOCK_RATIO BIT(16) -+#define RXDATA_WIDTH BIT(15) -+#define REFFREQ_SEL_MASK GENMASK(11, 9) -+#define REFFREQ_SEL(x) UPDATE(x, 11, 9) -+#define HDMI_DISABLE BIT(8) -+#define PHY_PDDQ BIT(1) -+#define PHY_RESET BIT(0) -+#define PHY_STATUS 0x00c8 -+#define HDMI_DISABLE_ACK BIT(1) -+#define PDDQ_ACK BIT(0) -+#define PHYCREG_CONFIG0 0x00e0 -+#define PHYCREG_CR_PARA_SELECTION_MODE_MASK GENMASK(1, 0) -+#define PHYCREG_CR_PARA_SELECTION_MODE(x) UPDATE(x, 1, 0) -+#define PHYCREG_CONFIG1 0x00e4 -+#define PHYCREG_CONFIG2 0x00e8 -+#define PHYCREG_CONFIG3 0x00ec -+#define PHYCREG_CONTROL 0x00f0 -+#define PHYCREG_CR_PARA_WRITE_P BIT(1) -+#define PHYCREG_CR_PARA_READ_P BIT(0) -+#define PHYCREG_STATUS 0x00f4 -+ -+#define MAINUNIT_STATUS 0x0150 -+#define TMDSVALID_STABLE_ST BIT(1) -+#define DESCRAND_EN_CONTROL 0x0210 -+#define SCRAMB_EN_SEL_QST_MASK GENMASK(1, 0) -+#define SCRAMB_EN_SEL_QST(x) UPDATE(x, 1, 0) -+#define DESCRAND_SYNC_CONTROL 0x0214 -+#define RECOVER_UNSYNC_STREAM_QST BIT(0) -+#define DESCRAND_SYNC_SEQ_CONFIG 0x022c -+#define DESCRAND_SYNC_SEQ_ERR_CNT_EN BIT(0) -+#define DESCRAND_SYNC_SEQ_STATUS 0x0234 -+#define DEFRAMER_CONFIG0 0x0270 -+#define VS_CNT_THR_QST_MASK GENMASK(27, 20) -+#define VS_CNT_THR_QST(x) UPDATE(x, 27, 20) -+#define HS_POL_QST_MASK GENMASK(19, 18) -+#define HS_POL_QST(x) UPDATE(x, 19, 18) -+#define VS_POL_QST_MASK GENMASK(17, 16) -+#define VS_POL_QST(x) UPDATE(x, 17, 16) -+#define VS_REMAPFILTER_EN_QST BIT(8) -+#define VS_FILTER_ORDER_QST_MASK GENMASK(1, 0) -+#define VS_FILTER_ORDER_QST(x) UPDATE(x, 1, 0) -+#define DEFRAMER_VSYNC_CNT_CLEAR 0x0278 -+#define VSYNC_CNT_CLR_P BIT(0) -+#define DEFRAMER_STATUS 0x027c -+#define OPMODE_STS_MASK GENMASK(6, 4) -+#define I2C_SLAVE_CONFIG1 0x0164 -+#define I2C_SDA_OUT_HOLD_VALUE_QST_MASK GENMASK(15, 8) -+#define I2C_SDA_OUT_HOLD_VALUE_QST(x) UPDATE(x, 15, 8) -+#define I2C_SDA_IN_HOLD_VALUE_QST_MASK GENMASK(7, 0) -+#define I2C_SDA_IN_HOLD_VALUE_QST(x) UPDATE(x, 7, 0) -+#define OPMODE_STS_MASK GENMASK(6, 4) -+#define REPEATER_QST BIT(28) -+#define FASTREAUTH_QST BIT(27) -+#define FEATURES_1DOT1_QST BIT(26) -+#define FASTI2C_QST BIT(25) -+#define EESS_CTL_THR_QST_MASK GENMASK(19, 16) -+#define EESS_CTL_THR_QST(x) UPDATE(x, 19, 16) -+#define OESS_CTL3_THR_QST_MASK GENMASK(11, 8) -+#define OESS_CTL3_THR_QST(x) UPDATE(x, 11, 8) -+#define EESS_OESS_SEL_QST_MASK GENMASK(5, 4) -+#define EESS_OESS_SEL_QST(x) UPDATE(x, 5, 4) -+#define KEY_DECRYPT_EN_QST BIT(0) -+#define KEY_DECRYPT_SEED_QST_MASK GENMASK(15, 0) -+#define KEY_DECRYPT_SEED_QST(x) UPDATE(x, 15, 0) -+#define HDCP_INT_CLEAR 0x50d8 -+#define HDCP_1_INT_CLEAR 0x50e8 -+#define HDCP2_CONFIG 0x02f0 -+#define HDCP2_SWITCH_OVR_VALUE BIT(2) -+#define HDCP2_SWITCH_OVR_EN BIT(1) -+ -+#define VIDEO_CONFIG2 0x042c -+#define VPROC_VSYNC_POL_OVR_VALUE BIT(19) -+#define VPROC_VSYNC_POL_OVR_EN BIT(18) -+#define VPROC_HSYNC_POL_OVR_VALUE BIT(17) -+#define VPROC_HSYNC_POL_OVR_EN BIT(16) -+#define VPROC_FMT_OVR_VALUE_MASK GENMASK(6, 4) -+#define VPROC_FMT_OVR_VALUE(x) UPDATE(x, 6, 4) -+#define VPROC_FMT_OVR_EN BIT(0) -+ -+#define AFIFO_FILL_RESTART BIT(0) -+#define AFIFO_INIT_P BIT(0) -+#define AFIFO_THR_LOW_QST_MASK GENMASK(25, 16) -+#define AFIFO_THR_LOW_QST(x) UPDATE(x, 25, 16) -+#define AFIFO_THR_HIGH_QST_MASK GENMASK(9, 0) -+#define AFIFO_THR_HIGH_QST(x) UPDATE(x, 9, 0) -+#define AFIFO_THR_MUTE_LOW_QST_MASK GENMASK(25, 16) -+#define AFIFO_THR_MUTE_LOW_QST(x) UPDATE(x, 25, 16) -+#define AFIFO_THR_MUTE_HIGH_QST_MASK GENMASK(9, 0) -+#define AFIFO_THR_MUTE_HIGH_QST(x) UPDATE(x, 9, 0) -+ -+#define AFIFO_UNDERFLOW_ST BIT(25) -+#define AFIFO_OVERFLOW_ST BIT(24) -+ -+#define SPEAKER_ALLOC_OVR_EN BIT(16) -+#define I2S_BPCUV_EN BIT(4) -+#define SPDIF_EN BIT(2) -+#define I2S_EN BIT(1) -+#define AFIFO_THR_PASS_DEMUTEMASK_N BIT(24) -+#define AVMUTE_DEMUTEMASK_N BIT(16) -+#define AFIFO_THR_MUTE_LOW_MUTEMASK_N BIT(9) -+#define AFIFO_THR_MUTE_HIGH_MUTEMASK_N BIT(8) -+#define AVMUTE_MUTEMASK_N BIT(0) -+#define SCDC_CONFIG 0x0580 -+#define HPDLOW BIT(1) -+#define POWERPROVIDED BIT(0) -+#define SCDC_REGBANK_STATUS1 0x058c -+#define SCDC_TMDSBITCLKRATIO BIT(1) -+#define SCDC_REGBANK_STATUS3 0x0594 -+#define SCDC_REGBANK_CONFIG0 0x05c0 -+#define SCDC_SINKVERSION_QST_MASK GENMASK(7, 0) -+#define SCDC_SINKVERSION_QST(x) UPDATE(x, 7, 0) -+#define AGEN_LAYOUT BIT(4) -+#define AGEN_SPEAKER_ALLOC GENMASK(15, 8) -+ -+#define CED_CONFIG 0x0760 -+#define CED_VIDDATACHECKEN_QST BIT(27) -+#define CED_DATAISCHECKEN_QST BIT(26) -+#define CED_GBCHECKEN_QST BIT(25) -+#define CED_CTRLCHECKEN_QST BIT(24) -+#define CED_CHLOCKMAXER_QST_MASK GENMASK(14, 0) -+#define CED_CHLOCKMAXER_QST(x) UPDATE(x, 14, 0) -+#define CED_DYN_CONFIG 0x0768 -+#define CED_DYN_CONTROL 0x076c -+#define PKTEX_BCH_ERRFILT_CONFIG 0x07c4 -+#define PKTEX_CHKSUM_ERRFILT_CONFIG 0x07c8 -+ -+#define PKTDEC_ACR_PH2_1 0x1100 -+#define PKTDEC_ACR_PB3_0 0x1104 -+#define PKTDEC_ACR_PB7_4 0x1108 -+#define PKTDEC_AVIIF_PH2_1 0x1200 -+#define PKTDEC_AVIIF_PB3_0 0x1204 -+#define PKTDEC_AVIIF_PB7_4 0x1208 -+#define VIC_VAL_MASK GENMASK(6, 0) -+#define PKTDEC_AVIIF_PB11_8 0x120c -+#define PKTDEC_AVIIF_PB15_12 0x1210 -+#define PKTDEC_AVIIF_PB19_16 0x1214 -+#define PKTDEC_AVIIF_PB23_20 0x1218 -+#define PKTDEC_AVIIF_PB27_24 0x121c -+ -+#define PKTFIFO_CONFIG 0x1500 -+#define PKTFIFO_STORE_FILT_CONFIG 0x1504 -+#define PKTFIFO_THR_CONFIG0 0x1508 -+#define PKTFIFO_THR_CONFIG1 0x150c -+#define PKTFIFO_CONTROL 0x1510 -+ -+#define VMON_STATUS1 0x1580 -+#define VMON_STATUS2 0x1584 -+#define VMON_STATUS3 0x1588 -+#define VMON_STATUS4 0x158c -+#define VMON_STATUS5 0x1590 -+#define VMON_STATUS6 0x1594 -+#define VMON_STATUS7 0x1598 -+#define VMON_ILACE_DETECT BIT(4) -+ -+#define CEC_TX_CONTROL 0x2000 -+#define CEC_STATUS 0x2004 -+#define CEC_CONFIG 0x2008 -+#define RX_AUTO_DRIVE_ACKNOWLEDGE BIT(9) -+#define CEC_ADDR 0x200c -+#define CEC_TX_COUNT 0x2020 -+#define CEC_TX_DATA3_0 0x2024 -+#define CEC_RX_COUNT_STATUS 0x2040 -+#define CEC_RX_DATA3_0 0x2044 -+#define CEC_LOCK_CONTROL 0x2054 -+#define CEC_RXQUAL_BITTIME_CONFIG 0x2060 -+#define CEC_RX_BITTIME_CONFIG 0x2064 -+#define CEC_TX_BITTIME_CONFIG 0x2068 -+ -+#define DMA_CONFIG1 0x4400 -+#define UV_WID_MASK GENMASK(31, 28) -+#define UV_WID(x) UPDATE(x, 31, 28) -+#define Y_WID_MASK GENMASK(27, 24) -+#define Y_WID(x) UPDATE(x, 27, 24) -+#define DDR_STORE_FORMAT_MASK GENMASK(15, 12) -+#define DDR_STORE_FORMAT(x) UPDATE(x, 15, 12) -+#define ABANDON_EN BIT(0) -+#define DMA_CONFIG2 0x4404 -+#define DMA_CONFIG3 0x4408 -+#define DMA_CONFIG4 0x440c // dma irq en -+#define DMA_CONFIG5 0x4410 // dma irq clear status -+#define LINE_FLAG_INT_EN BIT(8) -+#define HDMIRX_DMA_IDLE_INT BIT(7) -+#define HDMIRX_LOCK_DISABLE_INT BIT(6) -+#define LAST_FRAME_AXI_UNFINISH_INT_EN BIT(5) -+#define FIFO_OVERFLOW_INT_EN BIT(2) -+#define FIFO_UNDERFLOW_INT_EN BIT(1) -+#define HDMIRX_AXI_ERROR_INT_EN BIT(0) -+#define DMA_CONFIG6 0x4414 -+#define RB_SWAP_EN BIT(9) -+#define HSYNC_TOGGLE_EN BIT(5) -+#define VSYNC_TOGGLE_EN BIT(4) -+#define HDMIRX_DMA_EN BIT(1) -+#define DMA_CONFIG7 0x4418 -+#define LINE_FLAG_NUM_MASK GENMASK(31, 16) -+#define LINE_FLAG_NUM(x) UPDATE(x, 31, 16) -+#define LOCK_FRAME_NUM_MASK GENMASK(11, 0) -+#define LOCK_FRAME_NUM(x) UPDATE(x, 11, 0) -+#define DMA_CONFIG8 0x441c -+#define REG_MIRROR_EN BIT(0) -+#define DMA_CONFIG9 0x4420 -+#define DMA_CONFIG10 0x4424 -+#define DMA_CONFIG11 0x4428 -+#define EDID_READ_EN_MASK BIT(8) -+#define EDID_READ_EN(x) UPDATE(x, 8, 8) -+#define EDID_WRITE_EN_MASK BIT(7) -+#define EDID_WRITE_EN(x) UPDATE(x, 7, 7) -+#define EDID_SLAVE_ADDR_MASK GENMASK(6, 0) -+#define EDID_SLAVE_ADDR(x) UPDATE(x, 6, 0) -+#define DMA_STATUS1 0x4430 // dma irq status -+#define DMA_STATUS2 0x4434 -+#define DMA_STATUS3 0x4438 -+#define DMA_STATUS4 0x443c -+#define DMA_STATUS5 0x4440 -+#define DMA_STATUS6 0x4444 -+#define DMA_STATUS7 0x4448 -+#define DMA_STATUS8 0x444c -+#define DMA_STATUS9 0x4450 -+#define DMA_STATUS10 0x4454 -+#define HDMIRX_LOCK BIT(3) -+#define DMA_STATUS11 0x4458 -+#define HDMIRX_TYPE_MASK GENMASK(8, 7) -+#define HDMIRX_COLOR_DEPTH_MASK GENMASK(6, 3) -+#define HDMIRX_FORMAT_MASK GENMASK(2, 0) -+#define DMA_STATUS12 0x445c -+#define DMA_STATUS13 0x4460 -+#define DMA_STATUS14 0x4464 -+ -+#define MAINUNIT_INTVEC_INDEX 0x5000 -+#define MAINUNIT_0_INT_STATUS 0x5010 -+#define CECRX_NOTIFY_ERR BIT(12) -+#define CECRX_EOM BIT(11) -+#define CECTX_DRIVE_ERR BIT(10) -+#define CECRX_BUSY BIT(9) -+#define CECTX_BUSY BIT(8) -+#define CECTX_FRAME_DISCARDED BIT(5) -+#define CECTX_NRETRANSMIT_FAIL BIT(4) -+#define CECTX_LINE_ERR BIT(3) -+#define CECTX_ARBLOST BIT(2) -+#define CECTX_NACK BIT(1) -+#define CECTX_DONE BIT(0) -+#define MAINUNIT_0_INT_MASK_N 0x5014 -+#define MAINUNIT_0_INT_CLEAR 0x5018 -+#define MAINUNIT_0_INT_FORCE 0x501c -+#define TIMER_BASE_LOCKED_IRQ BIT(26) -+#define TMDSQPCLK_OFF_CHG BIT(5) -+#define TMDSQPCLK_LOCKED_CHG BIT(4) -+#define MAINUNIT_1_INT_STATUS 0x5020 -+#define MAINUNIT_1_INT_MASK_N 0x5024 -+#define MAINUNIT_1_INT_CLEAR 0x5028 -+#define MAINUNIT_1_INT_FORCE 0x502c -+#define MAINUNIT_2_INT_STATUS 0x5030 -+#define MAINUNIT_2_INT_MASK_N 0x5034 -+#define MAINUNIT_2_INT_CLEAR 0x5038 -+#define MAINUNIT_2_INT_FORCE 0x503c -+#define PHYCREG_CR_READ_DONE BIT(11) -+#define PHYCREG_CR_WRITE_DONE BIT(10) -+#define TMDSVALID_STABLE_CHG BIT(1) -+ -+#define AVPUNIT_0_INT_STATUS 0x5040 -+#define AVPUNIT_0_INT_MASK_N 0x5044 -+#define AVPUNIT_0_INT_CLEAR 0x5048 -+#define AVPUNIT_0_INT_FORCE 0x504c -+#define CED_DYN_CNT_CH2_IRQ BIT(22) -+#define CED_DYN_CNT_CH1_IRQ BIT(21) -+#define CED_DYN_CNT_CH0_IRQ BIT(20) -+#define AVPUNIT_1_INT_STATUS 0x5050 -+#define DEFRAMER_VSYNC_THR_REACHED_IRQ BIT(1) -+#define AVPUNIT_1_INT_MASK_N 0x5054 -+#define DEFRAMER_VSYNC_THR_REACHED_MASK_N BIT(1) -+#define DEFRAMER_VSYNC_MASK_N BIT(0) -+#define AVPUNIT_1_INT_CLEAR 0x5058 -+#define DEFRAMER_VSYNC_THR_REACHED_CLEAR BIT(1) -+#define PKT_0_INT_STATUS 0x5080 -+#define PKTDEC_ACR_CHG_IRQ BIT(3) -+#define PKT_0_INT_MASK_N 0x5084 -+#define PKTDEC_ACR_CHG_MASK_N BIT(3) -+#define PKT_0_INT_CLEAR 0x5088 -+#define PKT_1_INT_STATUS 0x5090 -+#define PKT_1_INT_MASK_N 0x5094 -+#define PKT_1_INT_CLEAR 0x5098 -+#define PKT_2_INT_STATUS 0x50a0 -+#define PKTDEC_ACR_RCV_IRQ BIT(3) -+#define PKT_2_INT_MASK_N 0x50a4 -+#define PKTDEC_AVIIF_RCV_IRQ BIT(11) -+#define PKTDEC_ACR_RCV_MASK_N BIT(3) -+#define PKT_2_INT_CLEAR 0x50a8 -+#define PKTDEC_AVIIF_RCV_CLEAR BIT(11) -+#define PKTDEC_ACR_RCV_CLEAR BIT(3) -+#define SCDC_INT_STATUS 0x50c0 -+#define SCDC_INT_MASK_N 0x50c4 -+#define SCDC_INT_CLEAR 0x50c8 -+#define SCDCTMDSCCFG_CHG BIT(2) -+ -+#define CEC_INT_STATUS 0x5100 -+#define CEC_INT_MASK_N 0x5104 -+#define CEC_INT_CLEAR 0x5108 -+ -+#endif -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c -@@ -0,0 +1,285 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2021 Rockchip Electronics Co. Ltd. -+ * -+ * Author: Shunqing Chen -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "snps_hdmirx.h" -+#include "snps_hdmirx_cec.h" -+ -+static void hdmirx_cec_write(struct hdmirx_cec *cec, int reg, u32 val) -+{ -+ cec->ops->write(cec->hdmirx, reg, val); -+} -+ -+static u32 hdmirx_cec_read(struct hdmirx_cec *cec, int reg) -+{ -+ return cec->ops->read(cec->hdmirx, reg); -+} -+ -+static void hdmirx_cec_update_bits(struct hdmirx_cec *cec, int reg, u32 mask, -+ u32 data) -+{ -+ u32 val = hdmirx_cec_read(cec, reg) & ~mask; -+ -+ val |= (data & mask); -+ hdmirx_cec_write(cec, reg, val); -+} -+ -+static int hdmirx_cec_log_addr(struct cec_adapter *adap, u8 logical_addr) -+{ -+ struct hdmirx_cec *cec = cec_get_drvdata(adap); -+ -+ if (logical_addr == CEC_LOG_ADDR_INVALID) -+ cec->addresses = 0; -+ else -+ cec->addresses |= BIT(logical_addr) | BIT(15); -+ -+ hdmirx_cec_write(cec, CEC_ADDR, cec->addresses); -+ -+ return 0; -+} -+ -+/* signal_free_time is handled by the Synopsys Designware -+ * HDMIRX Controller hardware. -+ */ -+static int hdmirx_cec_transmit(struct cec_adapter *adap, u8 attempts, -+ u32 signal_free_time, struct cec_msg *msg) -+{ -+ struct hdmirx_cec *cec = cec_get_drvdata(adap); -+ u32 data[4] = {0}; -+ int i, data_len, msg_len; -+ -+ msg_len = msg->len; -+ -+ hdmirx_cec_write(cec, CEC_TX_COUNT, msg_len - 1); -+ for (i = 0; i < msg_len; i++) -+ data[i / 4] |= msg->msg[i] << (i % 4) * 8; -+ -+ data_len = DIV_ROUND_UP(msg_len, 4); -+ -+ for (i = 0; i < data_len; i++) -+ hdmirx_cec_write(cec, CEC_TX_DATA3_0 + i * 4, data[i]); -+ -+ hdmirx_cec_write(cec, CEC_TX_CONTROL, 0x1); -+ -+ return 0; -+} -+ -+static irqreturn_t hdmirx_cec_hardirq(int irq, void *data) -+{ -+ struct cec_adapter *adap = data; -+ struct hdmirx_cec *cec = cec_get_drvdata(adap); -+ u32 stat = hdmirx_cec_read(cec, CEC_INT_STATUS); -+ irqreturn_t ret = IRQ_HANDLED; -+ u32 val; -+ -+ if (!stat) -+ return IRQ_NONE; -+ -+ hdmirx_cec_write(cec, CEC_INT_CLEAR, stat); -+ -+ if (stat & CECTX_LINE_ERR) { -+ cec->tx_status = CEC_TX_STATUS_ERROR; -+ cec->tx_done = true; -+ ret = IRQ_WAKE_THREAD; -+ } else if (stat & CECTX_DONE) { -+ cec->tx_status = CEC_TX_STATUS_OK; -+ cec->tx_done = true; -+ ret = IRQ_WAKE_THREAD; -+ } else if (stat & CECTX_NACK) { -+ cec->tx_status = CEC_TX_STATUS_NACK; -+ cec->tx_done = true; -+ ret = IRQ_WAKE_THREAD; -+ } else if (stat & CECTX_ARBLOST) { -+ cec->tx_status = CEC_TX_STATUS_ARB_LOST; -+ cec->tx_done = true; -+ ret = IRQ_WAKE_THREAD; -+ } -+ -+ if (stat & CECRX_EOM) { -+ unsigned int len, i; -+ -+ val = hdmirx_cec_read(cec, CEC_RX_COUNT_STATUS); -+ /* rxbuffer locked status */ -+ if ((val & 0x80)) -+ return ret; -+ -+ len = (val & 0xf) + 1; -+ if (len > sizeof(cec->rx_msg.msg)) -+ len = sizeof(cec->rx_msg.msg); -+ -+ for (i = 0; i < len; i++) { -+ if (!(i % 4)) -+ val = hdmirx_cec_read(cec, CEC_RX_DATA3_0 + i / 4 * 4); -+ cec->rx_msg.msg[i] = (val >> ((i % 4) * 8)) & 0xff; -+ } -+ -+ cec->rx_msg.len = len; -+ smp_wmb(); /* receive RX msg */ -+ cec->rx_done = true; -+ hdmirx_cec_write(cec, CEC_LOCK_CONTROL, 0x1); -+ -+ ret = IRQ_WAKE_THREAD; -+ } -+ -+ return ret; -+} -+ -+static irqreturn_t hdmirx_cec_thread(int irq, void *data) -+{ -+ struct cec_adapter *adap = data; -+ struct hdmirx_cec *cec = cec_get_drvdata(adap); -+ -+ if (cec->tx_done) { -+ cec->tx_done = false; -+ cec_transmit_attempt_done(adap, cec->tx_status); -+ } -+ if (cec->rx_done) { -+ cec->rx_done = false; -+ smp_rmb(); /* RX msg has been received */ -+ cec_received_msg(adap, &cec->rx_msg); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static int hdmirx_cec_enable(struct cec_adapter *adap, bool enable) -+{ -+ struct hdmirx_cec *cec = cec_get_drvdata(adap); -+ -+ if (!enable) { -+ hdmirx_cec_write(cec, CEC_INT_MASK_N, 0); -+ hdmirx_cec_write(cec, CEC_INT_CLEAR, 0); -+ if (cec->ops->disable) -+ cec->ops->disable(cec->hdmirx); -+ } else { -+ unsigned int irqs; -+ -+ hdmirx_cec_log_addr(cec->adap, CEC_LOG_ADDR_INVALID); -+ if (cec->ops->enable) -+ cec->ops->enable(cec->hdmirx); -+ hdmirx_cec_update_bits(cec, GLOBAL_SWENABLE, CEC_ENABLE, CEC_ENABLE); -+ -+ irqs = CECTX_LINE_ERR | CECTX_NACK | CECRX_EOM | CECTX_DONE; -+ hdmirx_cec_write(cec, CEC_INT_MASK_N, irqs); -+ } -+ -+ return 0; -+} -+ -+static const struct cec_adap_ops hdmirx_cec_ops = { -+ .adap_enable = hdmirx_cec_enable, -+ .adap_log_addr = hdmirx_cec_log_addr, -+ .adap_transmit = hdmirx_cec_transmit, -+}; -+ -+static void hdmirx_cec_del(void *data) -+{ -+ struct hdmirx_cec *cec = data; -+ -+ cec_delete_adapter(cec->adap); -+} -+ -+struct hdmirx_cec *snps_hdmirx_cec_register(struct hdmirx_cec_data *data) -+{ -+ struct hdmirx_cec *cec; -+ unsigned int irqs; -+ int ret; -+ -+ /* -+ * Our device is just a convenience - we want to link to the real -+ * hardware device here, so that userspace can see the association -+ * between the HDMI hardware and its associated CEC chardev. -+ */ -+ cec = devm_kzalloc(data->dev, sizeof(*cec), GFP_KERNEL); -+ if (!cec) -+ return NULL; -+ -+ cec->dev = data->dev; -+ cec->irq = data->irq; -+ cec->ops = data->ops; -+ cec->hdmirx = data->hdmirx; -+ -+ hdmirx_cec_update_bits(cec, GLOBAL_SWENABLE, CEC_ENABLE, CEC_ENABLE); -+ hdmirx_cec_update_bits(cec, CEC_CONFIG, RX_AUTO_DRIVE_ACKNOWLEDGE, -+ RX_AUTO_DRIVE_ACKNOWLEDGE); -+ -+ hdmirx_cec_write(cec, CEC_TX_COUNT, 0); -+ hdmirx_cec_write(cec, CEC_INT_MASK_N, 0); -+ hdmirx_cec_write(cec, CEC_INT_CLEAR, ~0); -+ -+ cec->adap = cec_allocate_adapter(&hdmirx_cec_ops, cec, "snps-hdmirx", -+ CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | -+ CEC_CAP_RC | CEC_CAP_PASSTHROUGH | -+ CEC_CAP_MONITOR_ALL, -+ CEC_MAX_LOG_ADDRS); -+ if (IS_ERR(cec->adap)) { -+ dev_err(cec->dev, "cec adap allocate failed\n"); -+ return NULL; -+ } -+ -+ /* override the module pointer */ -+ cec->adap->owner = THIS_MODULE; -+ -+ ret = devm_add_action(cec->dev, hdmirx_cec_del, cec); -+ if (ret) { -+ cec_delete_adapter(cec->adap); -+ return NULL; -+ } -+ -+ irq_set_status_flags(cec->irq, IRQ_NOAUTOEN); -+ -+ ret = devm_request_threaded_irq(cec->dev, cec->irq, -+ hdmirx_cec_hardirq, -+ hdmirx_cec_thread, IRQF_ONESHOT, -+ "rk_hdmirx_cec", cec->adap); -+ if (ret) { -+ dev_err(cec->dev, "cec irq request failed\n"); -+ return NULL; -+ } -+ -+ cec->notify = cec_notifier_cec_adap_register(cec->dev, -+ NULL, cec->adap); -+ if (!cec->notify) { -+ dev_err(cec->dev, "cec notify register failed\n"); -+ return NULL; -+ } -+ -+ ret = cec_register_adapter(cec->adap, cec->dev); -+ if (ret < 0) { -+ dev_err(cec->dev, "cec register adapter failed\n"); -+ cec_unregister_adapter(cec->adap); -+ return NULL; -+ } -+ -+ irqs = CECTX_LINE_ERR | CECTX_NACK | CECRX_EOM | CECTX_DONE; -+ hdmirx_cec_write(cec, CEC_INT_MASK_N, irqs); -+ -+ /* -+ * CEC documentation says we must not call cec_delete_adapter -+ * after a successful call to cec_register_adapter(). -+ */ -+ devm_remove_action(cec->dev, hdmirx_cec_del, cec); -+ -+ enable_irq(cec->irq); -+ -+ return cec; -+} -+ -+void snps_hdmirx_cec_unregister(struct hdmirx_cec *cec) -+{ -+ disable_irq(cec->irq); -+ -+ cec_unregister_adapter(cec->adap); -+} -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.h b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.h -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.h -@@ -0,0 +1,44 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2021 Rockchip Electronics Co. Ltd. -+ * -+ * Author: Shunqing Chen -+ */ -+ -+#ifndef DW_HDMI_RX_CEC_H -+#define DW_HDMI_RX_CEC_H -+ -+struct snps_hdmirx_dev; -+ -+struct hdmirx_cec_ops { -+ void (*write)(struct snps_hdmirx_dev *hdmirx_dev, int reg, u32 val); -+ u32 (*read)(struct snps_hdmirx_dev *hdmirx_dev, int reg); -+ void (*enable)(struct snps_hdmirx_dev *hdmirx); -+ void (*disable)(struct snps_hdmirx_dev *hdmirx); -+}; -+ -+struct hdmirx_cec_data { -+ struct snps_hdmirx_dev *hdmirx; -+ const struct hdmirx_cec_ops *ops; -+ struct device *dev; -+ int irq; -+}; -+ -+struct hdmirx_cec { -+ struct snps_hdmirx_dev *hdmirx; -+ struct device *dev; -+ const struct hdmirx_cec_ops *ops; -+ u32 addresses; -+ struct cec_adapter *adap; -+ struct cec_msg rx_msg; -+ unsigned int tx_status; -+ bool tx_done; -+ bool rx_done; -+ struct cec_notifier *notify; -+ int irq; -+}; -+ -+struct hdmirx_cec *snps_hdmirx_cec_register(struct hdmirx_cec_data *data); -+void snps_hdmirx_cec_unregister(struct hdmirx_cec *cec); -+ -+#endif /* DW_HDMI_RX_CEC_H */ --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Mon, 29 Jul 2024 17:29:46 +0200 -Subject: arm64: defconfig: Enable Synopsys HDMI receiver - -The Rockchip RK3588 has a built-in HDMI receiver block from -Synopsys. Let's enable the driver for it. - -Signed-off-by: Sebastian Reichel ---- - arch/arm64/configs/defconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig -index 111111111111..222222222222 100644 ---- a/arch/arm64/configs/defconfig -+++ b/arch/arm64/configs/defconfig -@@ -860,6 +860,7 @@ CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m - CONFIG_VIDEO_SAMSUNG_S5P_JPEG=m - CONFIG_VIDEO_SAMSUNG_S5P_MFC=m - CONFIG_VIDEO_SUN6I_CSI=m -+CONFIG_VIDEO_SYNOPSYS_HDMIRX=m - CONFIG_VIDEO_TI_J721E_CSI2RX=m - CONFIG_VIDEO_HANTRO=m - CONFIG_VIDEO_IMX219=m --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Muhammed Efe Cetin -Date: Thu, 1 Aug 2024 16:47:35 +0300 -Subject: comment v4l2 error on hdmirx - ---- - drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -index 111111111111..222222222222 100644 ---- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -@@ -1180,7 +1180,7 @@ static int hdmirx_wait_lock_and_get_timing(struct snps_hdmirx_dev *hdmirx_dev) - break; - - if (!tx_5v_power_present(hdmirx_dev)) { -- v4l2_err(v4l2_dev, "%s: HDMI pull out, return\n", __func__); -+ //v4l2_err(v4l2_dev, "%s: HDMI pull out, return\n", __func__); - return -1; - } - --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Hoff -Date: Sun, 15 Sep 2024 14:52:17 -0400 -Subject: fix spurious triggering of irq 5v while plugout code is running - ---- - drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 12 ++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -index 111111111111..222222222222 100644 ---- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -@@ -745,10 +745,17 @@ static void hdmirx_interrupts_setup(struct snps_hdmirx_dev *hdmirx_dev, bool en) - static void hdmirx_plugout(struct snps_hdmirx_dev *hdmirx_dev) - { - struct arm_smccc_res res; -+ int irq; - - hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, POWERPROVIDED, 0); - hdmirx_interrupts_setup(hdmirx_dev, false); - hdmirx_hpd_ctrl(hdmirx_dev, false); -+ irq = gpiod_to_irq(hdmirx_dev->detect_5v_gpio); -+ -+ if (irq >= 0) { -+ disable_irq(irq); -+ } -+ - hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, 0); - hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, - LINE_FLAG_INT_EN | -@@ -766,6 +773,11 @@ static void hdmirx_plugout(struct snps_hdmirx_dev *hdmirx_dev) - cancel_delayed_work_sync(&hdmirx_dev->delayed_work_heartbeat); - flush_work(&hdmirx_dev->work_wdt_config); - arm_smccc_smc(SIP_WDT_CFG, WDT_STOP, 0, 0, 0, 0, 0, 0, &res); -+ -+ hdmirx_hpd_ctrl(hdmirx_dev, true); -+ if (irq >= 0) { -+ enable_irq(irq); -+ } - } - - static int hdmirx_set_edid(struct file *file, void *fh, struct v4l2_edid *edid) --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Hoff -Date: Sun, 15 Sep 2024 14:53:25 -0400 -Subject: remove timing handling from plug in function - ---- - drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 7 ------- - 1 file changed, 7 deletions(-) - -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -index 111111111111..222222222222 100644 ---- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -@@ -2202,13 +2202,6 @@ static void hdmirx_plugin(struct snps_hdmirx_dev *hdmirx_dev) - hdmirx_hpd_ctrl(hdmirx_dev, true); - hdmirx_phy_config(hdmirx_dev); - ret = hdmirx_wait_lock_and_get_timing(hdmirx_dev); -- if (ret) { -- hdmirx_plugout(hdmirx_dev); -- queue_delayed_work(system_unbound_wq, -- &hdmirx_dev->delayed_work_hotplug, -- msecs_to_jiffies(200)); -- return; -- } - hdmirx_dma_config(hdmirx_dev); - hdmirx_interrupts_setup(hdmirx_dev, true); - } --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Hoff -Date: Mon, 23 Sep 2024 09:43:38 -0400 -Subject: expose itc type to v4l2 in synopsys hdmir rx - ---- - drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 16 +++++++++- - 1 file changed, 15 insertions(+), 1 deletion(-) - -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -index 111111111111..222222222222 100644 ---- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -@@ -151,6 +151,7 @@ struct snps_hdmirx_dev { - struct v4l2_ctrl_handler hdl; - struct v4l2_ctrl *detect_tx_5v_ctrl; - struct v4l2_ctrl *rgb_range; -+ struct v4l2_ctrl *content_type; - struct v4l2_dv_timings timings; - struct gpio_desc *detect_5v_gpio; - struct work_struct work_wdt_config; -@@ -512,6 +513,11 @@ static void hdmirx_get_avi_infoframe(struct snps_hdmirx_dev *hdmirx_dev) - } - - v4l2_ctrl_s_ctrl(hdmirx_dev->rgb_range, frame.avi.quantization_range); -+ if (frame.avi.itc) { -+ v4l2_ctrl_s_ctrl(hdmirx_dev->content_type, frame.avi.content_type); -+ } else { -+ v4l2_ctrl_s_ctrl(hdmirx_dev->content_type, V4L2_DV_IT_CONTENT_TYPE_NO_ITC); -+ } - } - - /* -@@ -1192,6 +1198,7 @@ static int hdmirx_wait_lock_and_get_timing(struct snps_hdmirx_dev *hdmirx_dev) - break; - - if (!tx_5v_power_present(hdmirx_dev)) { -+ v4l2_ctrl_s_ctrl(hdmirx_dev->content_type, V4L2_DV_IT_CONTENT_TYPE_NO_ITC); - //v4l2_err(v4l2_dev, "%s: HDMI pull out, return\n", __func__); - return -1; - } -@@ -1204,6 +1211,7 @@ static int hdmirx_wait_lock_and_get_timing(struct snps_hdmirx_dev *hdmirx_dev) - __func__, hdmirx_dev->tmds_clk_ratio); - v4l2_err(v4l2_dev, "%s: mu_st:%#x, scdc_st:%#x, dma_st10:%#x\n", - __func__, mu_status, scdc_status, dma_st10); -+ v4l2_ctrl_s_ctrl(hdmirx_dev->content_type, V4L2_DV_IT_CONTENT_TYPE_NO_ITC); - return -1; - } - -@@ -2668,7 +2676,7 @@ static int hdmirx_probe(struct platform_device *pdev) - strscpy(v4l2_dev->name, dev_name(dev), sizeof(v4l2_dev->name)); - - hdl = &hdmirx_dev->hdl; -- v4l2_ctrl_handler_init(hdl, 1); -+ v4l2_ctrl_handler_init(hdl, 3); - - hdmirx_dev->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, - V4L2_CID_DV_RX_POWER_PRESENT, -@@ -2681,6 +2689,12 @@ static int hdmirx_probe(struct platform_device *pdev) - - hdmirx_dev->rgb_range->flags |= V4L2_CTRL_FLAG_READ_ONLY; - -+ hdmirx_dev->content_type = v4l2_ctrl_new_std_menu(hdl, NULL, -+ V4L2_CID_DV_RX_IT_CONTENT_TYPE, -+ V4L2_DV_IT_CONTENT_TYPE_NO_ITC, -+ 0, -+ V4L2_DV_IT_CONTENT_TYPE_NO_ITC); -+ - if (hdl->error) { - dev_err(dev, "v4l2 ctrl handler init failed\n"); - ret = hdl->error; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-0130-add-hdmi1-support.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-0130-add-hdmi1-support.patch deleted file mode 100644 index e137612d6c..0000000000 --- a/patch/kernel/archive/rockchip64-6.15/rk3588-0130-add-hdmi1-support.patch +++ /dev/null @@ -1,123 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 7 Dec 2024 21:45:12 +0200 -Subject: arm64: dts: rockchip: Add PHY node for HDMI1 TX port on RK3588 - -In preparation to enable the second HDMI output port found on RK3588 -SoC, add the related PHY node. This requires a GRF, hence add the -dependent node as well. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 21 ++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -@@ -90,6 +90,11 @@ u2phy1_otg: otg-port { - }; - }; - -+ hdptxphy1_grf: syscon@fd5e4000 { -+ compatible = "rockchip,rk3588-hdptxphy-grf", "syscon"; -+ reg = <0x0 0xfd5e4000 0x0 0x100>; -+ }; -+ - i2s8_8ch: i2s@fddc8000 { - compatible = "rockchip,rk3588-i2s-tdm"; - reg = <0x0 0xfddc8000 0x0 0x1000>; -@@ -454,6 +459,22 @@ sata-port@0 { - }; - }; - -+ hdptxphy1: phy@fed70000 { -+ compatible = "rockchip,rk3588-hdptx-phy"; -+ reg = <0x0 0xfed70000 0x0 0x2000>; -+ clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>, <&cru PCLK_HDPTX1>; -+ clock-names = "ref", "apb"; -+ #phy-cells = <0>; -+ resets = <&cru SRST_HDPTX1>, <&cru SRST_P_HDPTX1>, -+ <&cru SRST_HDPTX1_INIT>, <&cru SRST_HDPTX1_CMN>, -+ <&cru SRST_HDPTX1_LANE>, <&cru SRST_HDPTX1_ROPLL>, -+ <&cru SRST_HDPTX1_LCPLL>; -+ reset-names = "phy", "apb", "init", "cmn", "lane", "ropll", -+ "lcpll"; -+ rockchip,grf = <&hdptxphy1_grf>; -+ status = "disabled"; -+ }; -+ - usbdp_phy1: phy@fed90000 { - compatible = "rockchip,rk3588-usbdp-phy"; - reg = <0x0 0xfed90000 0x0 0x10000>; --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 7 Dec 2024 21:53:07 +0200 -Subject: arm64: dts: rockchip: Add HDMI1 node on RK3588 - -Add support for the second HDMI TX port found on RK3588 SoC. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 41 ++++++++++ - 1 file changed, 41 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -@@ -196,6 +196,47 @@ hdmi_receiver: hdmi_receiver@fdee0000 { - status = "disabled"; - }; - -+ hdmi1: hdmi@fdea0000 { -+ compatible = "rockchip,rk3588-dw-hdmi-qp"; -+ reg = <0x0 0xfdea0000 0x0 0x20000>; -+ clocks = <&cru PCLK_HDMITX1>, -+ <&cru CLK_HDMITX1_EARC>, -+ <&cru CLK_HDMITX1_REF>, -+ <&cru MCLK_I2S6_8CH_TX>, -+ <&cru CLK_HDMIHDP1>, -+ <&cru HCLK_VO1>; -+ clock-names = "pclk", "earc", "ref", "aud", "hdp", "hclk_vo1"; -+ interrupts = , -+ , -+ , -+ , -+ ; -+ interrupt-names = "avp", "cec", "earc", "main", "hpd"; -+ phys = <&hdptxphy1>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&hdmim2_tx1_cec &hdmim0_tx1_hpd -+ &hdmim1_tx1_scl &hdmim1_tx1_sda>; -+ power-domains = <&power RK3588_PD_VO1>; -+ resets = <&cru SRST_HDMITX1_REF>, <&cru SRST_HDMIHDP1>; -+ reset-names = "ref", "hdp"; -+ rockchip,grf = <&sys_grf>; -+ rockchip,vo-grf = <&vo1_grf>; -+ status = "disabled"; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ hdmi1_in: port@0 { -+ reg = <0>; -+ }; -+ -+ hdmi1_out: port@1 { -+ reg = <1>; -+ }; -+ }; -+ }; -+ - pcie3x4: pcie@fe150000 { - compatible = "rockchip,rk3588-pcie", "rockchip,rk3568-pcie"; - #address-cells = <3>; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-0131-vop2-hdmi0-disp-modes-support.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-0131-vop2-hdmi0-disp-modes-support.patch deleted file mode 100644 index c5f0cac410..0000000000 --- a/patch/kernel/archive/rockchip64-6.15/rk3588-0131-vop2-hdmi0-disp-modes-support.patch +++ /dev/null @@ -1,252 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 16 Nov 2024 03:19:43 +0200 -Subject: dt-bindings: display: vop2: Add optional PLL clock properties - -On RK3588, HDMI PHY PLL can be used as an alternative and more accurate -pixel clock source for VOP2 video ports 0, 1 and 2. - -Document the optional PLL clock properties corresponding to the two HDMI -PHYs available on the SoC. - -Signed-off-by: Cristian Ciocaltea ---- - Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml -index 111111111111..222222222222 100644 ---- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml -+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml -@@ -53,6 +53,8 @@ properties: - - description: Pixel clock for video port 2. - - description: Pixel clock for video port 3. - - description: Peripheral(vop grf/dsi) clock. -+ - description: Alternative pixel clock provided by HDMI0 PHY PLL. -+ - description: Alternative pixel clock provided by HDMI1 PHY PLL. - - clock-names: - minItems: 5 -@@ -64,6 +66,8 @@ properties: - - const: dclk_vp2 - - const: dclk_vp3 - - const: pclk_vop -+ - const: pll_hdmiphy0 -+ - const: pll_hdmiphy1 - - rockchip,grf: - $ref: /schemas/types.yaml#/definitions/phandle --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Tue, 12 Nov 2024 02:27:35 +0200 -Subject: drm/rockchip: vop2: Drop unnecessary if_pixclk_rate computation - -The if_pixclk_rate variable is not being used outside of the if-block in -rk3588_calc_cru_cfg(), hence move the superfluous assignment from the -first branch to the inner comment-block. - -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -@@ -1905,8 +1905,8 @@ static unsigned long rk3588_calc_cru_cfg(struct vop2_video_port *vp, int id, - K = 2; - } - -- if_pixclk_rate = (dclk_core_rate << 1) / K; - /* -+ * if_pixclk_rate = (dclk_core_rate << 1) / K; - * if_dclk_rate = dclk_core_rate / K; - * *if_pixclk_div = dclk_rate / if_pixclk_rate; - * *if_dclk_div = dclk_rate / if_dclk_rate; --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Fri, 3 Nov 2023 19:58:02 +0200 -Subject: drm/rockchip: vop2: Improve display modes handling on RK3588 HDMI0 - -The RK3588 specific implementation is currently quite limited in terms -of handling the full range of display modes supported by the connected -screens, e.g. 2560x1440@75Hz, 2048x1152@60Hz, 1024x768@60Hz are just a -few of them. - -Additionally, it doesn't cope well with non-integer refresh rates like -59.94, 29.97, 23.98, etc. - -Make use of HDMI0 PHY PLL as a more accurate DCLK source to handle -all display modes up to 4K@60Hz. - -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 34 ++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -@@ -159,6 +159,7 @@ struct vop2_video_port { - struct drm_crtc crtc; - struct vop2 *vop2; - struct clk *dclk; -+ struct clk *dclk_src; - unsigned int id; - const struct vop2_video_port_data *data; - -@@ -214,6 +215,7 @@ struct vop2 { - struct clk *hclk; - struct clk *aclk; - struct clk *pclk; -+ struct clk *pll_hdmiphy0; - - /* optional internal rgb encoder */ - struct rockchip_rgb *rgb; -@@ -222,6 +224,8 @@ struct vop2 { - struct vop2_win win[]; - }; - -+#define VOP2_MAX_DCLK_RATE 600000000 -+ - #define vop2_output_if_is_hdmi(x) ((x) == ROCKCHIP_VOP2_EP_HDMI0 || \ - (x) == ROCKCHIP_VOP2_EP_HDMI1) - -@@ -1155,6 +1159,9 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, - - vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID); - -+ if (vp->dclk_src) -+ clk_set_parent(vp->dclk, vp->dclk_src); -+ - clk_disable_unprepare(vp->dclk); - - vop2->enable_count--; -@@ -2259,6 +2266,27 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - - vop2_vp_write(vp, RK3568_VP_MIPI_CTRL, 0); - -+ /* -+ * Switch to HDMI PHY PLL as DCLK source for display modes up -+ * to 4K@60Hz, if available, otherwise keep using the system CRU. -+ */ -+ if (vop2->pll_hdmiphy0 && clock <= VOP2_MAX_DCLK_RATE) { -+ drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { -+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); -+ -+ if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) { -+ if (!vp->dclk_src) -+ vp->dclk_src = clk_get_parent(vp->dclk); -+ -+ ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy0); -+ if (ret < 0) -+ drm_warn(vop2->drm, -+ "Could not switch to HDMI0 PHY PLL: %d\n", ret); -+ break; -+ } -+ } -+ } -+ - clk_set_rate(vp->dclk, clock); - - vop2_post_config(crtc); -@@ -3699,6 +3727,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) - return PTR_ERR(vop2->pclk); - } - -+ vop2->pll_hdmiphy0 = devm_clk_get_optional(vop2->dev, "pll_hdmiphy0"); -+ if (IS_ERR(vop2->pll_hdmiphy0)) { -+ drm_err(vop2->drm, "failed to get pll_hdmiphy0\n"); -+ return PTR_ERR(vop2->pll_hdmiphy0); -+ } -+ - vop2->irq = platform_get_irq(pdev, 0); - if (vop2->irq < 0) { - drm_err(vop2->drm, "cannot find irq for vop2\n"); --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Tue, 16 Jan 2024 03:13:38 +0200 -Subject: arm64: dts: rockchip: Enable HDMI0 PHY clk provider on RK3588 - -Since commit c4b09c562086 ("phy: phy-rockchip-samsung-hdptx: Add clock -provider support"), the HDMI PHY PLL can be used as an alternative and -more accurate pixel clock source for VOP2 to improve display modes -handling on RK3588 SoC. - -Add the missing #clock-cells property to allow using the clock provider -functionality of HDMI0 PHY. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -@@ -2812,6 +2812,7 @@ hdptxphy_hdmi0: phy@fed60000 { - reg = <0x0 0xfed60000 0x0 0x2000>; - clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>, <&cru PCLK_HDPTX0>; - clock-names = "ref", "apb"; -+ #clock-cells = <0>; - #phy-cells = <0>; - resets = <&cru SRST_HDPTX0>, <&cru SRST_P_HDPTX0>, - <&cru SRST_HDPTX0_INIT>, <&cru SRST_HDPTX0_CMN>, --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 16 Nov 2024 04:33:46 +0200 -Subject: arm64: dts: rockchip: Add HDMI0 PHY PLL clock source to VOP2 on - RK3588 - -VOP2 on RK3588 is able to use the HDMI PHY PLL as an alternative and -more accurate pixel clock source to improve handling of display modes up -to 4K@60Hz on video ports 0, 1 and 2. - -For now only HDMI0 output is supported, hence add the related PLL clock. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -@@ -1261,14 +1261,16 @@ vop: vop@fdd90000 { - <&cru DCLK_VOP1>, - <&cru DCLK_VOP2>, - <&cru DCLK_VOP3>, -- <&cru PCLK_VOP_ROOT>; -+ <&cru PCLK_VOP_ROOT>, -+ <&hdptxphy_hdmi0>; - clock-names = "aclk", - "hclk", - "dclk_vp0", - "dclk_vp1", - "dclk_vp2", - "dclk_vp3", -- "pclk_vop"; -+ "pclk_vop", -+ "pll_hdmiphy0"; - iommus = <&vop_mmu>; - power-domains = <&power RK3588_PD_VOP>; - rockchip,grf = <&sys_grf>; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-0132-Fix-label-name-of-hdptxphy-for-RK3588.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-0132-Fix-label-name-of-hdptxphy-for-RK3588.patch deleted file mode 100644 index d0be509478..0000000000 --- a/patch/kernel/archive/rockchip64-6.15/rk3588-0132-Fix-label-name-of-hdptxphy-for-RK3588.patch +++ /dev/null @@ -1,318 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Damon Ding -Date: Thu, 6 Feb 2025 11:03:30 +0800 -Subject: arm64: dts: rockchip: Fix label name of hdptxphy for RK3588 - -The hdptxphy is a combo transmit-PHY for HDMI2.1 TMDS Link, FRL Link, DP -and eDP Link. Therefore, it is better to name it hdptxphy0 other than -hdptxphy_hdmi0, which will be referenced by both hdmi0 and edp0 nodes. - -Signed-off-by: Damon Ding -Link: https://lore.kernel.org/r/20250206030330.680424-3-damon.ding@rock-chips.com -[added armsom-sige7, where hdmi-support was added recently and also - the hdptxphy0-as-dclk source I just added] -Signed-off-by: Heiko Stuebner ---- - arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 6 +++--- - arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dts | 2 +- - 20 files changed, 22 insertions(+), 22 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -@@ -1262,7 +1262,7 @@ vop: vop@fdd90000 { - <&cru DCLK_VOP2>, - <&cru DCLK_VOP3>, - <&cru PCLK_VOP_ROOT>, -- <&hdptxphy_hdmi0>; -+ <&hdptxphy0>; - clock-names = "aclk", - "hclk", - "dclk_vp0", -@@ -1387,7 +1387,7 @@ hdmi0: hdmi@fde80000 { - , - ; - interrupt-names = "avp", "cec", "earc", "main", "hpd"; -- phys = <&hdptxphy_hdmi0>; -+ phys = <&hdptxphy0>; - pinctrl-names = "default"; - pinctrl-0 = <&hdmim0_tx0_cec &hdmim0_tx0_hpd - &hdmim0_tx0_scl &hdmim0_tx0_sda>; -@@ -2809,7 +2809,7 @@ dmac2: dma-controller@fed10000 { - #dma-cells = <1>; - }; - -- hdptxphy_hdmi0: phy@fed60000 { -+ hdptxphy0: phy@fed60000 { - compatible = "rockchip,rk3588-hdptx-phy"; - reg = <0x0 0xfed60000 0x0 0x2000>; - clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>, <&cru PCLK_HDPTX0>; -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts -@@ -129,7 +129,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts -@@ -166,7 +166,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -@@ -364,7 +364,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dts b/arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dts -@@ -337,7 +337,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts -@@ -335,7 +335,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dts b/arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dts -@@ -207,7 +207,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts -@@ -303,7 +303,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi -@@ -360,7 +360,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts -@@ -39,7 +39,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -@@ -125,7 +125,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -@@ -220,7 +220,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts -@@ -189,7 +189,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts b/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts -@@ -236,7 +236,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts b/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts -@@ -278,7 +278,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi -@@ -251,7 +251,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts b/arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts -@@ -266,7 +266,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi -@@ -197,7 +197,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts -@@ -334,7 +334,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dts b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dts -@@ -278,7 +278,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-0133-vop2-hdmi1-disp-modes-support.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-0133-vop2-hdmi1-disp-modes-support.patch deleted file mode 100644 index 5e87f2459d..0000000000 --- a/patch/kernel/archive/rockchip64-6.15/rk3588-0133-vop2-hdmi1-disp-modes-support.patch +++ /dev/null @@ -1,173 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 15 Feb 2025 02:55:37 +0200 -Subject: drm/rockchip: vop2: Improve display modes handling on RK3588 HDMI1 - -The RK3588 specific implementation is currently quite limited in terms -of handling the full range of display modes supported by the connected -screens, e.g. 2560x1440@75Hz, 2048x1152@60Hz, 1024x768@60Hz are just a -few of them. - -Additionally, it doesn't cope well with non-integer refresh rates like -59.94, 29.97, 23.98, etc. - -Make use of HDMI1 PHY PLL as a more accurate DCLK source to handle -all display modes up to 4K@60Hz. - -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 26 +++++++++- - 1 file changed, 25 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -@@ -216,6 +216,7 @@ struct vop2 { - struct clk *aclk; - struct clk *pclk; - struct clk *pll_hdmiphy0; -+ struct clk *pll_hdmiphy1; - - /* optional internal rgb encoder */ - struct rockchip_rgb *rgb; -@@ -2270,11 +2271,14 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - * Switch to HDMI PHY PLL as DCLK source for display modes up - * to 4K@60Hz, if available, otherwise keep using the system CRU. - */ -- if (vop2->pll_hdmiphy0 && clock <= VOP2_MAX_DCLK_RATE) { -+ if ((vop2->pll_hdmiphy0 || vop2->pll_hdmiphy1) && clock <= VOP2_MAX_DCLK_RATE) { - drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { - struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); - - if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) { -+ if (!vop2->pll_hdmiphy0) -+ break; -+ - if (!vp->dclk_src) - vp->dclk_src = clk_get_parent(vp->dclk); - -@@ -2284,6 +2288,20 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - "Could not switch to HDMI0 PHY PLL: %d\n", ret); - break; - } -+ -+ if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI1) { -+ if (!vop2->pll_hdmiphy1) -+ break; -+ -+ if (!vp->dclk_src) -+ vp->dclk_src = clk_get_parent(vp->dclk); -+ -+ ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy1); -+ if (ret < 0) -+ drm_warn(vop2->drm, -+ "Could not switch to HDMI1 PHY PLL: %d\n", ret); -+ break; -+ } - } - } - -@@ -3733,6 +3751,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) - return PTR_ERR(vop2->pll_hdmiphy0); - } - -+ vop2->pll_hdmiphy1 = devm_clk_get_optional(vop2->dev, "pll_hdmiphy1"); -+ if (IS_ERR(vop2->pll_hdmiphy1)) { -+ drm_err(vop2->drm, "failed to get pll_hdmiphy1\n"); -+ return PTR_ERR(vop2->pll_hdmiphy1); -+ } -+ - vop2->irq = platform_get_irq(pdev, 0); - if (vop2->irq < 0) { - drm_err(vop2->drm, "cannot find irq for vop2\n"); --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 15 Feb 2025 02:55:38 +0200 -Subject: arm64: dts: rockchip: Enable HDMI1 PHY clk provider on RK3588 - -Since commit c4b09c562086 ("phy: phy-rockchip-samsung-hdptx: Add clock -provider support"), the HDMI PHY PLL can be used as an alternative and -more accurate pixel clock source for VOP2 to improve display modes -handling on RK3588 SoC. - -Add the missing #clock-cells property to allow using the clock provider -functionality of HDMI1 PHY. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -@@ -505,6 +505,7 @@ hdptxphy1: phy@fed70000 { - reg = <0x0 0xfed70000 0x0 0x2000>; - clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>, <&cru PCLK_HDPTX1>; - clock-names = "ref", "apb"; -+ #clock-cells = <0>; - #phy-cells = <0>; - resets = <&cru SRST_HDPTX1>, <&cru SRST_P_HDPTX1>, - <&cru SRST_HDPTX1_INIT>, <&cru SRST_HDPTX1_CMN>, --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 15 Feb 2025 02:55:39 +0200 -Subject: arm64: dts: rockchip: Add HDMI1 PHY PLL clock source to VOP2 on - RK3588 - -VOP2 on RK3588 is able to use the HDMI PHY PLL as an alternative and -more accurate pixel clock source to improve handling of display modes up -to 4K@60Hz on video ports 0, 1 and 2. - -The HDMI1 PHY PLL clock source cannot be added directly to vop node in -rk3588-base.dtsi, along with the HDMI0 related one, because HDMI1 is an -optional feature and its PHY node belongs to a separate (extra) DT file. - -Therefore, add the HDMI1 PHY PLL clock source to VOP2 by overwriting its -clocks & clock-names properties in the extra DT file. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 21 ++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -@@ -568,3 +568,24 @@ pcie30phy: phy@fee80000 { - status = "disabled"; - }; - }; -+ -+&vop { -+ clocks = <&cru ACLK_VOP>, -+ <&cru HCLK_VOP>, -+ <&cru DCLK_VOP0>, -+ <&cru DCLK_VOP1>, -+ <&cru DCLK_VOP2>, -+ <&cru DCLK_VOP3>, -+ <&cru PCLK_VOP_ROOT>, -+ <&hdptxphy0>, -+ <&hdptxphy1>; -+ clock-names = "aclk", -+ "hclk", -+ "dclk_vp0", -+ "dclk_vp1", -+ "dclk_vp2", -+ "dclk_vp3", -+ "pclk_vop", -+ "pll_hdmiphy0", -+ "pll_hdmiphy1"; -+}; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-0134-clk-check-for-disabled-clock-provider-in-of_clk_get_.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-0134-clk-check-for-disabled-clock-provider-in-of_clk_get_.patch deleted file mode 100644 index 16465a63b0..0000000000 --- a/patch/kernel/archive/rockchip64-6.15/rk3588-0134-clk-check-for-disabled-clock-provider-in-of_clk_get_.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Heiko Stuebner -Date: Thu, 20 Feb 2025 23:54:48 +0100 -Subject: clk: check for disabled clock-provider in of_clk_get_hw_from_clkspec - -of_clk_get_hw_from_clkspec checks all available clock-providers by -compairing their of-nodes to the one from the clkspec. If no matching -clock-provider is found, the function returns EPROBE_DEFER to cause a -re-check at a later date. - -If a matching clock-provider is found, a authoritative answer can be -retrieved from it whether the clock exists or not. - -This does not take into account that the clock-provider may never appear, -because it's node is disabled. This can happen for example when a clock -is optional, provided by a separate block which just never gets enabled. - -One example of this happening is the rk3588's VOP, which has optional -additional display-clock-supplies coming from PLLs inside the hdmiphy -blocks. These can be used for better rates, but the system will also -work without them. - -The problem around that is described in the followups to: -https://lore.kernel.org/dri-devel/20250215-vop2-hdmi1-disp-modes-v1-3-81962a7151d6@collabora.com/ - -As we already know the of-node of the presumed clock-provider, just add -a check via of_device_is_available whether this is a "valid" device node. -This prevents ethernal defer-loops. - -Signed-off-by: Heiko Stuebner ---- - drivers/clk/clk.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c -index 111111111111..222222222222 100644 ---- a/drivers/clk/clk.c -+++ b/drivers/clk/clk.c -@@ -5258,6 +5258,10 @@ of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec) - if (!clkspec) - return ERR_PTR(-EINVAL); - -+ /* Check if node in clkspec is in disabled/fail state */ -+ if (!of_device_is_available(clkspec->np)) -+ return ERR_PTR(-ENOENT); -+ - mutex_lock(&of_clk_mutex); - list_for_each_entry(provider, &of_clk_providers, link) { - if (provider->node == clkspec->np) { --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-0180-drm-bridge-dw-hdmi-qp.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-0180-drm-bridge-dw-hdmi-qp.patch deleted file mode 100644 index bce285c85f..0000000000 --- a/patch/kernel/archive/rockchip64-6.15/rk3588-0180-drm-bridge-dw-hdmi-qp.patch +++ /dev/null @@ -1,580 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: palachzzz <7zzzzzzz@mail.ru> -Date: Thu, 27 Feb 2025 23:06:51 +0800 -Subject: [ARCHEOLOGY] RK3588 add HDMI sound, add support for OPi5 Max #7884 - -> X-Git-Archeology: - Revision 0b88561ec332114404ff8075ab6bc2419ca66a47: https://github.com/armbian/build/commit/0b88561ec332114404ff8075ab6bc2419ca66a47 -> X-Git-Archeology: Date: Thu, 27 Feb 2025 23:06:51 +0800 -> X-Git-Archeology: From: palachzzz <7zzzzzzz@mail.ru> -> X-Git-Archeology: Subject: RK3588 add HDMI sound, add support for OPi5 Max #7884 -> X-Git-Archeology: ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 489 ++++++++++ - 1 file changed, 489 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c -@@ -36,6 +36,88 @@ - - #define SCRAMB_POLL_DELAY_MS 3000 - -+/* -+ * Unless otherwise noted, entries in this table are 100% optimization. -+ * Values can be obtained from dw_hdmi_qp_compute_n() but that function is -+ * slow so we pre-compute values we expect to see. -+ * -+ * The values for TMDS 25175, 25200, 27000, 54000, 74250 and 148500 kHz are -+ * the recommended N values specified in the Audio chapter of the HDMI -+ * specification. -+ */ -+static const struct dw_hdmi_audio_tmds_n { -+ unsigned long tmds; -+ unsigned int n_32k; -+ unsigned int n_44k1; -+ unsigned int n_48k; -+} common_tmds_n_table[] = { -+ { .tmds = 25175000, .n_32k = 4576, .n_44k1 = 7007, .n_48k = 6864, }, -+ { .tmds = 25200000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 27000000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 28320000, .n_32k = 4096, .n_44k1 = 5586, .n_48k = 6144, }, -+ { .tmds = 30240000, .n_32k = 4096, .n_44k1 = 5642, .n_48k = 6144, }, -+ { .tmds = 31500000, .n_32k = 4096, .n_44k1 = 5600, .n_48k = 6144, }, -+ { .tmds = 32000000, .n_32k = 4096, .n_44k1 = 5733, .n_48k = 6144, }, -+ { .tmds = 33750000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 36000000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, }, -+ { .tmds = 40000000, .n_32k = 4096, .n_44k1 = 5733, .n_48k = 6144, }, -+ { .tmds = 49500000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, }, -+ { .tmds = 50000000, .n_32k = 4096, .n_44k1 = 5292, .n_48k = 6144, }, -+ { .tmds = 54000000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 65000000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, }, -+ { .tmds = 68250000, .n_32k = 4096, .n_44k1 = 5376, .n_48k = 6144, }, -+ { .tmds = 71000000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, }, -+ { .tmds = 72000000, .n_32k = 4096, .n_44k1 = 5635, .n_48k = 6144, }, -+ { .tmds = 73250000, .n_32k = 11648, .n_44k1 = 14112, .n_48k = 6144, }, -+ { .tmds = 74250000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 75000000, .n_32k = 4096, .n_44k1 = 5880, .n_48k = 6144, }, -+ { .tmds = 78750000, .n_32k = 4096, .n_44k1 = 5600, .n_48k = 6144, }, -+ { .tmds = 78800000, .n_32k = 4096, .n_44k1 = 5292, .n_48k = 6144, }, -+ { .tmds = 79500000, .n_32k = 4096, .n_44k1 = 4704, .n_48k = 6144, }, -+ { .tmds = 83500000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, }, -+ { .tmds = 85500000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, }, -+ { .tmds = 88750000, .n_32k = 4096, .n_44k1 = 14112, .n_48k = 6144, }, -+ { .tmds = 97750000, .n_32k = 4096, .n_44k1 = 14112, .n_48k = 6144, }, -+ { .tmds = 101000000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, }, -+ { .tmds = 106500000, .n_32k = 4096, .n_44k1 = 4704, .n_48k = 6144, }, -+ { .tmds = 108000000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, }, -+ { .tmds = 115500000, .n_32k = 4096, .n_44k1 = 5712, .n_48k = 6144, }, -+ { .tmds = 119000000, .n_32k = 4096, .n_44k1 = 5544, .n_48k = 6144, }, -+ { .tmds = 135000000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, }, -+ { .tmds = 146250000, .n_32k = 11648, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 148500000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 154000000, .n_32k = 4096, .n_44k1 = 5544, .n_48k = 6144, }, -+ { .tmds = 162000000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, }, -+ -+ /* For 297 MHz+ HDMI spec have some other rule for setting N */ -+ { .tmds = 297000000, .n_32k = 3073, .n_44k1 = 4704, .n_48k = 5120, }, -+ { .tmds = 594000000, .n_32k = 3073, .n_44k1 = 9408, .n_48k = 10240,}, -+ -+ /* End of table */ -+ { .tmds = 0, .n_32k = 0, .n_44k1 = 0, .n_48k = 0, }, -+}; -+ -+/* -+ * These are the CTS values as recommended in the Audio chapter of the HDMI -+ * specification. -+ */ -+static const struct dw_hdmi_audio_tmds_cts { -+ unsigned long tmds; -+ unsigned int cts_32k; -+ unsigned int cts_44k1; -+ unsigned int cts_48k; -+} common_tmds_cts_table[] = { -+ { .tmds = 25175000, .cts_32k = 28125, .cts_44k1 = 31250, .cts_48k = 28125, }, -+ { .tmds = 25200000, .cts_32k = 25200, .cts_44k1 = 28000, .cts_48k = 25200, }, -+ { .tmds = 27000000, .cts_32k = 27000, .cts_44k1 = 30000, .cts_48k = 27000, }, -+ { .tmds = 54000000, .cts_32k = 54000, .cts_44k1 = 60000, .cts_48k = 54000, }, -+ { .tmds = 74250000, .cts_32k = 74250, .cts_44k1 = 82500, .cts_48k = 74250, }, -+ { .tmds = 148500000, .cts_32k = 148500, .cts_44k1 = 165000, .cts_48k = 148500, }, -+ -+ /* End of table */ -+ { .tmds = 0, .cts_32k = 0, .cts_44k1 = 0, .cts_48k = 0, }, -+}; -+ - struct dw_hdmi_qp_i2c { - struct i2c_adapter adap; - -@@ -60,6 +142,8 @@ struct dw_hdmi_qp { - } phy; - - struct regmap *regm; -+ -+ unsigned long tmds_char_rate; - }; - - static void dw_hdmi_qp_write(struct dw_hdmi_qp *hdmi, unsigned int val, -@@ -83,6 +167,346 @@ static void dw_hdmi_qp_mod(struct dw_hdmi_qp *hdmi, unsigned int data, - regmap_update_bits(hdmi->regm, reg, mask, data); - } - -+static struct dw_hdmi_qp *dw_hdmi_qp_from_bridge(struct drm_bridge *bridge) -+{ -+ return container_of(bridge, struct dw_hdmi_qp, bridge); -+} -+ -+static void dw_hdmi_qp_set_cts_n(struct dw_hdmi_qp *hdmi, unsigned int cts, -+ unsigned int n) -+{ -+ /* Set N */ -+ dw_hdmi_qp_mod(hdmi, n, AUDPKT_ACR_N_VALUE, AUDPKT_ACR_CONTROL0); -+ -+ /* Set CTS */ -+ if (cts) -+ dw_hdmi_qp_mod(hdmi, AUDPKT_ACR_CTS_OVR_EN, AUDPKT_ACR_CTS_OVR_EN_MSK, -+ AUDPKT_ACR_CONTROL1); -+ else -+ dw_hdmi_qp_mod(hdmi, 0, AUDPKT_ACR_CTS_OVR_EN_MSK, -+ AUDPKT_ACR_CONTROL1); -+ -+ dw_hdmi_qp_mod(hdmi, AUDPKT_ACR_CTS_OVR_VAL(cts), AUDPKT_ACR_CTS_OVR_VAL_MSK, -+ AUDPKT_ACR_CONTROL1); -+} -+ -+static int dw_hdmi_qp_match_tmds_n_table(struct dw_hdmi_qp *hdmi, -+ unsigned long pixel_clk, -+ unsigned long freq) -+{ -+ const struct dw_hdmi_audio_tmds_n *tmds_n = NULL; -+ int i; -+ -+ for (i = 0; common_tmds_n_table[i].tmds != 0; i++) { -+ if (pixel_clk == common_tmds_n_table[i].tmds) { -+ tmds_n = &common_tmds_n_table[i]; -+ break; -+ } -+ } -+ -+ if (!tmds_n) -+ return -ENOENT; -+ -+ switch (freq) { -+ case 32000: -+ return tmds_n->n_32k; -+ case 44100: -+ case 88200: -+ case 176400: -+ return (freq / 44100) * tmds_n->n_44k1; -+ case 48000: -+ case 96000: -+ case 192000: -+ return (freq / 48000) * tmds_n->n_48k; -+ default: -+ return -ENOENT; -+ } -+} -+ -+static u32 dw_hdmi_qp_audio_math_diff(unsigned int freq, unsigned int n, -+ unsigned int pixel_clk) -+{ -+ u64 cts = mul_u32_u32(pixel_clk, n); -+ -+ return do_div(cts, 128 * freq); -+} -+ -+static unsigned int dw_hdmi_qp_compute_n(struct dw_hdmi_qp *hdmi, -+ unsigned long pixel_clk, -+ unsigned long freq) -+{ -+ unsigned int min_n = DIV_ROUND_UP((128 * freq), 1500); -+ unsigned int max_n = (128 * freq) / 300; -+ unsigned int ideal_n = (128 * freq) / 1000; -+ unsigned int best_n_distance = ideal_n; -+ unsigned int best_n = 0; -+ u64 best_diff = U64_MAX; -+ int n; -+ -+ /* If the ideal N could satisfy the audio math, then just take it */ -+ if (dw_hdmi_qp_audio_math_diff(freq, ideal_n, pixel_clk) == 0) -+ return ideal_n; -+ -+ for (n = min_n; n <= max_n; n++) { -+ u64 diff = dw_hdmi_qp_audio_math_diff(freq, n, pixel_clk); -+ -+ if (diff < best_diff || -+ (diff == best_diff && abs(n - ideal_n) < best_n_distance)) { -+ best_n = n; -+ best_diff = diff; -+ best_n_distance = abs(best_n - ideal_n); -+ } -+ -+ /* -+ * The best N already satisfy the audio math, and also be -+ * the closest value to ideal N, so just cut the loop. -+ */ -+ if (best_diff == 0 && (abs(n - ideal_n) > best_n_distance)) -+ break; -+ } -+ -+ return best_n; -+} -+ -+static unsigned int dw_hdmi_qp_find_n(struct dw_hdmi_qp *hdmi, unsigned long pixel_clk, -+ unsigned long sample_rate) -+{ -+ int n = dw_hdmi_qp_match_tmds_n_table(hdmi, pixel_clk, sample_rate); -+ -+ if (n > 0) -+ return n; -+ -+ dev_warn(hdmi->dev, "Rate %lu missing; compute N dynamically\n", -+ pixel_clk); -+ -+ return dw_hdmi_qp_compute_n(hdmi, pixel_clk, sample_rate); -+} -+ -+static unsigned int dw_hdmi_qp_find_cts(struct dw_hdmi_qp *hdmi, unsigned long pixel_clk, -+ unsigned long sample_rate) -+{ -+ const struct dw_hdmi_audio_tmds_cts *tmds_cts = NULL; -+ int i; -+ -+ for (i = 0; common_tmds_cts_table[i].tmds != 0; i++) { -+ if (pixel_clk == common_tmds_cts_table[i].tmds) { -+ tmds_cts = &common_tmds_cts_table[i]; -+ break; -+ } -+ } -+ -+ if (!tmds_cts) -+ return 0; -+ -+ switch (sample_rate) { -+ case 32000: -+ return tmds_cts->cts_32k; -+ case 44100: -+ case 88200: -+ case 176400: -+ return tmds_cts->cts_44k1; -+ case 48000: -+ case 96000: -+ case 192000: -+ return tmds_cts->cts_48k; -+ default: -+ return -ENOENT; -+ } -+} -+ -+static void dw_hdmi_qp_set_audio_interface(struct dw_hdmi_qp *hdmi, -+ struct hdmi_codec_daifmt *fmt, -+ struct hdmi_codec_params *hparms) -+{ -+ u32 conf0 = 0; -+ -+ /* Reset the audio data path of the AVP */ -+ dw_hdmi_qp_write(hdmi, AVP_DATAPATH_PACKET_AUDIO_SWINIT_P, GLOBAL_SWRESET_REQUEST); -+ -+ /* Disable AUDS, ACR, AUDI */ -+ dw_hdmi_qp_mod(hdmi, 0, -+ PKTSCHED_ACR_TX_EN | PKTSCHED_AUDS_TX_EN | PKTSCHED_AUDI_TX_EN, -+ PKTSCHED_PKT_EN); -+ -+ /* Clear the audio FIFO */ -+ dw_hdmi_qp_write(hdmi, AUDIO_FIFO_CLR_P, AUDIO_INTERFACE_CONTROL0); -+ -+ /* Select I2S interface as the audio source */ -+ dw_hdmi_qp_mod(hdmi, AUD_IF_I2S, AUD_IF_SEL_MSK, AUDIO_INTERFACE_CONFIG0); -+ -+ /* Enable the active i2s lanes */ -+ switch (hparms->channels) { -+ case 7 ... 8: -+ conf0 |= I2S_LINES_EN(3); -+ fallthrough; -+ case 5 ... 6: -+ conf0 |= I2S_LINES_EN(2); -+ fallthrough; -+ case 3 ... 4: -+ conf0 |= I2S_LINES_EN(1); -+ fallthrough; -+ default: -+ conf0 |= I2S_LINES_EN(0); -+ break; -+ } -+ -+ dw_hdmi_qp_mod(hdmi, conf0, I2S_LINES_EN_MSK, AUDIO_INTERFACE_CONFIG0); -+ -+ /* -+ * Enable bpcuv generated internally for L-PCM, or received -+ * from stream for NLPCM/HBR. -+ */ -+ switch (fmt->bit_fmt) { -+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: -+ conf0 = (hparms->channels == 8) ? AUD_HBR : AUD_ASP; -+ conf0 |= I2S_BPCUV_RCV_EN; -+ break; -+ default: -+ conf0 = AUD_ASP | I2S_BPCUV_RCV_DIS; -+ break; -+ } -+ -+ dw_hdmi_qp_mod(hdmi, conf0, I2S_BPCUV_RCV_MSK | AUD_FORMAT_MSK, -+ AUDIO_INTERFACE_CONFIG0); -+ -+ /* Enable audio FIFO auto clear when overflow */ -+ dw_hdmi_qp_mod(hdmi, AUD_FIFO_INIT_ON_OVF_EN, AUD_FIFO_INIT_ON_OVF_MSK, -+ AUDIO_INTERFACE_CONFIG0); -+} -+ -+/* -+ * When transmitting IEC60958 linear PCM audio, these registers allow to -+ * configure the channel status information of all the channel status -+ * bits in the IEC60958 frame. For the moment this configuration is only -+ * used when the I2S audio interface, General Purpose Audio (GPA), -+ * or AHB audio DMA (AHBAUDDMA) interface is active -+ * (for S/PDIF interface this information comes from the stream). -+ */ -+static void dw_hdmi_qp_set_channel_status(struct dw_hdmi_qp *hdmi, -+ u8 *channel_status, bool ref2stream) -+{ -+ /* -+ * AUDPKT_CHSTATUS_OVR0: { RSV, RSV, CS1, CS0 } -+ * AUDPKT_CHSTATUS_OVR1: { CS6, CS5, CS4, CS3 } -+ * -+ * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | -+ * CS0: | Mode | d | c | b | a | -+ * CS1: | Category Code | -+ * CS2: | Channel Number | Source Number | -+ * CS3: | Clock Accuracy | Sample Freq | -+ * CS4: | Ori Sample Freq | Word Length | -+ * CS5: | | CGMS-A | -+ * CS6~CS23: Reserved -+ * -+ * a: use of channel status block -+ * b: linear PCM identification: 0 for lpcm, 1 for nlpcm -+ * c: copyright information -+ * d: additional format information -+ */ -+ -+ if (ref2stream) -+ channel_status[0] |= IEC958_AES0_NONAUDIO; -+ -+ if ((dw_hdmi_qp_read(hdmi, AUDIO_INTERFACE_CONFIG0) & GENMASK(25, 24)) == AUD_HBR) { -+ /* fixup cs for HBR */ -+ channel_status[3] = (channel_status[3] & 0xf0) | IEC958_AES3_CON_FS_768000; -+ channel_status[4] = (channel_status[4] & 0x0f) | IEC958_AES4_CON_ORIGFS_NOTID; -+ } -+ -+ dw_hdmi_qp_write(hdmi, channel_status[0] | (channel_status[1] << 8), -+ AUDPKT_CHSTATUS_OVR0); -+ -+ regmap_bulk_write(hdmi->regm, AUDPKT_CHSTATUS_OVR1, &channel_status[3], 1); -+ -+ if (ref2stream) -+ dw_hdmi_qp_mod(hdmi, 0, -+ AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK, -+ AUDPKT_CONTROL0); -+ else -+ dw_hdmi_qp_mod(hdmi, AUDPKT_PBIT_FORCE_EN | AUDPKT_CHSTATUS_OVR_EN, -+ AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK, -+ AUDPKT_CONTROL0); -+} -+ -+static void dw_hdmi_qp_set_sample_rate(struct dw_hdmi_qp *hdmi, unsigned long long tmds_char_rate, -+ unsigned int sample_rate) -+{ -+ unsigned int n, cts; -+ -+ n = dw_hdmi_qp_find_n(hdmi, tmds_char_rate, sample_rate); -+ cts = dw_hdmi_qp_find_cts(hdmi, tmds_char_rate, sample_rate); -+ -+ dw_hdmi_qp_set_cts_n(hdmi, cts, n); -+} -+ -+static int dw_hdmi_qp_audio_enable(struct drm_connector *connector, -+ struct drm_bridge *bridge) -+{ -+ struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge); -+ -+ if (hdmi->tmds_char_rate) -+ dw_hdmi_qp_mod(hdmi, 0, AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, GLOBAL_SWDISABLE); -+ -+ return 0; -+} -+ -+static int dw_hdmi_qp_audio_prepare(struct drm_connector *connector, -+ struct drm_bridge *bridge, -+ struct hdmi_codec_daifmt *fmt, -+ struct hdmi_codec_params *hparms) -+{ -+ struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge); -+ bool ref2stream = false; -+ -+ if (!hdmi->tmds_char_rate) -+ return -ENODEV; -+ -+ if (fmt->bit_clk_provider | fmt->frame_clk_provider) { -+ dev_err(hdmi->dev, "unsupported clock settings\n"); -+ return -EINVAL; -+ } -+ -+ if (fmt->bit_fmt == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE) -+ ref2stream = true; -+ -+ dw_hdmi_qp_set_audio_interface(hdmi, fmt, hparms); -+ dw_hdmi_qp_set_sample_rate(hdmi, hdmi->tmds_char_rate, hparms->sample_rate); -+ dw_hdmi_qp_set_channel_status(hdmi, hparms->iec.status, ref2stream); -+ drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector, &hparms->cea); -+ -+ return 0; -+} -+ -+static void dw_hdmi_qp_audio_disable_regs(struct dw_hdmi_qp *hdmi) -+{ -+ /* -+ * Keep ACR, AUDI, AUDS packet always on to make SINK device -+ * active for better compatibility and user experience. -+ * -+ * This also fix POP sound on some SINK devices which wakeup -+ * from suspend to active. -+ */ -+ dw_hdmi_qp_mod(hdmi, I2S_BPCUV_RCV_DIS, I2S_BPCUV_RCV_MSK, -+ AUDIO_INTERFACE_CONFIG0); -+ dw_hdmi_qp_mod(hdmi, AUDPKT_PBIT_FORCE_EN | AUDPKT_CHSTATUS_OVR_EN, -+ AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK, -+ AUDPKT_CONTROL0); -+ -+ dw_hdmi_qp_mod(hdmi, AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, -+ AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, GLOBAL_SWDISABLE); -+} -+ -+static void dw_hdmi_qp_audio_disable(struct drm_connector *connector, -+ struct drm_bridge *bridge) -+{ -+ struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge); -+ -+ drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector); -+ -+ if (hdmi->tmds_char_rate) -+ dw_hdmi_qp_audio_disable_regs(hdmi); -+} -+ - static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi, - unsigned char *buf, unsigned int length) - { -@@ -361,6 +785,51 @@ static int dw_hdmi_qp_config_drm_infoframe(struct dw_hdmi_qp *hdmi, - return 0; - } - -+/* -+ * Static values documented in the TRM -+ * Different values are only used for debug purposes -+ */ -+#define DW_HDMI_QP_AUDIO_INFOFRAME_HB1 0x1 -+#define DW_HDMI_QP_AUDIO_INFOFRAME_HB2 0xa -+ -+static int dw_hdmi_qp_config_audio_infoframe(struct dw_hdmi_qp *hdmi, -+ const u8 *buffer, size_t len) -+{ -+ /* -+ * AUDI_CONTENTS0: { RSV, HB2, HB1, RSV } -+ * AUDI_CONTENTS1: { PB3, PB2, PB1, PB0 } -+ * AUDI_CONTENTS2: { PB7, PB6, PB5, PB4 } -+ * -+ * PB0: CheckSum -+ * PB1: | CT3 | CT2 | CT1 | CT0 | F13 | CC2 | CC1 | CC0 | -+ * PB2: | F27 | F26 | F25 | SF2 | SF1 | SF0 | SS1 | SS0 | -+ * PB3: | F37 | F36 | F35 | F34 | F33 | F32 | F31 | F30 | -+ * PB4: | CA7 | CA6 | CA5 | CA4 | CA3 | CA2 | CA1 | CA0 | -+ * PB5: | DM_INH | LSV3 | LSV2 | LSV1 | LSV0 | F52 | F51 | F50 | -+ * PB6~PB10: Reserved -+ * -+ * AUDI_CONTENTS0 default value defined by HDMI specification, -+ * and shall only be changed for debug purposes. -+ */ -+ u32 header_bytes = (DW_HDMI_QP_AUDIO_INFOFRAME_HB1 << 8) | -+ (DW_HDMI_QP_AUDIO_INFOFRAME_HB2 << 16); -+ -+ regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS0, &header_bytes, 1); -+ regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS1, &buffer[3], 1); -+ regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS2, &buffer[4], 1); -+ -+ /* Enable ACR, AUDI, AMD */ -+ dw_hdmi_qp_mod(hdmi, -+ PKTSCHED_ACR_TX_EN | PKTSCHED_AUDI_TX_EN | PKTSCHED_AMD_TX_EN, -+ PKTSCHED_ACR_TX_EN | PKTSCHED_AUDI_TX_EN | PKTSCHED_AMD_TX_EN, -+ PKTSCHED_PKT_EN); -+ -+ /* Enable AUDS */ -+ dw_hdmi_qp_mod(hdmi, PKTSCHED_AUDS_TX_EN, PKTSCHED_AUDS_TX_EN, PKTSCHED_PKT_EN); -+ -+ return 0; -+} -+ - static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_state) - { -@@ -382,6 +851,7 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge, - dev_dbg(hdmi->dev, "%s mode=HDMI rate=%llu\n", - __func__, conn_state->hdmi.tmds_char_rate); - op_mode = 0; -+ hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate; - } else { - dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__); - op_mode = OPMODE_DVI; -@@ -400,6 +870,8 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge, - { - struct dw_hdmi_qp *hdmi = bridge->driver_private; - -+ hdmi->tmds_char_rate = 0; -+ - hdmi->phy.ops->disable(hdmi, hdmi->phy.data); - } - -@@ -455,6 +927,13 @@ static int dw_hdmi_qp_bridge_clear_infoframe(struct drm_bridge *bridge, - dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); - break; - -+ case HDMI_INFOFRAME_TYPE_AUDIO: -+ dw_hdmi_qp_mod(hdmi, 0, -+ PKTSCHED_ACR_TX_EN | -+ PKTSCHED_AUDS_TX_EN | -+ PKTSCHED_AUDI_TX_EN, -+ PKTSCHED_PKT_EN); -+ break; - default: - dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); - } -@@ -477,6 +956,9 @@ static int dw_hdmi_qp_bridge_write_infoframe(struct drm_bridge *bridge, - case HDMI_INFOFRAME_TYPE_DRM: - return dw_hdmi_qp_config_drm_infoframe(hdmi, buffer, len); - -+ case HDMI_INFOFRAME_TYPE_AUDIO: -+ return dw_hdmi_qp_config_audio_infoframe(hdmi, buffer, len); -+ - default: - dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); - return 0; -@@ -494,6 +976,9 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = { - .hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid, - .hdmi_clear_infoframe = dw_hdmi_qp_bridge_clear_infoframe, - .hdmi_write_infoframe = dw_hdmi_qp_bridge_write_infoframe, -+ .hdmi_audio_startup = dw_hdmi_qp_audio_enable, -+ .hdmi_audio_shutdown = dw_hdmi_qp_audio_disable, -+ .hdmi_audio_prepare = dw_hdmi_qp_audio_prepare, - }; - - static irqreturn_t dw_hdmi_qp_main_hardirq(int irq, void *dev_id) -@@ -603,6 +1088,10 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, - if (IS_ERR(hdmi->bridge.ddc)) - return ERR_CAST(hdmi->bridge.ddc); - -+ hdmi->bridge.hdmi_audio_max_i2s_playback_channels = 8; -+ hdmi->bridge.hdmi_audio_dev = dev; -+ hdmi->bridge.hdmi_audio_dai_port = 1; -+ - ret = devm_drm_bridge_add(dev, &hdmi->bridge); - if (ret) - return ERR_PTR(ret); --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-1011-rock5b-hdmi1.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1011-rock5b-hdmi1.patch deleted file mode 100644 index 1417729240..0000000000 --- a/patch/kernel/archive/rockchip64-6.15/rk3588-1011-rock5b-hdmi1.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: amazingfate -Date: Thu, 26 Dec 2024 21:47:15 +0100 -Subject: [ARCHEOLOGY] rockchip64-6.13: add hdmi1 support to rock5b - -> X-Git-Archeology: - Revision 12bb4ea7dfd695901aba31ae4b5260398c932a17: https://github.com/armbian/build/commit/12bb4ea7dfd695901aba31ae4b5260398c932a17 -> X-Git-Archeology: Date: Thu, 26 Dec 2024 21:47:15 +0100 -> X-Git-Archeology: From: amazingfate -> X-Git-Archeology: Subject: rockchip64-6.13: add hdmi1 support to rock5b -> X-Git-Archeology: ---- - arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts | 44 +++++++++- - 1 file changed, 42 insertions(+), 2 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -@@ -49,6 +49,17 @@ hdmi0_con_in: endpoint { - }; - }; - -+ hdmi1-con { -+ compatible = "hdmi-connector"; -+ type = "a"; -+ -+ port { -+ hdmi1_con_in: endpoint { -+ remote-endpoint = <&hdmi1_out_con>; -+ }; -+ }; -+ }; -+ - leds { - compatible = "gpio-leds"; - pinctrl-names = "default"; -@@ -220,10 +231,32 @@ hdmi0_out_con: endpoint { - }; - }; - -+&hdmi1 { -+ pinctrl-0 = <&hdmim0_tx1_cec &hdmim0_tx1_hpd -+ &hdmim1_tx1_scl &hdmim1_tx1_sda>; -+ status = "okay"; -+}; -+ -+&hdmi1_in { -+ hdmi1_in_vp1: endpoint { -+ remote-endpoint = <&vp1_out_hdmi1>; -+ }; -+}; -+ -+&hdmi1_out { -+ hdmi1_out_con: endpoint { -+ remote-endpoint = <&hdmi1_con_in>; -+ }; -+}; -+ - &hdptxphy0 { - status = "okay"; - }; - -+&hdptxphy1 { -+ status = "okay"; -+}; -+ - &i2c0 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c0m2_xfer>; -@@ -896,11 +929,11 @@ &usb_host2_xhci { - status = "okay"; - }; - --&vop_mmu { -+&vop { - status = "okay"; - }; - --&vop { -+&vop_mmu { - status = "okay"; - }; - -@@ -910,3 +943,10 @@ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { - remote-endpoint = <&hdmi0_in_vp0>; - }; - }; -+ -+&vp1 { -+ vp1_out_hdmi1: endpoint@ROCKCHIP_VOP2_EP_HDMI1 { -+ reg = ; -+ remote-endpoint = <&hdmi1_in_vp1>; -+ }; -+}; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-1012-arm64-dts-rockchip-add-hdmi1-support-to-ROCK-5-ITX.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1012-arm64-dts-rockchip-add-hdmi1-support-to-ROCK-5-ITX.patch deleted file mode 100644 index 4abccfdae9..0000000000 --- a/patch/kernel/archive/rockchip64-6.15/rk3588-1012-arm64-dts-rockchip-add-hdmi1-support-to-ROCK-5-ITX.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jianfeng Liu -Date: Sat, 15 Feb 2025 23:10:42 +0800 -Subject: arm64: dts: rockchip: add hdmi1 support to ROCK 5 ITX - -Enable the HDMI port next to ethernet port. - -Signed-off-by: Jianfeng Liu ---- - arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts | 49 ++++++++++ - 1 file changed, 49 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - #include "dt-bindings/usb/pd.h" - #include "rk3588.dtsi" - -@@ -89,6 +90,17 @@ fan0: pwm-fan { - pwms = <&pwm14 0 10000 0>; - }; - -+ hdmi1-con { -+ compatible = "hdmi-connector"; -+ type = "a"; -+ -+ port { -+ hdmi1_con_in: endpoint { -+ remote-endpoint = <&hdmi1_out_con>; -+ }; -+ }; -+ }; -+ - /* M.2 E-KEY */ - sdio_pwrseq: sdio-pwrseq { - compatible = "mmc-pwrseq-simple"; -@@ -261,6 +273,28 @@ &gpu { - status = "okay"; - }; - -+&hdmi1 { -+ pinctrl-0 = <&hdmim0_tx1_cec &hdmim0_tx1_hpd -+ &hdmim1_tx1_scl &hdmim1_tx1_sda>; -+ status = "okay"; -+}; -+ -+&hdmi1_in { -+ hdmi1_in_vp1: endpoint { -+ remote-endpoint = <&vp1_out_hdmi1>; -+ }; -+}; -+ -+&hdmi1_out { -+ hdmi1_out_con: endpoint { -+ remote-endpoint = <&hdmi1_con_in>; -+ }; -+}; -+ -+&hdptxphy1 { -+ status = "okay"; -+}; -+ - &i2c0 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c0m2_xfer>; -@@ -1208,3 +1242,18 @@ &usbdp_phy1 { - rockchip,dp-lane-mux = <2 3>; - status = "okay"; - }; -+ -+&vop { -+ status = "okay"; -+}; -+ -+&vop_mmu { -+ status = "okay"; -+}; -+ -+&vp1 { -+ vp1_out_hdmi1: endpoint@ROCKCHIP_VOP2_EP_HDMI1 { -+ reg = ; -+ remote-endpoint = <&hdmi1_in_vp1>; -+ }; -+}; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-1031-arm64-dts-rockchip-Add-HDMI-support-to-ArmSoM-Sige7.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1031-arm64-dts-rockchip-Add-HDMI-support-to-ArmSoM-Sige7.patch deleted file mode 100644 index 2906ea40c5..0000000000 --- a/patch/kernel/archive/rockchip64-6.15/rk3588-1031-arm64-dts-rockchip-Add-HDMI-support-to-ArmSoM-Sige7.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jianfeng Liu -Date: Thu, 6 Jun 2024 23:28:01 +0800 -Subject: arm64: dts: rockchip: Add HDMI support to ArmSoM Sige7 - ---- - arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts | 30 ++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts b/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts -@@ -4,6 +4,7 @@ - - #include - #include -+#include - #include "rk3588.dtsi" - - / { -@@ -164,6 +165,20 @@ &gpu { - status = "okay"; - }; - -+&hdmi0 { -+ status = "okay"; -+}; -+ -+&hdmi0_in { -+ hdmi0_in_vp0: endpoint { -+ remote-endpoint = <&vp0_out_hdmi0>; -+ }; -+}; -+ -+&hdptxphy0 { -+ status = "okay"; -+}; -+ - &i2c0 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c0m2_xfer>; -@@ -723,3 +738,18 @@ &usb_host1_xhci { - dr_mode = "host"; - status = "okay"; - }; -+ -+&vop { -+ status = "okay"; -+}; -+ -+&vop_mmu { -+ status = "okay"; -+}; -+ -+&vp0 { -+ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { -+ reg = ; -+ remote-endpoint = <&hdmi0_in_vp0>; -+ }; -+}; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-1032-arm64-dts-rockchip-Add-ap6275p-wireless-support-to-A.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1032-arm64-dts-rockchip-Add-ap6275p-wireless-support-to-A.patch deleted file mode 100644 index 3cfaee0136..0000000000 --- a/patch/kernel/archive/rockchip64-6.15/rk3588-1032-arm64-dts-rockchip-Add-ap6275p-wireless-support-to-A.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jianfeng Liu -Date: Thu, 6 Jun 2024 23:29:39 +0800 -Subject: arm64: dts: rockchip: Add ap6275p wireless support to ArmSoM Sige7 - ---- - arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts | 16 ++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts b/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts -@@ -283,6 +283,22 @@ &pcie2x1l0 { - &pcie2x1l1 { - reset-gpios = <&gpio3 RK_PD4 GPIO_ACTIVE_HIGH>; - status = "okay"; -+ -+ pcie@0,0 { -+ reg = <0x300000 0 0 0 0>; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ ranges; -+ device_type = "pci"; -+ bus-range = <0x30 0x3f>; -+ -+ wifi: wifi@0,0 { -+ compatible = "pci14e4,449d"; -+ reg = <0x310000 0 0 0 0>; -+ clocks = <&hym8563>; -+ clock-names = "lpo"; -+ }; -+ }; - }; - - /* phy0 - left ethernet port */ --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-1102-arm64-dts-rockchip-Rock-5B-add-hdmi-sound.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1102-arm64-dts-rockchip-Rock-5B-add-hdmi-sound.patch deleted file mode 100644 index fc3c04f36b..0000000000 --- a/patch/kernel/archive/rockchip64-6.15/rk3588-1102-arm64-dts-rockchip-Rock-5B-add-hdmi-sound.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aleksey Komarov -Date: Sat, 8 Mar 2025 19:43:05 +0100 -Subject: [ARCHEOLOGY] Enable HDMI audio outputs for Rock 5B by - detlev.casanova@collabora.com - -> X-Git-Archeology: > recovered message: > https://lore.kernel.org/all/20250217215641.372723-4-detlev.casanova@collabora.com/ -> X-Git-Archeology: - Revision bf9ffa6eedd5df804e3f9a86c84e00607289cd59: https://github.com/armbian/build/commit/bf9ffa6eedd5df804e3f9a86c84e00607289cd59 -> X-Git-Archeology: Date: Sat, 08 Mar 2025 19:43:05 +0100 -> X-Git-Archeology: From: Aleksey Komarov -> X-Git-Archeology: Subject: Enable HDMI audio outputs for Rock 5B by detlev.casanova@collabora.com -> X-Git-Archeology: ---- - arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts | 16 ++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -@@ -231,6 +231,10 @@ hdmi0_out_con: endpoint { - }; - }; - -+&hdmi0_sound { -+ status = "okay"; -+}; -+ - &hdmi1 { - pinctrl-0 = <&hdmim0_tx1_cec &hdmim0_tx1_hpd - &hdmim1_tx1_scl &hdmim1_tx1_sda>; -@@ -249,6 +253,10 @@ hdmi1_out_con: endpoint { - }; - }; - -+&hdmi1_sound { -+ status = "okay"; -+}; -+ - &hdptxphy0 { - status = "okay"; - }; -@@ -351,6 +359,14 @@ i2s0_8ch_p0_0: endpoint { - }; - }; - -+&i2s5_8ch { -+ status = "okay"; -+}; -+ -+&i2s6_8ch { -+ status = "okay"; -+}; -+ - &package_thermal { - polling-delay = <1000>; - --- -Armbian -