From aa4f74184088ba53f7e5ebcf89945998d16257a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Wed, 26 Jun 2024 22:45:14 +0300 Subject: [PATCH] remove op5p --- data.nix | 6 - flake.nix | 42 - hosts/op5p/configuration.nix | 43 - hosts/vno1-oh2/configuration.nix | 8 - hosts/vno1-op5p/configuration.nix | 92 - secrets.nix | 3 +- shared/platform/orangepi5plus.nix | 65 - .../orangepi5plus/rk3588-crypto.patch | 2365 --- .../orangepi5plus/rk3588-v6.10-rc1.patch | 12673 ---------------- 9 files changed, 1 insertion(+), 15296 deletions(-) delete mode 100644 hosts/op5p/configuration.nix delete mode 100644 hosts/vno1-op5p/configuration.nix delete mode 100644 shared/platform/orangepi5plus.nix delete mode 100644 shared/platform/orangepi5plus/rk3588-crypto.patch delete mode 100644 shared/platform/orangepi5plus/rk3588-v6.10-rc1.patch diff --git a/data.nix b/data.nix index bfd4741..f66c40d 100644 --- a/data.nix +++ b/data.nix @@ -64,12 +64,6 @@ rec { publicIP = "88.223.107.21"; jakstIP = "100.89.176.4"; }; - "vno1-op5p.servers.jakst" = rec { - extraHostNames = [jakstIP vno1IP]; - publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILOB4Kv/bQGUD4pd3otqEMd69xmjguvIStRYoTP1wdhX root@vno1-op5p"; - jakstIP = "100.89.176.11"; - vno1IP = "192.168.189.12"; - }; "vno3-rp3b.servers.jakst" = rec { extraHostNames = [jakstIP]; publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBudUFFEBpUVdr26vLJup8Hk6wj1iDbOPPQnJbv6GUGC"; diff --git a/flake.nix b/flake.nix index 1db1c87..e8a84b0 100644 --- a/flake.nix +++ b/flake.nix @@ -138,36 +138,6 @@ vm-x86_64 = mkVM "x86_64-linux"; vm-aarch64 = mkVM "aarch64-linux"; - op5p = nixpkgs.lib.nixosSystem { - system = "aarch64-linux"; - modules = [ - {nixpkgs.overlays = overlays;} - ./hosts/op5p/configuration.nix - home-manager.nixosModules.home-manager - ]; - specialArgs = {inherit myData;} // inputs; - }; - - vno1-op5p = nixpkgs.lib.nixosSystem { - system = "aarch64-linux"; - modules = [ - {nixpkgs.overlays = overlays;} - ./hosts/vno1-op5p/configuration.nix - home-manager.nixosModules.home-manager - - agenix.nixosModules.default - { - age.secrets = { - motiejus-passwd-hash.file = ./secrets/motiejus_passwd_hash.age; - root-passwd-hash.file = ./secrets/root_passwd_hash.age; - sasl-passwd.file = ./secrets/postfix_sasl_passwd.age; - }; - } - ]; - - specialArgs = {inherit myData;} // inputs; - }; - mtworx = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ @@ -348,18 +318,6 @@ }; }; - vno1-op5p = { - hostname = myData.hosts."vno1-op5p.servers.jakst".jakstIP; - profiles = { - system = { - sshUser = "motiejus"; - path = - self.nixosConfigurations.vno1-op5p.pkgs.deploy-rs.lib.activate.nixos self.nixosConfigurations.vno1-op5p; - user = "root"; - }; - }; - }; - vno3-rp3b = { hostname = myData.hosts."vno3-rp3b.servers.jakst".jakstIP; profiles = { diff --git a/hosts/op5p/configuration.nix b/hosts/op5p/configuration.nix deleted file mode 100644 index dba0c9d..0000000 --- a/hosts/op5p/configuration.nix +++ /dev/null @@ -1,43 +0,0 @@ -{...}: { - imports = [ - ../../modules - ../../shared/platform/orangepi5plus.nix - ]; - - mj = { - stateVersion = "23.11"; - timeZone = "UTC"; - username = "nixos"; - - base.users = { - enable = true; - user.initialHashedPassword = ""; - root.initialHashedPassword = ""; - }; - }; - - services = { - pcscd.enable = true; - }; - - boot.supportedFilesystems = ["btrfs" "bcachefs"]; - - fileSystems = { - "/" = { - device = "/dev/disk/by-label/nixos"; - fsType = "ext4"; - options = ["noatime"]; - }; - }; - - security.sudo = { - enable = true; - wheelNeedsPassword = false; - }; - - networking = { - hostName = "op5p"; - domain = "jakstys.lt"; - firewall.allowedTCPPorts = [22]; - }; -} diff --git a/hosts/vno1-oh2/configuration.nix b/hosts/vno1-oh2/configuration.nix index e3ce3a0..6e4dc12 100644 --- a/hosts/vno1-oh2/configuration.nix +++ b/hosts/vno1-oh2/configuration.nix @@ -214,10 +214,6 @@ derivationTarget = ".#mtworx"; pingTarget = myData.hosts."mtworx.motiejus.jakst".jakstIP; } - { - derivationTarget = ".#vno1-op5p"; - pingTarget = myData.hosts."vno1-op5p.servers.jakst".jakstIP; - } { derivationTarget = ".#vno3-rp3b"; pingTarget = myData.hosts."vno3-rp3b.servers.jakst".jakstIP; @@ -499,10 +495,6 @@ job_name = "vno3-rp3b.servers.jakst"; static_configs = [{targets = ["${myData.hosts."vno3-rp3b.servers.jakst".jakstIP}:${port}"];}]; } - { - job_name = "vno1-op5p.servers.jakst"; - static_configs = [{targets = ["${myData.hosts."vno1-op5p.servers.jakst".jakstIP}:${port}"];}]; - } { job_name = "fwminex.motiejus.jakst"; static_configs = [{targets = ["${myData.hosts."fwminex.motiejus.jakst".jakstIP}:${port}"];}]; diff --git a/hosts/vno1-op5p/configuration.nix b/hosts/vno1-op5p/configuration.nix deleted file mode 100644 index 55b544f..0000000 --- a/hosts/vno1-op5p/configuration.nix +++ /dev/null @@ -1,92 +0,0 @@ -{ - config, - myData, - ... -}: let - #nvme = "/dev/disk/by-id/nvme-WDC_PC_SN730_SDBQNTY-256G-1001_19494D801165"; - nvme = "/dev/nvme0n1"; -in { - imports = [ - ../../modules - - ../../modules/profiles/btrfs - - ../../shared/platform/orangepi5plus.nix - ]; - - boot = { - initrd = { - kernelModules = ["usb_storage"]; - luks.devices = { - luksroot = { - #device = "${nvme}-part3"; - device = "${nvme}p3"; - allowDiscards = true; - keyFileOffset = 9728; - keyFileSize = 512; - keyFile = "/dev/sda"; - }; - }; - }; - }; - - swapDevices = [ - { - device = "${nvme}p2"; - randomEncryption.enable = true; - } - ]; - - fileSystems = { - "/" = { - device = "/dev/mapper/luksroot"; - fsType = "btrfs"; - options = ["noatime" "compress=zstd"]; - }; - "/boot" = { - device = "${nvme}1"; - fsType = "ext4"; - }; - }; - - mj = { - stateVersion = "23.11"; - timeZone = "Europe/Vilnius"; - username = "motiejus"; - - base.users = { - enable = true; - root.hashedPasswordFile = config.age.secrets.root-passwd-hash.path; - user.hashedPasswordFile = config.age.secrets.motiejus-passwd-hash.path; - }; - - services = { - tailscale.enable = true; - node_exporter.enable = true; - sshguard.enable = true; - - postfix = { - enable = true; - saslPasswdPath = config.age.secrets.sasl-passwd.path; - }; - - deployerbot = { - follower = { - inherit (myData.hosts."vno1-oh2.servers.jakst") publicKey; - - enable = true; - sshAllowSubnets = [myData.subnets.tailscale.sshPattern]; - uidgid = myData.uidgid.updaterbot-deployee; - }; - }; - }; - }; - - services.pcscd.enable = true; - - networking = { - hostName = "vno1-op5p"; - domain = "jakstys.lt"; - firewall.allowedTCPPorts = [22]; - }; -} diff --git a/secrets.nix b/secrets.nix index 4e95889..ff2054c 100644 --- a/secrets.nix +++ b/secrets.nix @@ -10,9 +10,8 @@ let mtworx = (import ./data.nix).hosts."mtworx.motiejus.jakst".publicKey; fra1-a = (import ./data.nix).hosts."fra1-a.servers.jakst".publicKey; vno1-oh2 = (import ./data.nix).hosts."vno1-oh2.servers.jakst".publicKey; - vno1-op5p = (import ./data.nix).hosts."vno1-op5p.servers.jakst".publicKey; vno3-rp3b = (import ./data.nix).hosts."vno3-rp3b.servers.jakst".publicKey; - systems = [fra1-a vno1-oh2 vno1-op5p vno3-rp3b fwminex]; + systems = [fra1-a vno1-oh2 vno3-rp3b fwminex]; mk = auth: keyNames: builtins.listToAttrs ( diff --git a/shared/platform/orangepi5plus.nix b/shared/platform/orangepi5plus.nix deleted file mode 100644 index 37ec369..0000000 --- a/shared/platform/orangepi5plus.nix +++ /dev/null @@ -1,65 +0,0 @@ -{ - config, - lib, - pkgs, - modulesPath, - ... -}: -#let -#crossFast = pkgs.crossArm64.pkgsCross.aarch64-multiplatform; -#in -{ - mj.skipPerf = true; - - boot = { - #kernelPackages = crossNative.linuxPackagesFor (crossFast.buildLinux rec { - kernelPackages = pkgs.linuxPackagesFor (pkgs.buildLinux rec { - version = "6.10.0-rc1"; - modDirVersion = "6.10.0-rc1"; - - src = builtins.fetchTarball { - url = "https://github.com/torvalds/linux/archive/refs/tags/v6.10-rc1.tar.gz"; - # "unsupported snapshot format" 2024-05-06 - #url = "https://git.kernel.org/torvalds/t/linux-6.9-rc1.tar.gz"; - #url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.8.tar.xz"; - sha256 = "sha256:006frl76cwi9a4mw7x6vsyazgrjfiz1gn4q4hvpykqql5mar3a05"; - }; - kernelPatches = [ - { - name = "orangepi-5-plus-collabora-${version}"; - patch = ./orangepi5plus/rk3588-v6.10-rc1.patch; - } - { - name = "rk3588-crypto"; - patch = ./orangepi5plus/rk3588-crypto.patch; - } - ]; - extraConfig = '' - CRYPTO_DEV_ROCKCHIP2 m - CRYPTO_DEV_ROCKCHIP2_DEBUG y - ''; - - extraMeta.branch = "6.10"; - }); - - loader = { - grub.enable = false; - generic-extlinux-compatible.enable = true; - }; - - initrd.kernelModules = ["ahci_dwc" "phy_rockchip_naneng_combphy"]; - consoleLogLevel = 7; - }; - - hardware.deviceTree.name = "rockchip/rk3588-orangepi-5-plus.dtb"; - - system.build = { - sdImage = import "${modulesPath}/../lib/make-disk-image.nix" { - name = "orangepi5-sd-image"; - copyChannel = false; - inherit config lib pkgs; - }; - #uboot = crossFast.callPackage ../../hacks/orangepi5plus/uboot {}; - uboot = pkgs.callPackage ../../hacks/orangepi5plus/uboot {}; - }; -} diff --git a/shared/platform/orangepi5plus/rk3588-crypto.patch b/shared/platform/orangepi5plus/rk3588-crypto.patch deleted file mode 100644 index 8f8372c..0000000 --- a/shared/platform/orangepi5plus/rk3588-crypto.patch +++ /dev/null @@ -1,2365 +0,0 @@ -From c3537e5488bbd1b2babd0d5db3d8ea351e4af658 Mon Sep 17 00:00:00 2001 -From: Corentin Labbe -Date: Tue, 7 Nov 2023 15:55:27 +0000 -Subject: [PATCH 1/6] dt-bindings: crypto: add support for - rockchip,crypto-rk3588 - -Add device tree binding documentation for the Rockchip cryptographic -offloader V2. - -Signed-off-by: Corentin Labbe ---- - .../crypto/rockchip,rk3588-crypto.yaml | 65 +++++++++++++++++++ - 1 file changed, 65 insertions(+) - create mode 100644 Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml - -diff --git a/Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml b/Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml -new file mode 100644 -index 000000000000..c01963413260 ---- /dev/null -+++ b/Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml -@@ -0,0 +1,65 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/crypto/rockchip,rk3588-crypto.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Rockchip cryptographic offloader V2 -+ -+maintainers: -+ - Corentin Labbe -+ -+properties: -+ compatible: -+ enum: -+ - rockchip,rk3568-crypto -+ - rockchip,rk3588-crypto -+ -+ reg: -+ maxItems: 1 -+ -+ interrupts: -+ maxItems: 1 -+ -+ clocks: -+ minItems: 3 -+ -+ clock-names: -+ items: -+ - const: core -+ - const: a -+ - const: h -+ -+ resets: -+ minItems: 1 -+ -+ reset-names: -+ items: -+ - const: core -+ -+required: -+ - compatible -+ - reg -+ - interrupts -+ - clocks -+ - clock-names -+ - resets -+ - reset-names -+ -+additionalProperties: false -+ -+examples: -+ - | -+ #include -+ #include -+ #include -+ crypto@fe370000 { -+ compatible = "rockchip,rk3588-crypto"; -+ reg = <0xfe370000 0x4000>; -+ interrupts = ; -+ clocks = <&scmi_clk SCMI_CRYPTO_CORE>, <&scmi_clk SCMI_ACLK_SECURE_NS>, -+ <&scmi_clk SCMI_HCLK_SECURE_NS>; -+ clock-names = "core", "a", "h"; -+ resets = <&scmi_reset SRST_CRYPTO_CORE>; -+ reset-names = "core"; -+ }; --- -2.42.0 - - -From 79d1c4735692eccd91db72d09baac779451dc13e Mon Sep 17 00:00:00 2001 -From: Corentin Labbe -Date: Tue, 7 Nov 2023 15:55:28 +0000 -Subject: [PATCH 2/6] MAINTAINERS: add new dt-binding doc to the right entry - -Rockchip crypto driver have a new file to be added. - -Signed-off-by: Corentin Labbe ---- - MAINTAINERS | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/MAINTAINERS b/MAINTAINERS -index 4f298c4187fb..866776f419de 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -18910,6 +18910,7 @@ M: Corentin Labbe - L: linux-crypto@vger.kernel.org - S: Maintained - F: Documentation/devicetree/bindings/crypto/rockchip,rk3288-crypto.yaml -+F: Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml - F: drivers/crypto/rockchip/ - - ROCKCHIP I2S TDM DRIVER --- -2.42.0 - - -From 467ac14a13be1762ce135a8ebd23dca53b070de7 Mon Sep 17 00:00:00 2001 -From: Corentin Labbe -Date: Tue, 7 Nov 2023 15:55:30 +0000 -Subject: [PATCH 3/6] ARM64: dts: rk356x: add crypto node - -Both RK3566 and RK3568 have a crypto IP handled by the rk3588 crypto driver so adds a -node for it. - -Tested-by: Ricardo Pardini -Signed-off-by: Corentin Labbe ---- - arch/arm64/boot/dts/rockchip/rk356x.dtsi | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi -index c19c0f1b3778..d2764659d21b 100644 ---- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi -@@ -1070,6 +1070,18 @@ sdhci: mmc@fe310000 { - status = "disabled"; - }; - -+ crypto: crypto@fe380000 { -+ compatible = "rockchip,rk3568-crypto"; -+ reg = <0x0 0xfe380000 0x0 0x2000>; -+ interrupts = ; -+ clocks = <&cru ACLK_CRYPTO_NS>, <&cru HCLK_CRYPTO_NS>, -+ <&cru CLK_CRYPTO_NS_CORE>; -+ clock-names = "aclk", "hclk", "core"; -+ resets = <&cru SRST_CRYPTO_NS_CORE>; -+ reset-names = "core"; -+ status = "okay"; -+ }; -+ - i2s0_8ch: i2s@fe400000 { - compatible = "rockchip,rk3568-i2s-tdm"; - reg = <0x0 0xfe400000 0x0 0x1000>; --- -2.42.0 - - -From b4ac4ce99080d440ab69d599944beaf3de7b4003 Mon Sep 17 00:00:00 2001 -From: Corentin Labbe -Date: Tue, 7 Nov 2023 15:55:29 +0000 -Subject: [PATCH 4/6] ARM64: dts: rk3588: add crypto node - -The rk3588 has a crypto IP handled by the rk3588 crypto driver so adds a -node for it. - -Signed-off-by: Corentin Labbe ---- - arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -index 36b1b7acfe6a..8c902163e328 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -@@ -1638,6 +1638,18 @@ sdhci: mmc@fe2e0000 { - status = "disabled"; - }; - -+ crypto: crypto@fe370000 { -+ compatible = "rockchip,rk3588-crypto"; -+ reg = <0x0 0xfe370000 0x0 0x2000>; -+ interrupts = ; -+ clocks = <&scmi_clk SCMI_CRYPTO_CORE>, <&scmi_clk SCMI_ACLK_SECURE_NS>, -+ <&scmi_clk SCMI_HCLK_SECURE_NS>; -+ clock-names = "core", "aclk", "hclk"; -+ resets = <&scmi_reset SRST_CRYPTO_CORE>; -+ reset-names = "core"; -+ status = "okay"; -+ }; -+ - i2s0_8ch: i2s@fe470000 { - compatible = "rockchip,rk3588-i2s-tdm"; - reg = <0x0 0xfe470000 0x0 0x1000>; --- -2.42.0 - - -From 518130600c78cca223301dfc3394467ffd741ed7 Mon Sep 17 00:00:00 2001 -From: Corentin Labbe -Date: Tue, 7 Nov 2023 15:55:31 +0000 -Subject: [PATCH 5/6] reset: rockchip: secure reset must be used by SCMI - -While working on the rk3588 crypto driver, I loose lot of time -understanding why resetting the IP failed. -This is due to RK3588_SECURECRU_RESET_OFFSET being in the secure world, -so impossible to operate on it from the kernel. -All resets in this block must be handled via SCMI call. - -Signed-off-by: Corentin Labbe ---- - drivers/clk/rockchip/rst-rk3588.c | 42 ------------ - .../dt-bindings/reset/rockchip,rk3588-cru.h | 68 +++++++++---------- - 2 files changed, 34 insertions(+), 76 deletions(-) - -diff --git a/drivers/clk/rockchip/rst-rk3588.c b/drivers/clk/rockchip/rst-rk3588.c -index e855bb8d5413..6556d9d3c7ab 100644 ---- a/drivers/clk/rockchip/rst-rk3588.c -+++ b/drivers/clk/rockchip/rst-rk3588.c -@@ -16,9 +16,6 @@ - /* 0xFD7C8000 + 0x0A00 */ - #define RK3588_PHPTOPCRU_RESET_OFFSET(id, reg, bit) [id] = (0x8000*4 + reg * 16 + bit) - --/* 0xFD7D0000 + 0x0A00 */ --#define RK3588_SECURECRU_RESET_OFFSET(id, reg, bit) [id] = (0x10000*4 + reg * 16 + bit) -- - /* 0xFD7F0000 + 0x0A00 */ - #define RK3588_PMU1CRU_RESET_OFFSET(id, reg, bit) [id] = (0x30000*4 + reg * 16 + bit) - -@@ -806,45 +803,6 @@ static const int rk3588_register_offset[] = { - RK3588_PMU1CRU_RESET_OFFSET(SRST_P_PMU0IOC, 5, 4), - RK3588_PMU1CRU_RESET_OFFSET(SRST_P_GPIO0, 5, 5), - RK3588_PMU1CRU_RESET_OFFSET(SRST_GPIO0, 5, 6), -- -- /* SECURECRU_SOFTRST_CON00 */ -- RK3588_SECURECRU_RESET_OFFSET(SRST_A_SECURE_NS_BIU, 0, 10), -- RK3588_SECURECRU_RESET_OFFSET(SRST_H_SECURE_NS_BIU, 0, 11), -- RK3588_SECURECRU_RESET_OFFSET(SRST_A_SECURE_S_BIU, 0, 12), -- RK3588_SECURECRU_RESET_OFFSET(SRST_H_SECURE_S_BIU, 0, 13), -- RK3588_SECURECRU_RESET_OFFSET(SRST_P_SECURE_S_BIU, 0, 14), -- RK3588_SECURECRU_RESET_OFFSET(SRST_CRYPTO_CORE, 0, 15), -- -- /* SECURECRU_SOFTRST_CON01 */ -- RK3588_SECURECRU_RESET_OFFSET(SRST_CRYPTO_PKA, 1, 0), -- RK3588_SECURECRU_RESET_OFFSET(SRST_CRYPTO_RNG, 1, 1), -- RK3588_SECURECRU_RESET_OFFSET(SRST_A_CRYPTO, 1, 2), -- RK3588_SECURECRU_RESET_OFFSET(SRST_H_CRYPTO, 1, 3), -- RK3588_SECURECRU_RESET_OFFSET(SRST_KEYLADDER_CORE, 1, 9), -- RK3588_SECURECRU_RESET_OFFSET(SRST_KEYLADDER_RNG, 1, 10), -- RK3588_SECURECRU_RESET_OFFSET(SRST_A_KEYLADDER, 1, 11), -- RK3588_SECURECRU_RESET_OFFSET(SRST_H_KEYLADDER, 1, 12), -- RK3588_SECURECRU_RESET_OFFSET(SRST_P_OTPC_S, 1, 13), -- RK3588_SECURECRU_RESET_OFFSET(SRST_OTPC_S, 1, 14), -- RK3588_SECURECRU_RESET_OFFSET(SRST_WDT_S, 1, 15), -- -- /* SECURECRU_SOFTRST_CON02 */ -- RK3588_SECURECRU_RESET_OFFSET(SRST_T_WDT_S, 2, 0), -- RK3588_SECURECRU_RESET_OFFSET(SRST_H_BOOTROM, 2, 1), -- RK3588_SECURECRU_RESET_OFFSET(SRST_A_DCF, 2, 2), -- RK3588_SECURECRU_RESET_OFFSET(SRST_P_DCF, 2, 3), -- RK3588_SECURECRU_RESET_OFFSET(SRST_H_BOOTROM_NS, 2, 5), -- RK3588_SECURECRU_RESET_OFFSET(SRST_P_KEYLADDER, 2, 14), -- RK3588_SECURECRU_RESET_OFFSET(SRST_H_TRNG_S, 2, 15), -- -- /* SECURECRU_SOFTRST_CON03 */ -- RK3588_SECURECRU_RESET_OFFSET(SRST_H_TRNG_NS, 3, 0), -- RK3588_SECURECRU_RESET_OFFSET(SRST_D_SDMMC_BUFFER, 3, 1), -- RK3588_SECURECRU_RESET_OFFSET(SRST_H_SDMMC, 3, 2), -- RK3588_SECURECRU_RESET_OFFSET(SRST_H_SDMMC_BUFFER, 3, 3), -- RK3588_SECURECRU_RESET_OFFSET(SRST_SDMMC, 3, 4), -- RK3588_SECURECRU_RESET_OFFSET(SRST_P_TRNG_CHK, 3, 5), -- RK3588_SECURECRU_RESET_OFFSET(SRST_TRNG_S, 3, 6), - }; - - void rk3588_rst_init(struct device_node *np, void __iomem *reg_base) -diff --git a/include/dt-bindings/reset/rockchip,rk3588-cru.h b/include/dt-bindings/reset/rockchip,rk3588-cru.h -index d4264db2a07f..c0d08ae78cd5 100644 ---- a/include/dt-bindings/reset/rockchip,rk3588-cru.h -+++ b/include/dt-bindings/reset/rockchip,rk3588-cru.h -@@ -716,39 +716,39 @@ - #define SRST_P_GPIO0 627 - #define SRST_GPIO0 628 - --#define SRST_A_SECURE_NS_BIU 629 --#define SRST_H_SECURE_NS_BIU 630 --#define SRST_A_SECURE_S_BIU 631 --#define SRST_H_SECURE_S_BIU 632 --#define SRST_P_SECURE_S_BIU 633 --#define SRST_CRYPTO_CORE 634 -- --#define SRST_CRYPTO_PKA 635 --#define SRST_CRYPTO_RNG 636 --#define SRST_A_CRYPTO 637 --#define SRST_H_CRYPTO 638 --#define SRST_KEYLADDER_CORE 639 --#define SRST_KEYLADDER_RNG 640 --#define SRST_A_KEYLADDER 641 --#define SRST_H_KEYLADDER 642 --#define SRST_P_OTPC_S 643 --#define SRST_OTPC_S 644 --#define SRST_WDT_S 645 -- --#define SRST_T_WDT_S 646 --#define SRST_H_BOOTROM 647 --#define SRST_A_DCF 648 --#define SRST_P_DCF 649 --#define SRST_H_BOOTROM_NS 650 --#define SRST_P_KEYLADDER 651 --#define SRST_H_TRNG_S 652 -- --#define SRST_H_TRNG_NS 653 --#define SRST_D_SDMMC_BUFFER 654 --#define SRST_H_SDMMC 655 --#define SRST_H_SDMMC_BUFFER 656 --#define SRST_SDMMC 657 --#define SRST_P_TRNG_CHK 658 --#define SRST_TRNG_S 659 -+#define SRST_A_SECURE_NS_BIU 10 -+#define SRST_H_SECURE_NS_BIU 11 -+#define SRST_A_SECURE_S_BIU 12 -+#define SRST_H_SECURE_S_BIU 13 -+#define SRST_P_SECURE_S_BIU 14 -+#define SRST_CRYPTO_CORE 15 -+ -+#define SRST_CRYPTO_PKA 16 -+#define SRST_CRYPTO_RNG 17 -+#define SRST_A_CRYPTO 18 -+#define SRST_H_CRYPTO 19 -+#define SRST_KEYLADDER_CORE 25 -+#define SRST_KEYLADDER_RNG 26 -+#define SRST_A_KEYLADDER 27 -+#define SRST_H_KEYLADDER 28 -+#define SRST_P_OTPC_S 29 -+#define SRST_OTPC_S 30 -+#define SRST_WDT_S 31 -+ -+#define SRST_T_WDT_S 32 -+#define SRST_H_BOOTROM 33 -+#define SRST_A_DCF 34 -+#define SRST_P_DCF 35 -+#define SRST_H_BOOTROM_NS 37 -+#define SRST_P_KEYLADDER 46 -+#define SRST_H_TRNG_S 47 -+ -+#define SRST_H_TRNG_NS 48 -+#define SRST_D_SDMMC_BUFFER 49 -+#define SRST_H_SDMMC 50 -+#define SRST_H_SDMMC_BUFFER 51 -+#define SRST_SDMMC 52 -+#define SRST_P_TRNG_CHK 53 -+#define SRST_TRNG_S 54 - - #endif --- -2.42.0 - - -From 10253761fb982563b8311ea83c6467cacb030027 Mon Sep 17 00:00:00 2001 -From: Corentin Labbe -Date: Tue, 7 Nov 2023 15:55:32 +0000 -Subject: [PATCH 6/6] crypto: rockchip: add rk3588 driver - -RK3588 have a new crypto IP, this patch adds basic support for it. -Only hashes and cipher are handled for the moment. - -Signed-off-by: Corentin Labbe ---- - drivers/crypto/Kconfig | 29 + - drivers/crypto/rockchip/Makefile | 5 + - drivers/crypto/rockchip/rk2_crypto.c | 739 ++++++++++++++++++ - drivers/crypto/rockchip/rk2_crypto.h | 246 ++++++ - drivers/crypto/rockchip/rk2_crypto_ahash.c | 344 ++++++++ - drivers/crypto/rockchip/rk2_crypto_skcipher.c | 576 ++++++++++++++ - 6 files changed, 1939 insertions(+) - create mode 100644 drivers/crypto/rockchip/rk2_crypto.c - create mode 100644 drivers/crypto/rockchip/rk2_crypto.h - create mode 100644 drivers/crypto/rockchip/rk2_crypto_ahash.c - create mode 100644 drivers/crypto/rockchip/rk2_crypto_skcipher.c - -diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig -index 0991f026cb07..09edba08fbb6 100644 ---- a/drivers/crypto/Kconfig -+++ b/drivers/crypto/Kconfig -@@ -661,6 +661,35 @@ config CRYPTO_DEV_ROCKCHIP_DEBUG - the number of requests per algorithm and other internal stats. - - -+config CRYPTO_DEV_ROCKCHIP2 -+ tristate "Rockchip's cryptographic offloader V2" -+ depends on OF && ARCH_ROCKCHIP -+ depends on PM -+ select CRYPTO_ECB -+ select CRYPTO_CBC -+ select CRYPTO_AES -+ select CRYPTO_MD5 -+ select CRYPTO_SHA1 -+ select CRYPTO_SHA256 -+ select CRYPTO_SHA512 -+ select CRYPTO_SM3_GENERIC -+ select CRYPTO_HASH -+ select CRYPTO_SKCIPHER -+ select CRYPTO_ENGINE -+ -+ help -+ This driver interfaces with the hardware crypto offloader present -+ on RK3566, RK3568 and RK3588. -+ -+config CRYPTO_DEV_ROCKCHIP2_DEBUG -+ bool "Enable Rockchip V2 crypto stats" -+ depends on CRYPTO_DEV_ROCKCHIP2 -+ depends on DEBUG_FS -+ help -+ Say y to enable Rockchip crypto debug stats. -+ This will create /sys/kernel/debug/rk3588_crypto/stats for displaying -+ the number of requests per algorithm and other internal stats. -+ - config CRYPTO_DEV_ZYNQMP_AES - tristate "Support for Xilinx ZynqMP AES hw accelerator" - depends on ZYNQMP_FIRMWARE || COMPILE_TEST -diff --git a/drivers/crypto/rockchip/Makefile b/drivers/crypto/rockchip/Makefile -index 785277aca71e..452a12ff6538 100644 ---- a/drivers/crypto/rockchip/Makefile -+++ b/drivers/crypto/rockchip/Makefile -@@ -3,3 +3,8 @@ obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rk_crypto.o - rk_crypto-objs := rk3288_crypto.o \ - rk3288_crypto_skcipher.o \ - rk3288_crypto_ahash.o -+ -+obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP2) += rk_crypto2.o -+rk_crypto2-objs := rk2_crypto.o \ -+ rk2_crypto_skcipher.o \ -+ rk2_crypto_ahash.o -diff --git a/drivers/crypto/rockchip/rk2_crypto.c b/drivers/crypto/rockchip/rk2_crypto.c -new file mode 100644 -index 000000000000..79ed697d8ec5 ---- /dev/null -+++ b/drivers/crypto/rockchip/rk2_crypto.c -@@ -0,0 +1,739 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * hardware cryptographic offloader for RK3568/RK3588 SoC -+ * -+ * Copyright (c) 2022-2023, Corentin Labbe -+ */ -+ -+#include "rk2_crypto.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static struct rockchip_ip rocklist = { -+ .dev_list = LIST_HEAD_INIT(rocklist.dev_list), -+ .lock = __SPIN_LOCK_UNLOCKED(rocklist.lock), -+}; -+ -+struct rk2_crypto_dev *get_rk2_crypto(void) -+{ -+ struct rk2_crypto_dev *first; -+ -+ spin_lock(&rocklist.lock); -+ first = list_first_entry_or_null(&rocklist.dev_list, -+ struct rk2_crypto_dev, list); -+ list_rotate_left(&rocklist.dev_list); -+ spin_unlock(&rocklist.lock); -+ return first; -+} -+ -+static const struct rk2_variant rk3568_variant = { -+ .num_clks = 3, -+}; -+ -+static const struct rk2_variant rk3588_variant = { -+ .num_clks = 3, -+}; -+ -+static int rk2_crypto_get_clks(struct rk2_crypto_dev *dev) -+{ -+ int i, j, err; -+ unsigned long cr; -+ -+ dev->num_clks = devm_clk_bulk_get_all(dev->dev, &dev->clks); -+ if (dev->num_clks < dev->variant->num_clks) { -+ dev_err(dev->dev, "Missing clocks, got %d instead of %d\n", -+ dev->num_clks, dev->variant->num_clks); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < dev->num_clks; i++) { -+ cr = clk_get_rate(dev->clks[i].clk); -+ for (j = 0; j < ARRAY_SIZE(dev->variant->rkclks); j++) { -+ if (dev->variant->rkclks[j].max == 0) -+ continue; -+ if (strcmp(dev->variant->rkclks[j].name, dev->clks[i].id)) -+ continue; -+ if (cr > dev->variant->rkclks[j].max) { -+ err = clk_set_rate(dev->clks[i].clk, -+ dev->variant->rkclks[j].max); -+ if (err) -+ dev_err(dev->dev, "Fail downclocking %s from %lu to %lu\n", -+ dev->variant->rkclks[j].name, cr, -+ dev->variant->rkclks[j].max); -+ else -+ dev_info(dev->dev, "Downclocking %s from %lu to %lu\n", -+ dev->variant->rkclks[j].name, cr, -+ dev->variant->rkclks[j].max); -+ } -+ } -+ } -+ return 0; -+} -+ -+static int rk2_crypto_enable_clk(struct rk2_crypto_dev *dev) -+{ -+ int err; -+ -+ err = clk_bulk_prepare_enable(dev->num_clks, dev->clks); -+ if (err) -+ dev_err(dev->dev, "Could not enable clock clks\n"); -+ -+ return err; -+} -+ -+static void rk2_crypto_disable_clk(struct rk2_crypto_dev *dev) -+{ -+ clk_bulk_disable_unprepare(dev->num_clks, dev->clks); -+} -+ -+/* -+ * Power management strategy: The device is suspended until a request -+ * is handled. For avoiding suspend/resume yoyo, the autosuspend is set to 2s. -+ */ -+static int rk2_crypto_pm_suspend(struct device *dev) -+{ -+ struct rk2_crypto_dev *rkdev = dev_get_drvdata(dev); -+ -+ rk2_crypto_disable_clk(rkdev); -+ reset_control_assert(rkdev->rst); -+ -+ return 0; -+} -+ -+static int rk2_crypto_pm_resume(struct device *dev) -+{ -+ struct rk2_crypto_dev *rkdev = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = rk2_crypto_enable_clk(rkdev); -+ if (ret) -+ return ret; -+ -+ reset_control_deassert(rkdev->rst); -+ return 0; -+} -+ -+static const struct dev_pm_ops rk2_crypto_pm_ops = { -+ SET_RUNTIME_PM_OPS(rk2_crypto_pm_suspend, rk2_crypto_pm_resume, NULL) -+}; -+ -+static int rk2_crypto_pm_init(struct rk2_crypto_dev *rkdev) -+{ -+ int err; -+ -+ pm_runtime_use_autosuspend(rkdev->dev); -+ pm_runtime_set_autosuspend_delay(rkdev->dev, 2000); -+ -+ err = pm_runtime_set_suspended(rkdev->dev); -+ if (err) -+ return err; -+ pm_runtime_enable(rkdev->dev); -+ return err; -+} -+ -+static void rk2_crypto_pm_exit(struct rk2_crypto_dev *rkdev) -+{ -+ pm_runtime_disable(rkdev->dev); -+} -+ -+static irqreturn_t rk2_crypto_irq_handle(int irq, void *dev_id) -+{ -+ struct rk2_crypto_dev *rkc = platform_get_drvdata(dev_id); -+ u32 v; -+ -+ v = readl(rkc->reg + RK2_CRYPTO_DMA_INT_ST); -+ writel(v, rkc->reg + RK2_CRYPTO_DMA_INT_ST); -+ -+ rkc->status = 1; -+ if (v & 0xF8) { -+ dev_warn(rkc->dev, "DMA Error\n"); -+ rkc->status = 0; -+ } -+ complete(&rkc->complete); -+ -+ return IRQ_HANDLED; -+} -+ -+static struct rk2_crypto_template rk2_crypto_algs[] = { -+ { -+ .type = CRYPTO_ALG_TYPE_SKCIPHER, -+ .rk2_mode = RK2_CRYPTO_AES_ECB, -+ .alg.skcipher.base = { -+ .base.cra_name = "ecb(aes)", -+ .base.cra_driver_name = "ecb-aes-rk2", -+ .base.cra_priority = 300, -+ .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, -+ .base.cra_blocksize = AES_BLOCK_SIZE, -+ .base.cra_ctxsize = sizeof(struct rk2_cipher_ctx), -+ .base.cra_alignmask = 0x0f, -+ .base.cra_module = THIS_MODULE, -+ -+ .init = rk2_cipher_tfm_init, -+ .exit = rk2_cipher_tfm_exit, -+ .min_keysize = AES_MIN_KEY_SIZE, -+ .max_keysize = AES_MAX_KEY_SIZE, -+ .setkey = rk2_aes_setkey, -+ .encrypt = rk2_skcipher_encrypt, -+ .decrypt = rk2_skcipher_decrypt, -+ }, -+ .alg.skcipher.op = { -+ .do_one_request = rk2_cipher_run, -+ }, -+ }, -+ { -+ .type = CRYPTO_ALG_TYPE_SKCIPHER, -+ .rk2_mode = RK2_CRYPTO_AES_CBC, -+ .alg.skcipher.base = { -+ .base.cra_name = "cbc(aes)", -+ .base.cra_driver_name = "cbc-aes-rk2", -+ .base.cra_priority = 300, -+ .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, -+ .base.cra_blocksize = AES_BLOCK_SIZE, -+ .base.cra_ctxsize = sizeof(struct rk2_cipher_ctx), -+ .base.cra_alignmask = 0x0f, -+ .base.cra_module = THIS_MODULE, -+ -+ .init = rk2_cipher_tfm_init, -+ .exit = rk2_cipher_tfm_exit, -+ .min_keysize = AES_MIN_KEY_SIZE, -+ .max_keysize = AES_MAX_KEY_SIZE, -+ .ivsize = AES_BLOCK_SIZE, -+ .setkey = rk2_aes_setkey, -+ .encrypt = rk2_skcipher_encrypt, -+ .decrypt = rk2_skcipher_decrypt, -+ }, -+ .alg.skcipher.op = { -+ .do_one_request = rk2_cipher_run, -+ }, -+ }, -+ { -+ .type = CRYPTO_ALG_TYPE_SKCIPHER, -+ .rk2_mode = RK2_CRYPTO_AES_XTS, -+ .is_xts = true, -+ .alg.skcipher.base = { -+ .base.cra_name = "xts(aes)", -+ .base.cra_driver_name = "xts-aes-rk2", -+ .base.cra_priority = 300, -+ .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, -+ .base.cra_blocksize = AES_BLOCK_SIZE, -+ .base.cra_ctxsize = sizeof(struct rk2_cipher_ctx), -+ .base.cra_alignmask = 0x0f, -+ .base.cra_module = THIS_MODULE, -+ -+ .init = rk2_cipher_tfm_init, -+ .exit = rk2_cipher_tfm_exit, -+ .min_keysize = AES_MIN_KEY_SIZE * 2, -+ .max_keysize = AES_MAX_KEY_SIZE * 2, -+ .ivsize = AES_BLOCK_SIZE, -+ .setkey = rk2_aes_xts_setkey, -+ .encrypt = rk2_skcipher_encrypt, -+ .decrypt = rk2_skcipher_decrypt, -+ }, -+ .alg.skcipher.op = { -+ .do_one_request = rk2_cipher_run, -+ }, -+ }, -+ { -+ .type = CRYPTO_ALG_TYPE_AHASH, -+ .rk2_mode = RK2_CRYPTO_MD5, -+ .alg.hash.base = { -+ .init = rk2_ahash_init, -+ .update = rk2_ahash_update, -+ .final = rk2_ahash_final, -+ .finup = rk2_ahash_finup, -+ .export = rk2_ahash_export, -+ .import = rk2_ahash_import, -+ .digest = rk2_ahash_digest, -+ .init_tfm = rk2_hash_init_tfm, -+ .exit_tfm = rk2_hash_exit_tfm, -+ .halg = { -+ .digestsize = MD5_DIGEST_SIZE, -+ .statesize = sizeof(struct md5_state), -+ .base = { -+ .cra_name = "md5", -+ .cra_driver_name = "rk2-md5", -+ .cra_priority = 300, -+ .cra_flags = CRYPTO_ALG_ASYNC | -+ CRYPTO_ALG_NEED_FALLBACK, -+ .cra_blocksize = MD5_HMAC_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct rk2_ahash_ctx), -+ .cra_module = THIS_MODULE, -+ } -+ } -+ }, -+ .alg.hash.op = { -+ .do_one_request = rk2_hash_run, -+ }, -+ -+ }, -+ { -+ .type = CRYPTO_ALG_TYPE_AHASH, -+ .rk2_mode = RK2_CRYPTO_SHA1, -+ .alg.hash.base = { -+ .init = rk2_ahash_init, -+ .update = rk2_ahash_update, -+ .final = rk2_ahash_final, -+ .finup = rk2_ahash_finup, -+ .export = rk2_ahash_export, -+ .import = rk2_ahash_import, -+ .digest = rk2_ahash_digest, -+ .init_tfm = rk2_hash_init_tfm, -+ .exit_tfm = rk2_hash_exit_tfm, -+ .halg = { -+ .digestsize = SHA1_DIGEST_SIZE, -+ .statesize = sizeof(struct sha1_state), -+ .base = { -+ .cra_name = "sha1", -+ .cra_driver_name = "rk2-sha1", -+ .cra_priority = 300, -+ .cra_flags = CRYPTO_ALG_ASYNC | -+ CRYPTO_ALG_NEED_FALLBACK, -+ .cra_blocksize = SHA1_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct rk2_ahash_ctx), -+ .cra_module = THIS_MODULE, -+ } -+ } -+ }, -+ .alg.hash.op = { -+ .do_one_request = rk2_hash_run, -+ }, -+ }, -+ { -+ .type = CRYPTO_ALG_TYPE_AHASH, -+ .rk2_mode = RK2_CRYPTO_SHA256, -+ .alg.hash.base = { -+ .init = rk2_ahash_init, -+ .update = rk2_ahash_update, -+ .final = rk2_ahash_final, -+ .finup = rk2_ahash_finup, -+ .export = rk2_ahash_export, -+ .import = rk2_ahash_import, -+ .digest = rk2_ahash_digest, -+ .init_tfm = rk2_hash_init_tfm, -+ .exit_tfm = rk2_hash_exit_tfm, -+ .halg = { -+ .digestsize = SHA256_DIGEST_SIZE, -+ .statesize = sizeof(struct sha256_state), -+ .base = { -+ .cra_name = "sha256", -+ .cra_driver_name = "rk2-sha256", -+ .cra_priority = 300, -+ .cra_flags = CRYPTO_ALG_ASYNC | -+ CRYPTO_ALG_NEED_FALLBACK, -+ .cra_blocksize = SHA256_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct rk2_ahash_ctx), -+ .cra_module = THIS_MODULE, -+ } -+ } -+ }, -+ .alg.hash.op = { -+ .do_one_request = rk2_hash_run, -+ }, -+ }, -+ { -+ .type = CRYPTO_ALG_TYPE_AHASH, -+ .rk2_mode = RK2_CRYPTO_SHA384, -+ .alg.hash.base = { -+ .init = rk2_ahash_init, -+ .update = rk2_ahash_update, -+ .final = rk2_ahash_final, -+ .finup = rk2_ahash_finup, -+ .export = rk2_ahash_export, -+ .import = rk2_ahash_import, -+ .digest = rk2_ahash_digest, -+ .init_tfm = rk2_hash_init_tfm, -+ .exit_tfm = rk2_hash_exit_tfm, -+ .halg = { -+ .digestsize = SHA384_DIGEST_SIZE, -+ .statesize = sizeof(struct sha512_state), -+ .base = { -+ .cra_name = "sha384", -+ .cra_driver_name = "rk2-sha384", -+ .cra_priority = 300, -+ .cra_flags = CRYPTO_ALG_ASYNC | -+ CRYPTO_ALG_NEED_FALLBACK, -+ .cra_blocksize = SHA384_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct rk2_ahash_ctx), -+ .cra_module = THIS_MODULE, -+ } -+ } -+ }, -+ .alg.hash.op = { -+ .do_one_request = rk2_hash_run, -+ }, -+ }, -+ { -+ .type = CRYPTO_ALG_TYPE_AHASH, -+ .rk2_mode = RK2_CRYPTO_SHA512, -+ .alg.hash.base = { -+ .init = rk2_ahash_init, -+ .update = rk2_ahash_update, -+ .final = rk2_ahash_final, -+ .finup = rk2_ahash_finup, -+ .export = rk2_ahash_export, -+ .import = rk2_ahash_import, -+ .digest = rk2_ahash_digest, -+ .init_tfm = rk2_hash_init_tfm, -+ .exit_tfm = rk2_hash_exit_tfm, -+ .halg = { -+ .digestsize = SHA512_DIGEST_SIZE, -+ .statesize = sizeof(struct sha512_state), -+ .base = { -+ .cra_name = "sha512", -+ .cra_driver_name = "rk2-sha512", -+ .cra_priority = 300, -+ .cra_flags = CRYPTO_ALG_ASYNC | -+ CRYPTO_ALG_NEED_FALLBACK, -+ .cra_blocksize = SHA512_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct rk2_ahash_ctx), -+ .cra_module = THIS_MODULE, -+ } -+ } -+ }, -+ .alg.hash.op = { -+ .do_one_request = rk2_hash_run, -+ }, -+ }, -+ { -+ .type = CRYPTO_ALG_TYPE_AHASH, -+ .rk2_mode = RK2_CRYPTO_SM3, -+ .alg.hash.base = { -+ .init = rk2_ahash_init, -+ .update = rk2_ahash_update, -+ .final = rk2_ahash_final, -+ .finup = rk2_ahash_finup, -+ .export = rk2_ahash_export, -+ .import = rk2_ahash_import, -+ .digest = rk2_ahash_digest, -+ .init_tfm = rk2_hash_init_tfm, -+ .exit_tfm = rk2_hash_exit_tfm, -+ .halg = { -+ .digestsize = SM3_DIGEST_SIZE, -+ .statesize = sizeof(struct sm3_state), -+ .base = { -+ .cra_name = "sm3", -+ .cra_driver_name = "rk2-sm3", -+ .cra_priority = 300, -+ .cra_flags = CRYPTO_ALG_ASYNC | -+ CRYPTO_ALG_NEED_FALLBACK, -+ .cra_blocksize = SM3_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct rk2_ahash_ctx), -+ .cra_module = THIS_MODULE, -+ } -+ } -+ }, -+ .alg.hash.op = { -+ .do_one_request = rk2_hash_run, -+ }, -+ }, -+}; -+ -+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG -+static int rk2_crypto_debugfs_stats_show(struct seq_file *seq, void *v) -+{ -+ struct rk2_crypto_dev *rkc; -+ unsigned int i; -+ -+ spin_lock(&rocklist.lock); -+ list_for_each_entry(rkc, &rocklist.dev_list, list) { -+ seq_printf(seq, "%s %s requests: %lu\n", -+ dev_driver_string(rkc->dev), dev_name(rkc->dev), -+ rkc->nreq); -+ } -+ spin_unlock(&rocklist.lock); -+ -+ for (i = 0; i < ARRAY_SIZE(rk2_crypto_algs); i++) { -+ if (!rk2_crypto_algs[i].dev) -+ continue; -+ switch (rk2_crypto_algs[i].type) { -+ case CRYPTO_ALG_TYPE_SKCIPHER: -+ seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n", -+ rk2_crypto_algs[i].alg.skcipher.base.base.cra_driver_name, -+ rk2_crypto_algs[i].alg.skcipher.base.base.cra_name, -+ rk2_crypto_algs[i].stat_req, rk2_crypto_algs[i].stat_fb); -+ seq_printf(seq, "\tfallback due to length: %lu\n", -+ rk2_crypto_algs[i].stat_fb_len); -+ seq_printf(seq, "\tfallback due to alignment: %lu\n", -+ rk2_crypto_algs[i].stat_fb_align); -+ seq_printf(seq, "\tfallback due to SGs: %lu\n", -+ rk2_crypto_algs[i].stat_fb_sgdiff); -+ break; -+ case CRYPTO_ALG_TYPE_AHASH: -+ seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n", -+ rk2_crypto_algs[i].alg.hash.base.halg.base.cra_driver_name, -+ rk2_crypto_algs[i].alg.hash.base.halg.base.cra_name, -+ rk2_crypto_algs[i].stat_req, rk2_crypto_algs[i].stat_fb); -+ break; -+ } -+ } -+ return 0; -+} -+ -+static int rk2_crypto_debugfs_info_show(struct seq_file *seq, void *d) -+{ -+ struct rk2_crypto_dev *rkc; -+ u32 v; -+ -+ spin_lock(&rocklist.lock); -+ list_for_each_entry(rkc, &rocklist.dev_list, list) { -+ v = readl(rkc->reg + RK2_CRYPTO_CLK_CTL); -+ seq_printf(seq, "CRYPTO_CLK_CTL %x\n", v); -+ v = readl(rkc->reg + RK2_CRYPTO_RST_CTL); -+ seq_printf(seq, "CRYPTO_RST_CTL %x\n", v); -+ -+ v = readl(rkc->reg + CRYPTO_AES_VERSION); -+ seq_printf(seq, "CRYPTO_AES_VERSION %x\n", v); -+ if (v & BIT(17)) -+ seq_puts(seq, "AES 192\n"); -+ -+ v = readl(rkc->reg + CRYPTO_DES_VERSION); -+ seq_printf(seq, "CRYPTO_DES_VERSION %x\n", v); -+ v = readl(rkc->reg + CRYPTO_SM4_VERSION); -+ seq_printf(seq, "CRYPTO_SM4_VERSION %x\n", v); -+ v = readl(rkc->reg + CRYPTO_HASH_VERSION); -+ seq_printf(seq, "CRYPTO_HASH_VERSION %x\n", v); -+ v = readl(rkc->reg + CRYPTO_HMAC_VERSION); -+ seq_printf(seq, "CRYPTO_HMAC_VERSION %x\n", v); -+ v = readl(rkc->reg + CRYPTO_RNG_VERSION); -+ seq_printf(seq, "CRYPTO_RNG_VERSION %x\n", v); -+ v = readl(rkc->reg + CRYPTO_PKA_VERSION); -+ seq_printf(seq, "CRYPTO_PKA_VERSION %x\n", v); -+ v = readl(rkc->reg + CRYPTO_CRYPTO_VERSION); -+ seq_printf(seq, "CRYPTO_CRYPTO_VERSION %x\n", v); -+ } -+ spin_unlock(&rocklist.lock); -+ -+ return 0; -+} -+ -+DEFINE_SHOW_ATTRIBUTE(rk2_crypto_debugfs_stats); -+DEFINE_SHOW_ATTRIBUTE(rk2_crypto_debugfs_info); -+ -+#endif -+ -+static void register_debugfs(struct rk2_crypto_dev *crypto_dev) -+{ -+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG -+ /* Ignore error of debugfs */ -+ rocklist.dbgfs_dir = debugfs_create_dir("rk2_crypto", NULL); -+ rocklist.dbgfs_stats = debugfs_create_file("stats", 0440, -+ rocklist.dbgfs_dir, -+ &rocklist, -+ &rk2_crypto_debugfs_stats_fops); -+ rocklist.dbgfs_stats = debugfs_create_file("info", 0440, -+ rocklist.dbgfs_dir, -+ &rocklist, -+ &rk2_crypto_debugfs_info_fops); -+#endif -+} -+ -+static int rk2_crypto_register(struct rk2_crypto_dev *rkc) -+{ -+ unsigned int i, k; -+ int err = 0; -+ -+ for (i = 0; i < ARRAY_SIZE(rk2_crypto_algs); i++) { -+ rk2_crypto_algs[i].dev = rkc; -+ switch (rk2_crypto_algs[i].type) { -+ case CRYPTO_ALG_TYPE_SKCIPHER: -+ dev_info(rkc->dev, "Register %s as %s\n", -+ rk2_crypto_algs[i].alg.skcipher.base.base.cra_name, -+ rk2_crypto_algs[i].alg.skcipher.base.base.cra_driver_name); -+ err = crypto_engine_register_skcipher(&rk2_crypto_algs[i].alg.skcipher); -+ break; -+ case CRYPTO_ALG_TYPE_AHASH: -+ dev_info(rkc->dev, "Register %s as %s %d\n", -+ rk2_crypto_algs[i].alg.hash.base.halg.base.cra_name, -+ rk2_crypto_algs[i].alg.hash.base.halg.base.cra_driver_name, i); -+ err = crypto_engine_register_ahash(&rk2_crypto_algs[i].alg.hash); -+ break; -+ default: -+ dev_err(rkc->dev, "unknown algorithm\n"); -+ } -+ if (err) -+ goto err_cipher_algs; -+ } -+ return 0; -+ -+err_cipher_algs: -+ for (k = 0; k < i; k++) { -+ if (rk2_crypto_algs[k].type == CRYPTO_ALG_TYPE_SKCIPHER) -+ crypto_engine_unregister_skcipher(&rk2_crypto_algs[k].alg.skcipher); -+ else -+ crypto_engine_unregister_ahash(&rk2_crypto_algs[k].alg.hash); -+ } -+ return err; -+} -+ -+static void rk2_crypto_unregister(void) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(rk2_crypto_algs); i++) { -+ if (rk2_crypto_algs[i].type == CRYPTO_ALG_TYPE_SKCIPHER) -+ crypto_engine_unregister_skcipher(&rk2_crypto_algs[i].alg.skcipher); -+ else -+ crypto_engine_unregister_ahash(&rk2_crypto_algs[i].alg.hash); -+ } -+} -+ -+static const struct of_device_id crypto_of_id_table[] = { -+ { .compatible = "rockchip,rk3568-crypto", -+ .data = &rk3568_variant, -+ }, -+ { .compatible = "rockchip,rk3588-crypto", -+ .data = &rk3588_variant, -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, crypto_of_id_table); -+ -+static int rk2_crypto_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct rk2_crypto_dev *rkc, *first; -+ int err = 0; -+ -+ rkc = devm_kzalloc(&pdev->dev, sizeof(*rkc), GFP_KERNEL); -+ if (!rkc) { -+ err = -ENOMEM; -+ goto err_crypto; -+ } -+ -+ rkc->dev = &pdev->dev; -+ platform_set_drvdata(pdev, rkc); -+ -+ rkc->variant = of_device_get_match_data(&pdev->dev); -+ if (!rkc->variant) { -+ dev_err(&pdev->dev, "Missing variant\n"); -+ return -EINVAL; -+ } -+ -+ rkc->rst = devm_reset_control_array_get_exclusive(dev); -+ if (IS_ERR(rkc->rst)) { -+ err = PTR_ERR(rkc->rst); -+ dev_err(&pdev->dev, "Fail to get resets err=%d\n", err); -+ goto err_crypto; -+ } -+ -+ rkc->tl = dma_alloc_coherent(rkc->dev, -+ sizeof(struct rk2_crypto_lli) * MAX_LLI, -+ &rkc->t_phy, GFP_KERNEL); -+ if (!rkc->tl) { -+ dev_err(rkc->dev, "Cannot get DMA memory for task\n"); -+ err = -ENOMEM; -+ goto err_crypto; -+ } -+ -+ reset_control_assert(rkc->rst); -+ usleep_range(10, 20); -+ reset_control_deassert(rkc->rst); -+ -+ rkc->reg = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(rkc->reg)) { -+ err = PTR_ERR(rkc->reg); -+ dev_err(&pdev->dev, "Fail to get resources\n"); -+ goto err_crypto; -+ } -+ -+ err = rk2_crypto_get_clks(rkc); -+ if (err) -+ goto err_crypto; -+ -+ rkc->irq = platform_get_irq(pdev, 0); -+ if (rkc->irq < 0) { -+ dev_err(&pdev->dev, "control Interrupt is not available.\n"); -+ err = rkc->irq; -+ goto err_crypto; -+ } -+ -+ err = devm_request_irq(&pdev->dev, rkc->irq, -+ rk2_crypto_irq_handle, IRQF_SHARED, -+ "rk-crypto", pdev); -+ -+ if (err) { -+ dev_err(&pdev->dev, "irq request failed.\n"); -+ goto err_crypto; -+ } -+ -+ rkc->engine = crypto_engine_alloc_init(&pdev->dev, true); -+ crypto_engine_start(rkc->engine); -+ init_completion(&rkc->complete); -+ -+ err = rk2_crypto_pm_init(rkc); -+ if (err) -+ goto err_pm; -+ -+ err = pm_runtime_resume_and_get(&pdev->dev); -+ -+ spin_lock(&rocklist.lock); -+ first = list_first_entry_or_null(&rocklist.dev_list, -+ struct rk2_crypto_dev, list); -+ list_add_tail(&rkc->list, &rocklist.dev_list); -+ spin_unlock(&rocklist.lock); -+ -+ if (!first) { -+ dev_info(dev, "Registers crypto algos\n"); -+ err = rk2_crypto_register(rkc); -+ if (err) { -+ dev_err(dev, "Fail to register crypto algorithms"); -+ goto err_register_alg; -+ } -+ -+ register_debugfs(rkc); -+ } -+ -+ return 0; -+ -+err_register_alg: -+ rk2_crypto_pm_exit(rkc); -+err_pm: -+ crypto_engine_exit(rkc->engine); -+err_crypto: -+ dev_err(dev, "Crypto Accelerator not successfully registered\n"); -+ return err; -+} -+ -+static int rk2_crypto_remove(struct platform_device *pdev) -+{ -+ struct rk2_crypto_dev *rkc = platform_get_drvdata(pdev); -+ struct rk2_crypto_dev *first; -+ -+ spin_lock_bh(&rocklist.lock); -+ list_del(&rkc->list); -+ first = list_first_entry_or_null(&rocklist.dev_list, -+ struct rk2_crypto_dev, list); -+ spin_unlock_bh(&rocklist.lock); -+ -+ if (!first) { -+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG -+ debugfs_remove_recursive(rocklist.dbgfs_dir); -+#endif -+ rk2_crypto_unregister(); -+ } -+ rk2_crypto_pm_exit(rkc); -+ crypto_engine_exit(rkc->engine); -+ return 0; -+} -+ -+static struct platform_driver crypto_driver = { -+ .probe = rk2_crypto_probe, -+ .remove = rk2_crypto_remove, -+ .driver = { -+ .name = "rk2-crypto", -+ .pm = &rk2_crypto_pm_ops, -+ .of_match_table = crypto_of_id_table, -+ }, -+}; -+ -+module_platform_driver(crypto_driver); -+ -+MODULE_DESCRIPTION("Rockchip Crypto Engine cryptographic offloader"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Corentin Labbe "); -diff --git a/drivers/crypto/rockchip/rk2_crypto.h b/drivers/crypto/rockchip/rk2_crypto.h -new file mode 100644 -index 000000000000..59cd8be59f70 ---- /dev/null -+++ b/drivers/crypto/rockchip/rk2_crypto.h -@@ -0,0 +1,246 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define RK2_CRYPTO_CLK_CTL 0x0000 -+#define RK2_CRYPTO_RST_CTL 0x0004 -+ -+#define RK2_CRYPTO_DMA_INT_EN 0x0008 -+/* values for RK2_CRYPTO_DMA_INT_EN */ -+#define RK2_CRYPTO_DMA_INT_LISTDONE BIT(0) -+ -+#define RK2_CRYPTO_DMA_INT_ST 0x000C -+/* values in RK2_CRYPTO_DMA_INT_ST are the same than in RK2_CRYPTO_DMA_INT_EN */ -+ -+#define RK2_CRYPTO_DMA_CTL 0x0010 -+#define RK2_CRYPTO_DMA_CTL_START BIT(0) -+ -+#define RK2_CRYPTO_DMA_LLI_ADDR 0x0014 -+#define RK2_CRYPTO_DMA_ST 0x0018 -+#define RK2_CRYPTO_DMA_STATE 0x001C -+#define RK2_CRYPTO_DMA_LLI_RADDR 0x0020 -+#define RK2_CRYPTO_DMA_SRC_RADDR 0x0024 -+#define RK2_CRYPTO_DMA_DST_WADDR 0x0028 -+#define RK2_CRYPTO_DMA_ITEM_ID 0x002C -+ -+#define RK2_CRYPTO_FIFO_CTL 0x0040 -+ -+#define RK2_CRYPTO_BC_CTL 0x0044 -+#define RK2_CRYPTO_AES (0 << 8) -+#define RK2_CRYPTO_MODE_ECB (0 << 4) -+#define RK2_CRYPTO_MODE_CBC (1 << 4) -+#define RK2_CRYPTO_XTS (6 << 4) -+ -+#define RK2_CRYPTO_HASH_CTL 0x0048 -+#define RK2_CRYPTO_HW_PAD BIT(2) -+#define RK2_CRYPTO_SHA1 (0 << 4) -+#define RK2_CRYPTO_MD5 (1 << 4) -+#define RK2_CRYPTO_SHA224 (3 << 4) -+#define RK2_CRYPTO_SHA256 (2 << 4) -+#define RK2_CRYPTO_SHA384 (9 << 4) -+#define RK2_CRYPTO_SHA512 (8 << 4) -+#define RK2_CRYPTO_SM3 (4 << 4) -+ -+#define RK2_CRYPTO_AES_ECB (RK2_CRYPTO_AES | RK2_CRYPTO_MODE_ECB) -+#define RK2_CRYPTO_AES_CBC (RK2_CRYPTO_AES | RK2_CRYPTO_MODE_CBC) -+#define RK2_CRYPTO_AES_XTS (RK2_CRYPTO_AES | RK2_CRYPTO_XTS) -+#define RK2_CRYPTO_AES_CTR_MODE 3 -+#define RK2_CRYPTO_AES_128BIT_key (0 << 2) -+#define RK2_CRYPTO_AES_192BIT_key (1 << 2) -+#define RK2_CRYPTO_AES_256BIT_key (2 << 2) -+ -+#define RK2_CRYPTO_DEC BIT(1) -+#define RK2_CRYPTO_ENABLE BIT(0) -+ -+#define RK2_CRYPTO_CIPHER_ST 0x004C -+#define RK2_CRYPTO_CIPHER_STATE 0x0050 -+ -+#define RK2_CRYPTO_CH0_IV_0 0x0100 -+ -+#define RK2_CRYPTO_KEY0 0x0180 -+#define RK2_CRYPTO_KEY1 0x0184 -+#define RK2_CRYPTO_KEY2 0x0188 -+#define RK2_CRYPTO_KEY3 0x018C -+#define RK2_CRYPTO_KEY4 0x0190 -+#define RK2_CRYPTO_KEY5 0x0194 -+#define RK2_CRYPTO_KEY6 0x0198 -+#define RK2_CRYPTO_KEY7 0x019C -+#define RK2_CRYPTO_CH4_KEY0 0x01c0 -+ -+#define RK2_CRYPTO_CH0_PC_LEN_0 0x0280 -+ -+#define RK2_CRYPTO_CH0_IV_LEN 0x0300 -+ -+#define RK2_CRYPTO_HASH_DOUT_0 0x03A0 -+#define RK2_CRYPTO_HASH_VALID 0x03E4 -+ -+#define RK2_CRYPTO_TRNG_CTL 0x0400 -+#define RK2_CRYPTO_TRNG_START BIT(0) -+#define RK2_CRYPTO_TRNG_ENABLE BIT(1) -+#define RK2_CRYPTO_TRNG_256 (0x3 << 4) -+#define RK2_CRYPTO_TRNG_SAMPLE_CNT 0x0404 -+#define RK2_CRYPTO_TRNG_DOUT 0x0410 -+ -+#define CRYPTO_AES_VERSION 0x0680 -+#define CRYPTO_DES_VERSION 0x0684 -+#define CRYPTO_SM4_VERSION 0x0688 -+#define CRYPTO_HASH_VERSION 0x068C -+#define CRYPTO_HMAC_VERSION 0x0690 -+#define CRYPTO_RNG_VERSION 0x0694 -+#define CRYPTO_PKA_VERSION 0x0698 -+#define CRYPTO_CRYPTO_VERSION 0x06F0 -+ -+#define RK2_LLI_DMA_CTRL_SRC_INT BIT(10) -+#define RK2_LLI_DMA_CTRL_DST_INT BIT(9) -+#define RK2_LLI_DMA_CTRL_LIST_INT BIT(8) -+#define RK2_LLI_DMA_CTRL_LAST BIT(0) -+ -+#define RK2_LLI_STRING_LAST BIT(2) -+#define RK2_LLI_STRING_FIRST BIT(1) -+#define RK2_LLI_CIPHER_START BIT(0) -+ -+#define RK2_MAX_CLKS 4 -+ -+#define MAX_LLI 20 -+ -+struct rk2_crypto_lli { -+ __le32 src_addr; -+ __le32 src_len; -+ __le32 dst_addr; -+ __le32 dst_len; -+ __le32 user; -+ __le32 iv; -+ __le32 dma_ctrl; -+ __le32 next; -+}; -+ -+/* -+ * struct rockchip_ip - struct for managing a list of RK crypto instance -+ * @dev_list: Used for doing a list of rk2_crypto_dev -+ * @lock: Control access to dev_list -+ * @dbgfs_dir: Debugfs dentry for statistic directory -+ * @dbgfs_stats: Debugfs dentry for statistic counters -+ */ -+struct rockchip_ip { -+ struct list_head dev_list; -+ spinlock_t lock; /* Control access to dev_list */ -+ struct dentry *dbgfs_dir; -+ struct dentry *dbgfs_stats; -+}; -+ -+struct rk2_clks { -+ const char *name; -+ unsigned long max; -+}; -+ -+struct rk2_variant { -+ int num_clks; -+ struct rk2_clks rkclks[RK2_MAX_CLKS]; -+}; -+ -+struct rk2_crypto_dev { -+ struct list_head list; -+ struct device *dev; -+ struct clk_bulk_data *clks; -+ int num_clks; -+ struct reset_control *rst; -+ void __iomem *reg; -+ int irq; -+ const struct rk2_variant *variant; -+ unsigned long nreq; -+ struct crypto_engine *engine; -+ struct completion complete; -+ int status; -+ struct rk2_crypto_lli *tl; -+ dma_addr_t t_phy; -+}; -+ -+/* the private variable of hash */ -+struct rk2_ahash_ctx { -+ /* for fallback */ -+ struct crypto_ahash *fallback_tfm; -+}; -+ -+/* the private variable of hash for fallback */ -+struct rk2_ahash_rctx { -+ struct rk2_crypto_dev *dev; -+ struct ahash_request fallback_req; -+ u32 mode; -+ int nrsgs; -+}; -+ -+/* the private variable of cipher */ -+struct rk2_cipher_ctx { -+ unsigned int keylen; -+ u8 key[AES_MAX_KEY_SIZE * 2]; -+ u8 iv[AES_BLOCK_SIZE]; -+ struct crypto_skcipher *fallback_tfm; -+}; -+ -+struct rk2_cipher_rctx { -+ struct rk2_crypto_dev *dev; -+ u8 backup_iv[AES_BLOCK_SIZE]; -+ u32 mode; -+ struct skcipher_request fallback_req; // keep at the end -+}; -+ -+struct rk2_crypto_template { -+ u32 type; -+ u32 rk2_mode; -+ bool is_xts; -+ struct rk2_crypto_dev *dev; -+ union { -+ struct skcipher_engine_alg skcipher; -+ struct ahash_engine_alg hash; -+ } alg; -+ unsigned long stat_req; -+ unsigned long stat_fb; -+ unsigned long stat_fb_len; -+ unsigned long stat_fb_sglen; -+ unsigned long stat_fb_align; -+ unsigned long stat_fb_sgdiff; -+}; -+ -+struct rk2_crypto_dev *get_rk2_crypto(void); -+int rk2_cipher_run(struct crypto_engine *engine, void *async_req); -+int rk2_hash_run(struct crypto_engine *engine, void *breq); -+ -+int rk2_cipher_tfm_init(struct crypto_skcipher *tfm); -+void rk2_cipher_tfm_exit(struct crypto_skcipher *tfm); -+int rk2_aes_setkey(struct crypto_skcipher *cipher, const u8 *key, -+ unsigned int keylen); -+int rk2_aes_xts_setkey(struct crypto_skcipher *cipher, const u8 *key, -+ unsigned int keylen); -+int rk2_skcipher_encrypt(struct skcipher_request *req); -+int rk2_skcipher_decrypt(struct skcipher_request *req); -+int rk2_aes_ecb_encrypt(struct skcipher_request *req); -+int rk2_aes_ecb_decrypt(struct skcipher_request *req); -+int rk2_aes_cbc_encrypt(struct skcipher_request *req); -+int rk2_aes_cbc_decrypt(struct skcipher_request *req); -+ -+int rk2_ahash_init(struct ahash_request *req); -+int rk2_ahash_update(struct ahash_request *req); -+int rk2_ahash_final(struct ahash_request *req); -+int rk2_ahash_finup(struct ahash_request *req); -+int rk2_ahash_import(struct ahash_request *req, const void *in); -+int rk2_ahash_export(struct ahash_request *req, void *out); -+int rk2_ahash_digest(struct ahash_request *req); -+int rk2_hash_init_tfm(struct crypto_ahash *tfm); -+void rk2_hash_exit_tfm(struct crypto_ahash *tfm); -diff --git a/drivers/crypto/rockchip/rk2_crypto_ahash.c b/drivers/crypto/rockchip/rk2_crypto_ahash.c -new file mode 100644 -index 000000000000..75b8d9893447 ---- /dev/null -+++ b/drivers/crypto/rockchip/rk2_crypto_ahash.c -@@ -0,0 +1,344 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Crypto offloader support for Rockchip RK3568/RK3588 -+ * -+ * Copyright (c) 2022-2023 Corentin Labbe -+ */ -+#include -+#include -+#include "rk2_crypto.h" -+ -+static bool rk2_ahash_need_fallback(struct ahash_request *areq) -+{ -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); -+ struct ahash_alg *alg = crypto_ahash_alg(tfm); -+ struct rk2_crypto_template *algt = container_of(alg, struct rk2_crypto_template, alg.hash.base); -+ struct scatterlist *sg; -+ -+ sg = areq->src; -+ while (sg) { -+ if (!IS_ALIGNED(sg->offset, sizeof(u32))) { -+ algt->stat_fb_align++; -+ return true; -+ } -+ if (sg->length % 4) { -+ algt->stat_fb_sglen++; -+ return true; -+ } -+ sg = sg_next(sg); -+ } -+ return false; -+} -+ -+static int rk2_ahash_digest_fb(struct ahash_request *areq) -+{ -+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(areq); -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); -+ struct rk2_ahash_ctx *tfmctx = crypto_ahash_ctx(tfm); -+ struct ahash_alg *alg = crypto_ahash_alg(tfm); -+ struct rk2_crypto_template *algt = container_of(alg, struct rk2_crypto_template, alg.hash.base); -+ -+ algt->stat_fb++; -+ -+ ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm); -+ rctx->fallback_req.base.flags = areq->base.flags & -+ CRYPTO_TFM_REQ_MAY_SLEEP; -+ -+ rctx->fallback_req.nbytes = areq->nbytes; -+ rctx->fallback_req.src = areq->src; -+ rctx->fallback_req.result = areq->result; -+ -+ return crypto_ahash_digest(&rctx->fallback_req); -+} -+ -+static int zero_message_process(struct ahash_request *req) -+{ -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); -+ struct ahash_alg *alg = crypto_ahash_alg(tfm); -+ struct rk2_crypto_template *algt = container_of(alg, struct rk2_crypto_template, alg.hash.base); -+ int digestsize = crypto_ahash_digestsize(tfm); -+ -+ switch (algt->rk2_mode) { -+ case RK2_CRYPTO_SHA1: -+ memcpy(req->result, sha1_zero_message_hash, digestsize); -+ break; -+ case RK2_CRYPTO_SHA256: -+ memcpy(req->result, sha256_zero_message_hash, digestsize); -+ break; -+ case RK2_CRYPTO_SHA384: -+ memcpy(req->result, sha384_zero_message_hash, digestsize); -+ break; -+ case RK2_CRYPTO_SHA512: -+ memcpy(req->result, sha512_zero_message_hash, digestsize); -+ break; -+ case RK2_CRYPTO_MD5: -+ memcpy(req->result, md5_zero_message_hash, digestsize); -+ break; -+ case RK2_CRYPTO_SM3: -+ memcpy(req->result, sm3_zero_message_hash, digestsize); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+int rk2_ahash_init(struct ahash_request *req) -+{ -+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req); -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); -+ struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm); -+ -+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); -+ rctx->fallback_req.base.flags = req->base.flags & -+ CRYPTO_TFM_REQ_MAY_SLEEP; -+ -+ return crypto_ahash_init(&rctx->fallback_req); -+} -+ -+int rk2_ahash_update(struct ahash_request *req) -+{ -+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req); -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); -+ struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm); -+ -+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); -+ rctx->fallback_req.base.flags = req->base.flags & -+ CRYPTO_TFM_REQ_MAY_SLEEP; -+ rctx->fallback_req.nbytes = req->nbytes; -+ rctx->fallback_req.src = req->src; -+ -+ return crypto_ahash_update(&rctx->fallback_req); -+} -+ -+int rk2_ahash_final(struct ahash_request *req) -+{ -+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req); -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); -+ struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm); -+ -+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); -+ rctx->fallback_req.base.flags = req->base.flags & -+ CRYPTO_TFM_REQ_MAY_SLEEP; -+ rctx->fallback_req.result = req->result; -+ -+ return crypto_ahash_final(&rctx->fallback_req); -+} -+ -+int rk2_ahash_finup(struct ahash_request *req) -+{ -+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req); -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); -+ struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm); -+ -+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); -+ rctx->fallback_req.base.flags = req->base.flags & -+ CRYPTO_TFM_REQ_MAY_SLEEP; -+ -+ rctx->fallback_req.nbytes = req->nbytes; -+ rctx->fallback_req.src = req->src; -+ rctx->fallback_req.result = req->result; -+ -+ return crypto_ahash_finup(&rctx->fallback_req); -+} -+ -+int rk2_ahash_import(struct ahash_request *req, const void *in) -+{ -+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req); -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); -+ struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm); -+ -+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); -+ rctx->fallback_req.base.flags = req->base.flags & -+ CRYPTO_TFM_REQ_MAY_SLEEP; -+ -+ return crypto_ahash_import(&rctx->fallback_req, in); -+} -+ -+int rk2_ahash_export(struct ahash_request *req, void *out) -+{ -+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req); -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); -+ struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm); -+ -+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); -+ rctx->fallback_req.base.flags = req->base.flags & -+ CRYPTO_TFM_REQ_MAY_SLEEP; -+ -+ return crypto_ahash_export(&rctx->fallback_req, out); -+} -+ -+int rk2_ahash_digest(struct ahash_request *req) -+{ -+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req); -+ struct rk2_crypto_dev *dev; -+ struct crypto_engine *engine; -+ -+ if (rk2_ahash_need_fallback(req)) -+ return rk2_ahash_digest_fb(req); -+ -+ if (!req->nbytes) -+ return zero_message_process(req); -+ -+ dev = get_rk2_crypto(); -+ -+ rctx->dev = dev; -+ engine = dev->engine; -+ -+ return crypto_transfer_hash_request_to_engine(engine, req); -+} -+ -+static int rk2_hash_prepare(struct crypto_engine *engine, void *breq) -+{ -+ struct ahash_request *areq = container_of(breq, struct ahash_request, base); -+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(areq); -+ struct rk2_crypto_dev *rkc = rctx->dev; -+ int ret; -+ -+ ret = dma_map_sg(rkc->dev, areq->src, sg_nents(areq->src), DMA_TO_DEVICE); -+ if (ret <= 0) -+ return -EINVAL; -+ -+ rctx->nrsgs = ret; -+ -+ return 0; -+} -+ -+static void rk2_hash_unprepare(struct crypto_engine *engine, void *breq) -+{ -+ struct ahash_request *areq = container_of(breq, struct ahash_request, base); -+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(areq); -+ struct rk2_crypto_dev *rkc = rctx->dev; -+ -+ dma_unmap_sg(rkc->dev, areq->src, rctx->nrsgs, DMA_TO_DEVICE); -+} -+ -+int rk2_hash_run(struct crypto_engine *engine, void *breq) -+{ -+ struct ahash_request *areq = container_of(breq, struct ahash_request, base); -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); -+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(areq); -+ struct ahash_alg *alg = crypto_ahash_alg(tfm); -+ struct rk2_crypto_template *algt = container_of(alg, struct rk2_crypto_template, alg.hash.base); -+ struct scatterlist *sgs = areq->src; -+ struct rk2_crypto_dev *rkc = rctx->dev; -+ struct rk2_crypto_lli *dd = &rkc->tl[0]; -+ int ddi = 0; -+ int err = 0; -+ unsigned int len = areq->nbytes; -+ unsigned int todo; -+ u32 v; -+ int i; -+ -+ err = rk2_hash_prepare(engine, breq); -+ -+ err = pm_runtime_resume_and_get(rkc->dev); -+ if (err) -+ return err; -+ -+ dev_dbg(rkc->dev, "%s %s len=%d\n", __func__, -+ crypto_tfm_alg_name(areq->base.tfm), areq->nbytes); -+ -+ algt->stat_req++; -+ rkc->nreq++; -+ -+ rctx->mode = algt->rk2_mode; -+ rctx->mode |= 0xffff0000; -+ rctx->mode |= RK2_CRYPTO_ENABLE | RK2_CRYPTO_HW_PAD; -+ writel(rctx->mode, rkc->reg + RK2_CRYPTO_HASH_CTL); -+ -+ while (sgs && len > 0) { -+ dd = &rkc->tl[ddi]; -+ -+ todo = min(sg_dma_len(sgs), len); -+ dd->src_addr = sg_dma_address(sgs); -+ dd->src_len = todo; -+ dd->dst_addr = 0; -+ dd->dst_len = 0; -+ dd->dma_ctrl = ddi << 24; -+ dd->iv = 0; -+ dd->next = rkc->t_phy + sizeof(struct rk2_crypto_lli) * (ddi + 1); -+ -+ if (ddi == 0) -+ dd->user = RK2_LLI_CIPHER_START | RK2_LLI_STRING_FIRST; -+ else -+ dd->user = 0; -+ -+ len -= todo; -+ dd->dma_ctrl |= RK2_LLI_DMA_CTRL_SRC_INT; -+ if (len == 0) { -+ dd->user |= RK2_LLI_STRING_LAST; -+ dd->dma_ctrl |= RK2_LLI_DMA_CTRL_LAST; -+ } -+ dev_dbg(rkc->dev, "HASH SG %d sglen=%d user=%x dma=%x mode=%x len=%d todo=%d phy=%llx\n", -+ ddi, sgs->length, dd->user, dd->dma_ctrl, rctx->mode, len, todo, rkc->t_phy); -+ -+ sgs = sg_next(sgs); -+ ddi++; -+ } -+ dd->next = 1; -+ writel(RK2_CRYPTO_DMA_INT_LISTDONE | 0x7F, rkc->reg + RK2_CRYPTO_DMA_INT_EN); -+ -+ writel(rkc->t_phy, rkc->reg + RK2_CRYPTO_DMA_LLI_ADDR); -+ -+ reinit_completion(&rkc->complete); -+ rkc->status = 0; -+ -+ writel(RK2_CRYPTO_DMA_CTL_START | RK2_CRYPTO_DMA_CTL_START << 16, rkc->reg + RK2_CRYPTO_DMA_CTL); -+ -+ wait_for_completion_interruptible_timeout(&rkc->complete, -+ msecs_to_jiffies(2000)); -+ if (!rkc->status) { -+ dev_err(rkc->dev, "DMA timeout\n"); -+ err = -EFAULT; -+ goto theend; -+ } -+ -+ readl_poll_timeout_atomic(rkc->reg + RK2_CRYPTO_HASH_VALID, v, v == 1, -+ 10, 1000); -+ -+ for (i = 0; i < crypto_ahash_digestsize(tfm) / 4; i++) { -+ v = readl(rkc->reg + RK2_CRYPTO_HASH_DOUT_0 + i * 4); -+ put_unaligned_le32(be32_to_cpu(v), areq->result + i * 4); -+ } -+ -+theend: -+ pm_runtime_put_autosuspend(rkc->dev); -+ -+ rk2_hash_unprepare(engine, breq); -+ -+ local_bh_disable(); -+ crypto_finalize_hash_request(engine, breq, err); -+ local_bh_enable(); -+ -+ return 0; -+} -+ -+int rk2_hash_init_tfm(struct crypto_ahash *tfm) -+{ -+ struct rk2_ahash_ctx *tctx = crypto_ahash_ctx(tfm); -+ const char *alg_name = crypto_ahash_alg_name(tfm); -+ struct ahash_alg *alg = crypto_ahash_alg(tfm); -+ struct rk2_crypto_template *algt = container_of(alg, struct rk2_crypto_template, alg.hash.base); -+ -+ /* for fallback */ -+ tctx->fallback_tfm = crypto_alloc_ahash(alg_name, 0, -+ CRYPTO_ALG_NEED_FALLBACK); -+ if (IS_ERR(tctx->fallback_tfm)) { -+ dev_err(algt->dev->dev, "Could not load fallback driver.\n"); -+ return PTR_ERR(tctx->fallback_tfm); -+ } -+ -+ crypto_ahash_set_reqsize(tfm, -+ sizeof(struct rk2_ahash_rctx) + -+ crypto_ahash_reqsize(tctx->fallback_tfm)); -+ return 0; -+} -+ -+void rk2_hash_exit_tfm(struct crypto_ahash *tfm) -+{ -+ struct rk2_ahash_ctx *tctx = crypto_ahash_ctx(tfm); -+ -+ crypto_free_ahash(tctx->fallback_tfm); -+} -diff --git a/drivers/crypto/rockchip/rk2_crypto_skcipher.c b/drivers/crypto/rockchip/rk2_crypto_skcipher.c -new file mode 100644 -index 000000000000..3e8e44d84b47 ---- /dev/null -+++ b/drivers/crypto/rockchip/rk2_crypto_skcipher.c -@@ -0,0 +1,576 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * hardware cryptographic offloader for RK3568/RK3588 SoC -+ * -+ * Copyright (c) 2022-2023 Corentin Labbe -+ */ -+#include -+#include "rk2_crypto.h" -+ -+static void rk2_print(struct rk2_crypto_dev *rkc) -+{ -+ u32 v; -+ -+ v = readl(rkc->reg + RK2_CRYPTO_DMA_ST); -+ dev_info(rkc->dev, "DMA_ST %x\n", v); -+ switch (v) { -+ case 0: -+ dev_info(rkc->dev, "DMA_ST: DMA IDLE\n"); -+ break; -+ case 1: -+ dev_info(rkc->dev, "DMA_ST: DMA BUSY\n"); -+ break; -+ default: -+ dev_err(rkc->dev, "DMA_ST: invalid value\n"); -+ } -+ -+ v = readl(rkc->reg + RK2_CRYPTO_DMA_STATE); -+ dev_info(rkc->dev, "DMA_STATE %x\n", v); -+ -+ switch (v & 0x3) { -+ case 0: -+ dev_info(rkc->dev, "DMA_STATE: DMA DST IDLE\n"); -+ break; -+ case 1: -+ dev_info(rkc->dev, "DMA_STATE: DMA DST LOAD\n"); -+ break; -+ case 2: -+ dev_info(rkc->dev, "DMA_STATE: DMA DST WORK\n"); -+ break; -+ default: -+ dev_err(rkc->dev, "DMA DST invalid\n"); -+ break; -+ } -+ switch (v & 0xC) { -+ case 0: -+ dev_info(rkc->dev, "DMA_STATE: DMA SRC IDLE\n"); -+ break; -+ case 1: -+ dev_info(rkc->dev, "DMA_STATE: DMA SRC LOAD\n"); -+ break; -+ case 2: -+ dev_info(rkc->dev, "DMA_STATE: DMA SRC WORK\n"); -+ break; -+ default: -+ dev_err(rkc->dev, "DMA_STATE: DMA SRC invalid\n"); -+ break; -+ } -+ switch (v & 0x30) { -+ case 0: -+ dev_info(rkc->dev, "DMA_STATE: DMA LLI IDLE\n"); -+ break; -+ case 1: -+ dev_info(rkc->dev, "DMA_STATE: DMA LLI LOAD\n"); -+ break; -+ case 2: -+ dev_info(rkc->dev, "DMA LLI WORK\n"); -+ break; -+ default: -+ dev_err(rkc->dev, "DMA LLI invalid\n"); -+ break; -+ } -+ -+ v = readl(rkc->reg + RK2_CRYPTO_DMA_LLI_RADDR); -+ dev_info(rkc->dev, "DMA_LLI_RADDR %x\n", v); -+ v = readl(rkc->reg + RK2_CRYPTO_DMA_SRC_RADDR); -+ dev_info(rkc->dev, "DMA_SRC_RADDR %x\n", v); -+ v = readl(rkc->reg + RK2_CRYPTO_DMA_DST_WADDR); -+ dev_info(rkc->dev, "DMA_LLI_WADDR %x\n", v); -+ v = readl(rkc->reg + RK2_CRYPTO_DMA_ITEM_ID); -+ dev_info(rkc->dev, "DMA_LLI_ITEMID %x\n", v); -+ -+ v = readl(rkc->reg + RK2_CRYPTO_CIPHER_ST); -+ dev_info(rkc->dev, "CIPHER_ST %x\n", v); -+ if (v & BIT(0)) -+ dev_info(rkc->dev, "CIPHER_ST: BLOCK CIPHER BUSY\n"); -+ else -+ dev_info(rkc->dev, "CIPHER_ST: BLOCK CIPHER IDLE\n"); -+ if (v & BIT(2)) -+ dev_info(rkc->dev, "CIPHER_ST: HASH BUSY\n"); -+ else -+ dev_info(rkc->dev, "CIPHER_ST: HASH IDLE\n"); -+ if (v & BIT(2)) -+ dev_info(rkc->dev, "CIPHER_ST: OTP KEY VALID\n"); -+ else -+ dev_info(rkc->dev, "CIPHER_ST: OTP KEY INVALID\n"); -+ -+ v = readl(rkc->reg + RK2_CRYPTO_CIPHER_STATE); -+ dev_info(rkc->dev, "CIPHER_STATE %x\n", v); -+ switch (v & 0x3) { -+ case 0: -+ dev_info(rkc->dev, "serial: IDLE state\n"); -+ break; -+ case 1: -+ dev_info(rkc->dev, "serial: PRE state\n"); -+ break; -+ case 2: -+ dev_info(rkc->dev, "serial: BULK state\n"); -+ break; -+ default: -+ dev_info(rkc->dev, "serial: reserved state\n"); -+ break; -+ } -+ switch (v & 0xC) { -+ case 0: -+ dev_info(rkc->dev, "mac_state: IDLE state\n"); -+ break; -+ case 1: -+ dev_info(rkc->dev, "mac_state: PRE state\n"); -+ break; -+ case 2: -+ dev_info(rkc->dev, "mac_state: BULK state\n"); -+ break; -+ default: -+ dev_info(rkc->dev, "mac_state: reserved state\n"); -+ break; -+ } -+ switch (v & 0x30) { -+ case 0: -+ dev_info(rkc->dev, "parallel_state: IDLE state\n"); -+ break; -+ case 1: -+ dev_info(rkc->dev, "parallel_state: PRE state\n"); -+ break; -+ case 2: -+ dev_info(rkc->dev, "parallel_state: BULK state\n"); -+ break; -+ default: -+ dev_info(rkc->dev, "parallel_state: reserved state\n"); -+ break; -+ } -+ switch (v & 0xC0) { -+ case 0: -+ dev_info(rkc->dev, "ccm_state: IDLE state\n"); -+ break; -+ case 1: -+ dev_info(rkc->dev, "ccm_state: PRE state\n"); -+ break; -+ case 2: -+ dev_info(rkc->dev, "ccm_state: NA state\n"); -+ break; -+ default: -+ dev_info(rkc->dev, "ccm_state: reserved state\n"); -+ break; -+ } -+ switch (v & 0xF00) { -+ case 0: -+ dev_info(rkc->dev, "gcm_state: IDLE state\n"); -+ break; -+ case 1: -+ dev_info(rkc->dev, "gcm_state: PRE state\n"); -+ break; -+ case 2: -+ dev_info(rkc->dev, "gcm_state: NA state\n"); -+ break; -+ case 3: -+ dev_info(rkc->dev, "gcm_state: PC state\n"); -+ break; -+ } -+ switch (v & 0xC00) { -+ case 0x1: -+ dev_info(rkc->dev, "hash_state: IDLE state\n"); -+ break; -+ case 0x2: -+ dev_info(rkc->dev, "hash_state: IPAD state\n"); -+ break; -+ case 0x4: -+ dev_info(rkc->dev, "hash_state: TEXT state\n"); -+ break; -+ case 0x8: -+ dev_info(rkc->dev, "hash_state: OPAD state\n"); -+ break; -+ case 0x10: -+ dev_info(rkc->dev, "hash_state: OPAD EXT state\n"); -+ break; -+ default: -+ dev_info(rkc->dev, "hash_state: invalid state\n"); -+ break; -+ } -+ -+ v = readl(rkc->reg + RK2_CRYPTO_DMA_INT_ST); -+ dev_info(rkc->dev, "RK2_CRYPTO_DMA_INT_ST %x\n", v); -+} -+ -+static int rk2_cipher_need_fallback(struct skcipher_request *req) -+{ -+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); -+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm); -+ struct rk2_crypto_template *algt = container_of(alg, struct rk2_crypto_template, alg.skcipher.base); -+ struct scatterlist *sgs, *sgd; -+ unsigned int stodo, dtodo, len; -+ unsigned int bs = crypto_skcipher_blocksize(tfm); -+ -+ if (!req->cryptlen) -+ return true; -+ -+ if (algt->is_xts) { -+ if (sg_nents_for_len(req->src, req->cryptlen) > 1) -+ return true; -+ if (sg_nents_for_len(req->dst, req->cryptlen) > 1) -+ return true; -+ } -+ -+ len = req->cryptlen; -+ sgs = req->src; -+ sgd = req->dst; -+ while (sgs && sgd) { -+ if (!IS_ALIGNED(sgs->offset, sizeof(u32))) { -+ algt->stat_fb_align++; -+ return true; -+ } -+ if (!IS_ALIGNED(sgd->offset, sizeof(u32))) { -+ algt->stat_fb_align++; -+ return true; -+ } -+ stodo = min(len, sgs->length); -+ if (stodo % bs) { -+ algt->stat_fb_len++; -+ return true; -+ } -+ dtodo = min(len, sgd->length); -+ if (dtodo % bs) { -+ algt->stat_fb_len++; -+ return true; -+ } -+ if (stodo != dtodo) { -+ algt->stat_fb_sgdiff++; -+ return true; -+ } -+ len -= stodo; -+ sgs = sg_next(sgs); -+ sgd = sg_next(sgd); -+ } -+ return false; -+} -+ -+static int rk2_cipher_fallback(struct skcipher_request *areq) -+{ -+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); -+ struct rk2_cipher_ctx *op = crypto_skcipher_ctx(tfm); -+ struct rk2_cipher_rctx *rctx = skcipher_request_ctx(areq); -+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm); -+ struct rk2_crypto_template *algt = container_of(alg, struct rk2_crypto_template, alg.skcipher.base); -+ int err; -+ -+ algt->stat_fb++; -+ -+ skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm); -+ skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags, -+ areq->base.complete, areq->base.data); -+ skcipher_request_set_crypt(&rctx->fallback_req, areq->src, areq->dst, -+ areq->cryptlen, areq->iv); -+ if (rctx->mode & RK2_CRYPTO_DEC) -+ err = crypto_skcipher_decrypt(&rctx->fallback_req); -+ else -+ err = crypto_skcipher_encrypt(&rctx->fallback_req); -+ return err; -+} -+ -+static int rk2_cipher_handle_req(struct skcipher_request *req) -+{ -+ struct rk2_cipher_rctx *rctx = skcipher_request_ctx(req); -+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); -+ struct rk2_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); -+ struct rk2_crypto_dev *rkc; -+ struct crypto_engine *engine; -+ -+ if (ctx->keylen == AES_KEYSIZE_192 * 2) -+ return rk2_cipher_fallback(req); -+ -+ if (rk2_cipher_need_fallback(req)) -+ return rk2_cipher_fallback(req); -+ -+ rkc = get_rk2_crypto(); -+ -+ engine = rkc->engine; -+ rctx->dev = rkc; -+ -+ return crypto_transfer_skcipher_request_to_engine(engine, req); -+} -+ -+int rk2_aes_xts_setkey(struct crypto_skcipher *cipher, const u8 *key, -+ unsigned int keylen) -+{ -+ struct crypto_tfm *tfm = crypto_skcipher_tfm(cipher); -+ struct rk2_cipher_ctx *ctx = crypto_tfm_ctx(tfm); -+ int err; -+ -+ err = xts_verify_key(cipher, key, keylen); -+ if (err) -+ return err; -+ -+ ctx->keylen = keylen; -+ memcpy(ctx->key, key, keylen); -+ -+ return crypto_skcipher_setkey(ctx->fallback_tfm, key, keylen); -+} -+ -+int rk2_aes_setkey(struct crypto_skcipher *cipher, const u8 *key, -+ unsigned int keylen) -+{ -+ struct crypto_tfm *tfm = crypto_skcipher_tfm(cipher); -+ struct rk2_cipher_ctx *ctx = crypto_tfm_ctx(tfm); -+ -+ if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 && -+ keylen != AES_KEYSIZE_256) -+ return -EINVAL; -+ ctx->keylen = keylen; -+ memcpy(ctx->key, key, keylen); -+ -+ return crypto_skcipher_setkey(ctx->fallback_tfm, key, keylen); -+} -+ -+int rk2_skcipher_encrypt(struct skcipher_request *req) -+{ -+ struct rk2_cipher_rctx *rctx = skcipher_request_ctx(req); -+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); -+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm); -+ struct rk2_crypto_template *algt = container_of(alg, struct rk2_crypto_template, alg.skcipher.base); -+ -+ rctx->mode = algt->rk2_mode; -+ return rk2_cipher_handle_req(req); -+} -+ -+int rk2_skcipher_decrypt(struct skcipher_request *req) -+{ -+ struct rk2_cipher_rctx *rctx = skcipher_request_ctx(req); -+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); -+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm); -+ struct rk2_crypto_template *algt = container_of(alg, struct rk2_crypto_template, alg.skcipher.base); -+ -+ rctx->mode = algt->rk2_mode | RK2_CRYPTO_DEC; -+ return rk2_cipher_handle_req(req); -+} -+ -+int rk2_cipher_run(struct crypto_engine *engine, void *async_req) -+{ -+ struct skcipher_request *areq = container_of(async_req, struct skcipher_request, base); -+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); -+ struct rk2_cipher_rctx *rctx = skcipher_request_ctx(areq); -+ struct rk2_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); -+ struct scatterlist *sgs, *sgd; -+ int err = 0; -+ int ivsize = crypto_skcipher_ivsize(tfm); -+ unsigned int len = areq->cryptlen; -+ unsigned int todo; -+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm); -+ struct rk2_crypto_template *algt = container_of(alg, struct rk2_crypto_template, alg.skcipher.base); -+ struct rk2_crypto_dev *rkc = rctx->dev; -+ struct rk2_crypto_lli *dd = &rkc->tl[0]; -+ u32 m, v; -+ u32 *rkey = (u32 *)ctx->key; -+ u32 *riv = (u32 *)areq->iv; -+ int i; -+ unsigned int offset; -+ -+ algt->stat_req++; -+ rkc->nreq++; -+ -+ m = rctx->mode | RK2_CRYPTO_ENABLE; -+ if (algt->is_xts) { -+ switch (ctx->keylen) { -+ case AES_KEYSIZE_128 * 2: -+ m |= RK2_CRYPTO_AES_128BIT_key; -+ break; -+ case AES_KEYSIZE_256 * 2: -+ m |= RK2_CRYPTO_AES_256BIT_key; -+ break; -+ default: -+ dev_err(rkc->dev, "Invalid key length %u\n", ctx->keylen); -+ return -EINVAL; -+ } -+ } else { -+ switch (ctx->keylen) { -+ case AES_KEYSIZE_128: -+ m |= RK2_CRYPTO_AES_128BIT_key; -+ break; -+ case AES_KEYSIZE_192: -+ m |= RK2_CRYPTO_AES_192BIT_key; -+ break; -+ case AES_KEYSIZE_256: -+ m |= RK2_CRYPTO_AES_256BIT_key; -+ break; -+ default: -+ dev_err(rkc->dev, "Invalid key length %u\n", ctx->keylen); -+ return -EINVAL; -+ } -+ } -+ -+ err = pm_runtime_resume_and_get(rkc->dev); -+ if (err) -+ return err; -+ -+ /* the upper bits are a write enable mask, so we need to write 1 to all -+ * upper 16 bits to allow write to the 16 lower bits -+ */ -+ m |= 0xffff0000; -+ -+ dev_dbg(rkc->dev, "%s %s len=%u keylen=%u mode=%x\n", __func__, -+ crypto_tfm_alg_name(areq->base.tfm), -+ areq->cryptlen, ctx->keylen, m); -+ sgs = areq->src; -+ sgd = areq->dst; -+ -+ while (sgs && sgd && len) { -+ ivsize = crypto_skcipher_ivsize(tfm); -+ if (areq->iv && crypto_skcipher_ivsize(tfm) > 0) { -+ if (rctx->mode & RK2_CRYPTO_DEC) { -+ offset = sgs->length - ivsize; -+ scatterwalk_map_and_copy(rctx->backup_iv, sgs, -+ offset, ivsize, 0); -+ } -+ } -+ -+ dev_dbg(rkc->dev, "SG len=%u mode=%x ivsize=%u\n", sgs->length, m, ivsize); -+ -+ if (sgs == sgd) { -+ err = dma_map_sg(rkc->dev, sgs, 1, DMA_BIDIRECTIONAL); -+ if (err != 1) { -+ dev_err(rkc->dev, "Invalid sg number %d\n", err); -+ err = -EINVAL; -+ goto theend; -+ } -+ } else { -+ err = dma_map_sg(rkc->dev, sgs, 1, DMA_TO_DEVICE); -+ if (err != 1) { -+ dev_err(rkc->dev, "Invalid sg number %d\n", err); -+ err = -EINVAL; -+ goto theend; -+ } -+ err = dma_map_sg(rkc->dev, sgd, 1, DMA_FROM_DEVICE); -+ if (err != 1) { -+ dev_err(rkc->dev, "Invalid sg number %d\n", err); -+ err = -EINVAL; -+ dma_unmap_sg(rkc->dev, sgs, 1, DMA_TO_DEVICE); -+ goto theend; -+ } -+ } -+ err = 0; -+ writel(m, rkc->reg + RK2_CRYPTO_BC_CTL); -+ -+ if (algt->is_xts) { -+ for (i = 0; i < ctx->keylen / 8; i++) { -+ v = cpu_to_be32(rkey[i]); -+ writel(v, rkc->reg + RK2_CRYPTO_KEY0 + i * 4); -+ } -+ for (i = 0; i < (ctx->keylen / 8); i++) { -+ v = cpu_to_be32(rkey[i + ctx->keylen / 8]); -+ writel(v, rkc->reg + RK2_CRYPTO_CH4_KEY0 + i * 4); -+ } -+ } else { -+ for (i = 0; i < ctx->keylen / 4; i++) { -+ v = cpu_to_be32(rkey[i]); -+ writel(v, rkc->reg + RK2_CRYPTO_KEY0 + i * 4); -+ } -+ } -+ -+ if (ivsize) { -+ for (i = 0; i < ivsize / 4; i++) -+ writel(cpu_to_be32(riv[i]), -+ rkc->reg + RK2_CRYPTO_CH0_IV_0 + i * 4); -+ writel(ivsize, rkc->reg + RK2_CRYPTO_CH0_IV_LEN); -+ } -+ if (!sgs->length) { -+ sgs = sg_next(sgs); -+ sgd = sg_next(sgd); -+ continue; -+ } -+ -+ /* The hw support multiple descriptor, so why this driver use -+ * only one descriptor ? -+ * Using one descriptor per SG seems the way to do and it works -+ * but only when doing encryption. -+ * With decryption it always fail on second descriptor. -+ * Probably the HW dont know how to use IV. -+ */ -+ todo = min(sg_dma_len(sgs), len); -+ len -= todo; -+ dd->src_addr = sg_dma_address(sgs); -+ dd->src_len = todo; -+ dd->dst_addr = sg_dma_address(sgd); -+ dd->dst_len = todo; -+ dd->iv = 0; -+ dd->next = 1; -+ -+ dd->user = RK2_LLI_CIPHER_START | RK2_LLI_STRING_FIRST | RK2_LLI_STRING_LAST; -+ dd->dma_ctrl |= RK2_LLI_DMA_CTRL_DST_INT | RK2_LLI_DMA_CTRL_LAST; -+ -+ writel(RK2_CRYPTO_DMA_INT_LISTDONE | 0x7F, rkc->reg + RK2_CRYPTO_DMA_INT_EN); -+ -+ /*writel(0x00030000, rkc->reg + RK2_CRYPTO_FIFO_CTL);*/ -+ writel(rkc->t_phy, rkc->reg + RK2_CRYPTO_DMA_LLI_ADDR); -+ -+ reinit_completion(&rkc->complete); -+ rkc->status = 0; -+ -+ writel(RK2_CRYPTO_DMA_CTL_START | 1 << 16, rkc->reg + RK2_CRYPTO_DMA_CTL); -+ -+ wait_for_completion_interruptible_timeout(&rkc->complete, -+ msecs_to_jiffies(10000)); -+ if (sgs == sgd) { -+ dma_unmap_sg(rkc->dev, sgs, 1, DMA_BIDIRECTIONAL); -+ } else { -+ dma_unmap_sg(rkc->dev, sgs, 1, DMA_TO_DEVICE); -+ dma_unmap_sg(rkc->dev, sgd, 1, DMA_FROM_DEVICE); -+ } -+ -+ if (!rkc->status) { -+ dev_err(rkc->dev, "DMA timeout\n"); -+ rk2_print(rkc); -+ err = -EFAULT; -+ goto theend; -+ } -+ if (areq->iv && ivsize > 0) { -+ offset = sgd->length - ivsize; -+ if (rctx->mode & RK2_CRYPTO_DEC) { -+ memcpy(areq->iv, rctx->backup_iv, ivsize); -+ memzero_explicit(rctx->backup_iv, ivsize); -+ } else { -+ scatterwalk_map_and_copy(areq->iv, sgd, offset, -+ ivsize, 0); -+ } -+ } -+ sgs = sg_next(sgs); -+ sgd = sg_next(sgd); -+ } -+theend: -+ writel(0xffff0000, rkc->reg + RK2_CRYPTO_BC_CTL); -+ pm_runtime_put_autosuspend(rkc->dev); -+ -+ local_bh_disable(); -+ crypto_finalize_skcipher_request(engine, areq, err); -+ local_bh_enable(); -+ return 0; -+} -+ -+int rk2_cipher_tfm_init(struct crypto_skcipher *tfm) -+{ -+ struct rk2_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); -+ const char *name = crypto_tfm_alg_name(&tfm->base); -+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm); -+ struct rk2_crypto_template *algt = container_of(alg, struct rk2_crypto_template, alg.skcipher.base); -+ -+ ctx->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); -+ if (IS_ERR(ctx->fallback_tfm)) { -+ dev_err(algt->dev->dev, "ERROR: Cannot allocate fallback for %s %ld\n", -+ name, PTR_ERR(ctx->fallback_tfm)); -+ return PTR_ERR(ctx->fallback_tfm); -+ } -+ -+ dev_info(algt->dev->dev, "Fallback for %s is %s\n", -+ crypto_tfm_alg_driver_name(&tfm->base), -+ crypto_tfm_alg_driver_name(crypto_skcipher_tfm(ctx->fallback_tfm))); -+ -+ tfm->reqsize = sizeof(struct rk2_cipher_rctx) + -+ crypto_skcipher_reqsize(ctx->fallback_tfm); -+ -+ return 0; -+} -+ -+void rk2_cipher_tfm_exit(struct crypto_skcipher *tfm) -+{ -+ struct rk2_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); -+ -+ memzero_explicit(ctx->key, ctx->keylen); -+ crypto_free_skcipher(ctx->fallback_tfm); -+} --- -2.42.0 - diff --git a/shared/platform/orangepi5plus/rk3588-v6.10-rc1.patch b/shared/platform/orangepi5plus/rk3588-v6.10-rc1.patch deleted file mode 100644 index 6a55be7..0000000 --- a/shared/platform/orangepi5plus/rk3588-v6.10-rc1.patch +++ /dev/null @@ -1,12673 +0,0 @@ -From 6b7104d36138a01859f23a81a565f1bbba89ecac Mon Sep 17 00:00:00 2001 -From: Christopher Obbard -Date: Mon, 20 Feb 2023 16:59:04 +0000 -Subject: [PATCH 01/54] [NOUPSTREAM] Add GitLab CI support - -Add CI support. This will do the following: - -1. Run dt_binding_check to make sure no major flaws were introduced in - the DT bindings -2. Run dtbs_check, for Rock 5A, Rock 5B and EVB1. If warnings are - generated the CI will report that as warning -3. Build a Kernel .deb package -4. Generate a test job for LAVA and run it - -Co-developed-by: Sebastian Reichel -Co-developed-by: Sjoerd Simons -Signed-off-by: Sebastian Reichel -Signed-off-by: Sjoerd Simons -Signed-off-by: Christopher Obbard ---- - .gitignore | 1 + - .gitlab-ci.yml | 142 ++++++++++++++++++++++++++++++++++++++++++++++ - lava/testjob.yaml | 73 ++++++++++++++++++++++++ - 3 files changed, 216 insertions(+) - create mode 100644 .gitlab-ci.yml - create mode 100644 lava/testjob.yaml - -diff --git a/.gitignore b/.gitignore -index c59dc60ba62e..59aa4da11b89 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -104,6 +104,7 @@ modules.order - !.kunitconfig - !.mailmap - !.rustfmt.toml -+!.gitlab-ci.yml - - # - # Generated include files -diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml -new file mode 100644 -index 000000000000..5582b71f0c67 ---- /dev/null -+++ b/.gitlab-ci.yml -@@ -0,0 +1,142 @@ -+default: -+ image: debian:testing -+ tags: -+ - bookworm -+ -+stages: -+ - build -+ - test -+ - generate -+ - lava -+ -+check devicetrees: -+ stage: build -+ tags: -+ - ultra-heavyweight -+ variables: -+ DEBIAN_FRONTEND: noninteractive -+ GIT_SUBMODULE_STRATEGY: normal -+ ARCH: arm64 -+ DEFCONFIG: defconfig -+ CROSS_COMPILE: aarch64-linux-gnu- -+ DUT: rockchip/rk3588s-rock-5a.dtb rockchip/rk3588-rock-5b.dtb rockchip/rk3588-evb1-v10.dtb -+ before_script: -+ - apt update -+ - apt install -y devscripts -+ build-essential -+ crossbuild-essential-arm64 -+ bc -+ bison -+ flex -+ swig -+ python3-dev -+ python3-pip -+ yamllint -+ - pip3 install --break-system-packages dtschema -+ script: -+ - make $DEFCONFIG -+ - make -j$(nproc) dt_binding_check -+ - make -j$(nproc) CHECK_DTBS=y $DUT 2> dt-warnings.txt -+ - if [[ $(cat dt-warnings.txt | wc -l) > 0 ]]; then cat dt-warnings.txt; exit 42; fi -+ allow_failure: -+ exit_codes: -+ - 42 -+ -+.build debian package: -+ stage: build -+ tags: -+ - ultra-heavyweight -+ cache: -+ when: on_success -+ key: $CI_COMMIT_REF_SLUG -+ paths: -+ - ccache -+ variables: -+ DEBIAN_FRONTEND: noninteractive -+ GIT_SUBMODULE_STRATEGY: normal -+ ARCH: amd64 -+ DEFCONFIG: defconfig -+ CCACHE_BASEDIR: $CI_PROJECT_DIR -+ CCACHE_DIR: $CI_PROJECT_DIR/ccache -+ before_script: -+ - apt update -+ - apt install -y devscripts -+ build-essential -+ crossbuild-essential-arm64 -+ bc -+ bison -+ ccache -+ flex -+ rsync -+ kmod -+ cpio -+ libelf-dev -+ libssl-dev -+ # Setup ccache -+ - export PATH="/usr/lib/ccache:$PATH" -+ - ccache -s -+ script: -+ - make $DEFCONFIG -+ - ./scripts/config -e WLAN -e WLAN_VENDOR_BROADCOM -m BRCMUTIL -m BRCMFMAC -+ -e BRCMFMAC_PROTO_BCDC -e BRCMFMAC_PROTO_MSGBUF -+ -e BRCMFMAC_USB -+ -e WLAN_VENDOR_REALTEK -m RTW89 -m RTW89_CORE -+ -m RTW89_PCI -m RTW89_8825B -m RTW89_8852BE -+ -m BINFMT_MISC -+ - make -j$(nproc) $ADDITIONAL_BUILD_CMD bindeb-pkg -+ - mkdir artifacts && dcmd mv ../*.changes artifacts/ -+ artifacts: -+ paths: -+ - artifacts -+ -+build arm64 debian package: -+ extends: .build debian package -+ variables: -+ ARCH: arm64 -+ CROSS_COMPILE: aarch64-linux-gnu- -+ ADDITIONAL_BUILD_CMD: KBUILD_IMAGE=arch/arm64/boot/Image -+ -+generate tests: -+ image: debian:bookworm-slim -+ stage: generate -+ tags: -+ - lightweight -+ variables: -+ GIT_STRATEGY: fetch -+ GIT_DEPTH: "1" -+ needs: -+ - "build arm64 debian package" -+ before_script: -+ - apt update -+ - apt install -y wget -+ script: -+ - mkdir deb -+ - "for x in artifacts/linux-image*.deb ; do dpkg -x ${x} deb ; done" -+ - cp deb/boot/vmlinuz* vmlinuz -+ - mkdir -p deb/lib/firmware/arm/mali/arch10.8 -+ - wget -O deb/lib/firmware/arm/mali/arch10.8/mali_csffw.bin "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/arm/mali/arch10.8/mali_csffw.bin" -+ - tar -f modules.tar.gz -C deb -c -z -v lib/modules lib/firmware -+ - mkdir dtbs -+ - cp -r deb/usr/lib/linux-image*/* dtbs -+ - sed -i s,%%KERNEL_BUILD_JOB%%,${CI_JOB_ID},g lava/testjob.yaml -+ artifacts: -+ paths: -+ - vmlinuz* -+ - modules.tar.gz -+ - dtbs -+ - lava/testjob.yaml -+ -+lava test: -+ stage: lava -+ tags: -+ - lava-runner -+ script: -+ - submit lava/testjob.yaml -+ needs: -+ - "generate tests" -+ artifacts: -+ when: always -+ paths: -+ - "*" -+ reports: -+ junit: "*.xml" -diff --git a/lava/testjob.yaml b/lava/testjob.yaml -new file mode 100644 -index 000000000000..8dfaf772296c ---- /dev/null -+++ b/lava/testjob.yaml -@@ -0,0 +1,73 @@ -+device_type: rk3588-rock-5b -+ -+job_name: Hardware enablement tests {{job.CI_JOB_ID}} -+timeouts: -+ job: -+ minutes: 15 -+ action: -+ minutes: 5 -+priority: high -+visibility: public -+ -+context: -+ extra_kernel_args: rootwait -+ -+actions: -+ - deploy: -+ timeout: -+ minutes: 2 -+ to: tftp -+ kernel: -+ url: "{{job.CI_PROJECT_URL}}/-/jobs/%%KERNEL_BUILD_JOB%%/artifacts/raw/vmlinuz" -+ type: image -+ modules: -+ url: "{{job.CI_PROJECT_URL}}/-/jobs/%%KERNEL_BUILD_JOB%%/artifacts/raw/modules.tar.gz" -+ compression: gz -+ dtb: -+ url: "{{job.CI_PROJECT_URL}}/-/jobs/%%KERNEL_BUILD_JOB%%/artifacts/raw/dtbs/rockchip/rk3588-rock-5b.dtb" -+ ramdisk: -+ url: https://gitlab.collabora.com/lava/health-check-images/-/jobs/artifacts/bookworm/raw/bookworm/bookworm-rootfs-arm64-initramfs.gz?job=build+bookworm+image:+%5Barm64,+rootfs%5D -+ compression: gz -+ nfsrootfs: -+ url: https://gitlab.collabora.com/lava/health-check-images/-/jobs/artifacts/bookworm/raw/bookworm/bookworm-rootfs-arm64.tar.gz?job=build+bookworm+image:+%5Barm64,+rootfs%5D -+ compression: gz -+ -+ - boot: -+ method: u-boot -+ commands: nfs -+ timeout: -+ minutes: 10 -+ auto_login: -+ login_prompt: 'login:' -+ username: user -+ password_prompt: 'Password:' -+ password: user -+ login_commands: -+ - sudo su -+ - env -+ - systemctl --failed -+ prompts: -+ - 'user@health(.*)$' -+ - 'root@health(.*)#' -+ -+ - test: -+ timeout: -+ minutes: 1 -+ definitions: -+ - repository: -+ metadata: -+ format: Lava-Test Test Definition 1.0 -+ name: health -+ description: "health check" -+ os: -+ - apertis -+ scope: -+ - functional -+ environment: -+ - lava-test-shell -+ run: -+ steps: -+ - ip a s -+ from: inline -+ name: network -+ path: inline/health.yaml --- -2.44.1 - - -From f851992e8c9758ccd3720b2b0a18a5f6a81bd820 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Tue, 25 Jul 2023 18:35:56 +0200 -Subject: [PATCH 02/54] arm64: dts: rockchip: rk3588-rock5b: add USB-C support - -Add hardware description for the USB-C port in the Radxa Rock 5 Model B. -This describes the OHCI, EHCI and XHCI USB parts, but not yet the -DisplayPort AltMode (bindings are not yet upstream). - -For now the fusb302 node is marked with status "fail", since the board -is usually powered through the USB-C port. Handling of errors can result -in hard resets, which removed the bus power for some time resulting in -a board reset. - -The main problem right now is that devices are supposed to interact with -the power-supply within 5 seconds after the plug event according to the -USB PD specification. This is more or less impossible to achieve when -the kernel is the first software communicating with the power-supply. - -Currently the most likely workaround will be USB-PD handling added to -U-Boot. In that case U-Boot can update the status to "okay". That way -booting a kernel with the updated DT on an old U-Boot avoids a reset -loop. - -Signed-off-by: Sebastian Reichel ---- - .../boot/dts/rockchip/rk3588-rock-5b.dts | 121 ++++++++++++++++++ - 1 file changed, 121 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -index b8e15b76a8a6..0c4359f1b97e 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -@@ -4,6 +4,7 @@ - - #include - #include -+#include - #include "rk3588.dtsi" - - / { -@@ -65,6 +66,15 @@ rfkill { - shutdown-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; - }; - -+ vcc12v_dcin: vcc12v-dcin-regulator { -+ compatible = "regulator-fixed"; -+ regulator-name = "vcc12v_dcin"; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <12000000>; -+ regulator-max-microvolt = <12000000>; -+ }; -+ - vcc3v3_pcie2x1l0: vcc3v3-pcie2x1l0-regulator { - compatible = "regulator-fixed"; - enable-active-high; -@@ -123,6 +133,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { - regulator-boot-on; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; -+ vin-supply = <&vcc12v_dcin>; - }; - - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { -@@ -225,6 +236,67 @@ regulator-state-mem { - }; - }; - -+&i2c4 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c4m1_xfer>; -+ status = "okay"; -+ -+ usbc0: usb-typec@22 { -+ compatible = "fcs,fusb302"; -+ reg = <0x22>; -+ interrupt-parent = <&gpio3>; -+ interrupts = ; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&usbc0_int>; -+ vbus-supply = <&vcc12v_dcin>; -+ /* -+ * When the board is starting to send power-delivery messages -+ * too late (5 seconds according to the specification), the -+ * power-supply reacts with a hard-reset. That removes the -+ * power from VBUS for some time, which resets te whole board. -+ */ -+ status = "fail"; -+ -+ usb_con: connector { -+ compatible = "usb-c-connector"; -+ label = "USB-C"; -+ data-role = "dual"; -+ power-role = "sink"; -+ try-power-role = "sink"; -+ op-sink-microwatt = <1000000>; -+ sink-pdos = -+ , -+ ; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ port@0 { -+ reg = <0>; -+ usbc0_orien_sw: endpoint { -+ remote-endpoint = <&usbdp_phy0_orientation_switch>; -+ }; -+ }; -+ -+ port@1 { -+ reg = <1>; -+ usbc0_role_sw: endpoint { -+ remote-endpoint = <&dwc3_0_role_switch>; -+ }; -+ }; -+ -+ port@2 { -+ reg = <2>; -+ dp_altmode_mux: endpoint { -+ remote-endpoint = <&usbdp_phy0_dp_altmode_mux>; -+ }; -+ }; -+ }; -+ }; -+ }; -+}; -+ - &i2c6 { - status = "okay"; - -@@ -354,6 +426,10 @@ usb { - vcc5v0_host_en: vcc5v0-host-en { - rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; - }; -+ -+ usbc0_int: usbc0-int { -+ rockchip,pins = <3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; - }; - }; - -@@ -747,6 +823,14 @@ &uart2 { - status = "okay"; - }; - -+&u2phy0 { -+ status = "okay"; -+}; -+ -+&u2phy0_otg { -+ status = "okay"; -+}; -+ - &u2phy1 { - status = "okay"; - }; -@@ -778,6 +862,29 @@ &usbdp_phy1 { - status = "okay"; - }; - -+&usbdp_phy0 { -+ mode-switch; -+ orientation-switch; -+ sbu1-dc-gpios = <&gpio4 RK_PA6 GPIO_ACTIVE_HIGH>; -+ sbu2-dc-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; -+ status = "okay"; -+ -+ port { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ usbdp_phy0_orientation_switch: endpoint@0 { -+ reg = <0>; -+ remote-endpoint = <&usbc0_orien_sw>; -+ }; -+ -+ usbdp_phy0_dp_altmode_mux: endpoint@1 { -+ reg = <1>; -+ remote-endpoint = <&dp_altmode_mux>; -+ }; -+ }; -+}; -+ - &usb_host0_ehci { - status = "okay"; - }; -@@ -786,6 +893,20 @@ &usb_host0_ohci { - status = "okay"; - }; - -+&usb_host0_xhci { -+ usb-role-switch; -+ status = "okay"; -+ -+ port { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ dwc3_0_role_switch: endpoint { -+ remote-endpoint = <&usbc0_role_sw>; -+ }; -+ }; -+}; -+ - &usb_host1_ehci { - status = "okay"; - }; --- -2.44.1 - - -From eb006b9c23a873d2d7dbeb1af0c0d9418d35fd31 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Tue, 24 Oct 2023 16:09:35 +0200 -Subject: [PATCH 03/54] math.h: add DIV_ROUND_UP_NO_OVERFLOW - -Add a new DIV_ROUND_UP helper, which cannot overflow when -big numbers are being used. - -Signed-off-by: Sebastian Reichel ---- - include/linux/math.h | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/include/linux/math.h b/include/linux/math.h -index dd4152711de7..f80bfb375ab9 100644 ---- a/include/linux/math.h -+++ b/include/linux/math.h -@@ -36,6 +36,17 @@ - - #define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP - -+/** -+ * DIV_ROUND_UP_NO_OVERFLOW - divide two numbers and always round up -+ * @n: numerator / dividend -+ * @d: denominator / divisor -+ * -+ * This functions does the same as DIV_ROUND_UP, but internally uses a -+ * division and a modulo operation instead of math tricks. This way it -+ * avoids overflowing when handling big numbers. -+ */ -+#define DIV_ROUND_UP_NO_OVERFLOW(n, d) (((n) / (d)) + !!((n) % (d))) -+ - #define DIV_ROUND_DOWN_ULL(ll, d) \ - ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; }) - --- -2.44.1 - - -From bba6ab440970c2b9a69d3b32a16f2680e38ea9e1 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Tue, 24 Oct 2023 16:13:50 +0200 -Subject: [PATCH 04/54] clk: divider: Fix divisor masking on 64 bit platforms - -The clock framework handles clock rates as "unsigned long", so u32 on -32-bit architectures and u64 on 64-bit architectures. - -The current code casts the dividend to u64 on 32-bit to avoid a -potential overflow. For example DIV_ROUND_UP(3000000000, 1500000000) -= (3.0G + 1.5G - 1) / 1.5G = = OVERFLOW / 1.5G, which has been -introduced in commit 9556f9dad8f5 ("clk: divider: handle integer overflow -when dividing large clock rates"). - -On 64 bit platforms this masks the divisor, so that only the lower -32 bit are used. Thus requesting a frequency >= 4.3GHz results -in incorrect values. For example requesting 4300000000 (4.3 GHz) will -effectively request ca. 5 MHz. Requesting clk_round_rate(clk, ULONG_MAX) -is a bit of a special case, since that still returns correct values as -long as the parent clock is below 8.5 GHz. - -Fix this by switching to DIV_ROUND_UP_NO_OVERFLOW, which cannot -overflow. This avoids any requirements on the arguments (except -that divisor should not be 0 obviously). - -Signed-off-by: Sebastian Reichel ---- - drivers/clk/clk-divider.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c -index a2c2b5203b0a..94b4fb66a60f 100644 ---- a/drivers/clk/clk-divider.c -+++ b/drivers/clk/clk-divider.c -@@ -220,7 +220,7 @@ static int _div_round_up(const struct clk_div_table *table, - unsigned long parent_rate, unsigned long rate, - unsigned long flags) - { -- int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); -+ int div = DIV_ROUND_UP_NO_OVERFLOW(parent_rate, rate); - - if (flags & CLK_DIVIDER_POWER_OF_TWO) - div = __roundup_pow_of_two(div); -@@ -237,7 +237,7 @@ static int _div_round_closest(const struct clk_div_table *table, - int up, down; - unsigned long up_rate, down_rate; - -- up = DIV_ROUND_UP_ULL((u64)parent_rate, rate); -+ up = DIV_ROUND_UP_NO_OVERFLOW(parent_rate, rate); - down = parent_rate / rate; - - if (flags & CLK_DIVIDER_POWER_OF_TWO) { -@@ -473,7 +473,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate, - { - unsigned int div, value; - -- div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); -+ div = DIV_ROUND_UP_NO_OVERFLOW(parent_rate, rate); - - if (!_is_valid_div(table, div, flags)) - return -EINVAL; --- -2.44.1 - - -From 37865cfc273efe64b16651ff167566564ca8cd2e Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Tue, 24 Oct 2023 18:09:57 +0200 -Subject: [PATCH 05/54] clk: composite: replace open-coded abs_diff() - -Replace the open coded abs_diff() with the existing helper function. - -Suggested-by: Andy Shevchenko -Signed-off-by: Sebastian Reichel ---- - drivers/clk/clk-composite.c | 6 ++---- - 1 file changed, 2 insertions(+), 4 deletions(-) - -diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c -index 66759fe28fad..478a4e594336 100644 ---- a/drivers/clk/clk-composite.c -+++ b/drivers/clk/clk-composite.c -@@ -6,6 +6,7 @@ - #include - #include - #include -+#include - #include - - static u8 clk_composite_get_parent(struct clk_hw *hw) -@@ -119,10 +120,7 @@ static int clk_composite_determine_rate(struct clk_hw *hw, - if (ret) - continue; - -- if (req->rate >= tmp_req.rate) -- rate_diff = req->rate - tmp_req.rate; -- else -- rate_diff = tmp_req.rate - req->rate; -+ rate_diff = abs_diff(req->rate, tmp_req.rate); - - if (!rate_diff || !req->best_parent_hw - || best_rate_diff > rate_diff) { --- -2.44.1 - - -From 346137db0818fa1d55da82180f40c5986daec9a5 Mon Sep 17 00:00:00 2001 -From: Alexey Charkov -Date: Thu, 29 Feb 2024 23:26:32 +0400 -Subject: [PATCH 06/54] arm64: dts: rockchip: enable built-in thermal - monitoring on RK3588 - -Include thermal zones information in device tree for RK3588 variants. - -This also enables the TSADC controller unconditionally on all boards -to ensure that thermal protections are in place via throttling and -emergency reset, once OPPs are added to enable CPU DVFS. - -The default settings (using CRU as the emergency reset mechanism) -should work on all boards regardless of their wiring, as CRU resets -do not depend on any external components. Boards that have the TSHUT -signal wired to the reset line of the PMIC may opt to switch to GPIO -tshut mode instead (rockchip,hw-tshut-mode = <1>;) - -It seems though that downstream kernels don't use that, even for -those boards where the wiring allows for GPIO based tshut, such as -Radxa Rock 5B [1], [2], [3] - -[1] https://github.com/radxa/kernel/blob/stable-5.10-rock5/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts#L540 -[2] https://github.com/radxa/kernel/blob/stable-5.10-rock5/arch/arm64/boot/dts/rockchip/rk3588s.dtsi#L5433 -[3] https://dl.radxa.com/rock5/5b/docs/hw/radxa_rock_5b_v1423_sch.pdf page 11 (TSADC_SHUT_H) - -Signed-off-by: Alexey Charkov -Link: https://lore.kernel.org/r/20240229-rk-dts-additions-v3-1-6afe8473a631@gmail.com -Signed-off-by: Sebastian Reichel ---- - arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 176 +++++++++++++++++++++- - 1 file changed, 175 insertions(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -index 6ac5ac8b48ab..e2b24d4bfc2e 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - - / { - compatible = "rockchip,rk3588"; -@@ -2385,7 +2386,180 @@ tsadc: tsadc@fec00000 { - pinctrl-1 = <&tsadc_shut>; - pinctrl-names = "gpio", "otpout"; - #thermal-sensor-cells = <1>; -- status = "disabled"; -+ status = "okay"; -+ }; -+ -+ thermal_zones: thermal-zones { -+ /* sensor near the center of the SoC */ -+ package_thermal: package-thermal { -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ thermal-sensors = <&tsadc 0>; -+ -+ trips { -+ package_crit: package-crit { -+ temperature = <115000>; -+ hysteresis = <0>; -+ type = "critical"; -+ }; -+ }; -+ }; -+ -+ /* sensor between A76 cores 0 and 1 */ -+ bigcore0_thermal: bigcore0-thermal { -+ polling-delay-passive = <100>; -+ polling-delay = <0>; -+ thermal-sensors = <&tsadc 1>; -+ -+ trips { -+ /* threshold to start collecting temperature -+ * statistics e.g. with the IPA governor -+ */ -+ bigcore0_alert0: bigcore0-alert0 { -+ temperature = <75000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ /* actual control temperature */ -+ bigcore0_alert1: bigcore0-alert1 { -+ temperature = <85000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ bigcore0_crit: bigcore0-crit { -+ temperature = <115000>; -+ hysteresis = <0>; -+ type = "critical"; -+ }; -+ }; -+ cooling-maps { -+ map0 { -+ trip = <&bigcore0_alert1>; -+ cooling-device = -+ <&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, -+ <&cpu_b1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; -+ }; -+ }; -+ }; -+ -+ /* sensor between A76 cores 2 and 3 */ -+ bigcore2_thermal: bigcore2-thermal { -+ polling-delay-passive = <100>; -+ polling-delay = <0>; -+ thermal-sensors = <&tsadc 2>; -+ -+ trips { -+ /* threshold to start collecting temperature -+ * statistics e.g. with the IPA governor -+ */ -+ bigcore2_alert0: bigcore2-alert0 { -+ temperature = <75000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ /* actual control temperature */ -+ bigcore2_alert1: bigcore2-alert1 { -+ temperature = <85000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ bigcore2_crit: bigcore2-crit { -+ temperature = <115000>; -+ hysteresis = <0>; -+ type = "critical"; -+ }; -+ }; -+ cooling-maps { -+ map0 { -+ trip = <&bigcore2_alert1>; -+ cooling-device = -+ <&cpu_b2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, -+ <&cpu_b3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; -+ }; -+ }; -+ }; -+ -+ /* sensor between the four A55 cores */ -+ little_core_thermal: littlecore-thermal { -+ polling-delay-passive = <100>; -+ polling-delay = <0>; -+ thermal-sensors = <&tsadc 3>; -+ -+ trips { -+ /* threshold to start collecting temperature -+ * statistics e.g. with the IPA governor -+ */ -+ littlecore_alert0: littlecore-alert0 { -+ temperature = <75000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ /* actual control temperature */ -+ littlecore_alert1: littlecore-alert1 { -+ temperature = <85000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ littlecore_crit: littlecore-crit { -+ temperature = <115000>; -+ hysteresis = <0>; -+ type = "critical"; -+ }; -+ }; -+ cooling-maps { -+ map0 { -+ trip = <&littlecore_alert1>; -+ cooling-device = -+ <&cpu_l0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, -+ <&cpu_l1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, -+ <&cpu_l2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, -+ <&cpu_l3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; -+ }; -+ }; -+ }; -+ -+ /* sensor near the PD_CENTER power domain */ -+ center_thermal: center-thermal { -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ thermal-sensors = <&tsadc 4>; -+ -+ trips { -+ center_crit: center-crit { -+ temperature = <115000>; -+ hysteresis = <0>; -+ type = "critical"; -+ }; -+ }; -+ }; -+ -+ gpu_thermal: gpu-thermal { -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ thermal-sensors = <&tsadc 5>; -+ -+ trips { -+ gpu_crit: gpu-crit { -+ temperature = <115000>; -+ hysteresis = <0>; -+ type = "critical"; -+ }; -+ }; -+ }; -+ -+ npu_thermal: npu-thermal { -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ thermal-sensors = <&tsadc 6>; -+ -+ trips { -+ npu_crit: npu-crit { -+ temperature = <115000>; -+ hysteresis = <0>; -+ type = "critical"; -+ }; -+ }; -+ }; - }; - - saradc: adc@fec10000 { --- -2.44.1 - - -From c81266f4e265da4e7a56222b6ea03e1936d11287 Mon Sep 17 00:00:00 2001 -From: Alexey Charkov -Date: Thu, 29 Feb 2024 23:26:33 +0400 -Subject: [PATCH 07/54] arm64: dts: rockchip: enable automatic active cooling - on Rock 5B - -This links the PWM fan on Radxa Rock 5B as an active cooling device -managed automatically by the thermal subsystem, with a target SoC -temperature of 65C and a minimum-spin interval from 55C to 65C to -ensure airflow when the system gets warm - -Signed-off-by: Alexey Charkov -Helped-by: Dragan Simic -Reviewed-by: Dragan Simic -Link: https://lore.kernel.org/r/20240229-rk-dts-additions-v3-2-6afe8473a631@gmail.com -Signed-off-by: Sebastian Reichel ---- - .../boot/dts/rockchip/rk3588-rock-5b.dts | 30 ++++++++++++++++++- - 1 file changed, 29 insertions(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -index 0c4359f1b97e..e18e970393a6 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -@@ -53,7 +53,7 @@ led_rgb_b { - - fan: pwm-fan { - compatible = "pwm-fan"; -- cooling-levels = <0 95 145 195 255>; -+ cooling-levels = <0 120 150 180 210 240 255>; - fan-supply = <&vcc5v0_sys>; - pwms = <&pwm1 0 50000 0>; - #cooling-cells = <2>; -@@ -351,6 +351,34 @@ i2s0_8ch_p0_0: endpoint { - }; - }; - -+&package_thermal { -+ polling-delay = <1000>; -+ -+ trips { -+ package_fan0: package-fan0 { -+ hysteresis = <2000>; -+ temperature = <55000>; -+ type = "active"; -+ }; -+ package_fan1: package-fan1 { -+ hysteresis = <2000>; -+ temperature = <65000>; -+ type = "active"; -+ }; -+ }; -+ -+ cooling-maps { -+ map1 { -+ cooling-device = <&fan THERMAL_NO_LIMIT 1>; -+ trip = <&package_fan0>; -+ }; -+ map2 { -+ cooling-device = <&fan 2 THERMAL_NO_LIMIT>; -+ trip = <&package_fan1>; -+ }; -+ }; -+}; -+ - &pcie2x1l0 { - pinctrl-names = "default"; - pinctrl-0 = <&pcie2_0_rst>; --- -2.44.1 - - -From e6fac8dde2ec69f02435b3c5ccd68ea1355bac05 Mon Sep 17 00:00:00 2001 -From: Alexey Charkov -Date: Thu, 29 Feb 2024 23:26:34 +0400 -Subject: [PATCH 08/54] arm64: dts: rockchip: Add CPU/memory regulator coupling - for RK3588 - -RK3588 chips allow for their CPU cores to be powered by a different -supply vs. their corresponding memory interfaces, and two of the -boards currently upstream do that (EVB1 and QuartzPro64). - -The voltage of the memory interface though has to match that of the -CPU cores that use it, which downstream kernels achieve by the means -of a custom cpufreq driver which adjusts both at the same time. - -It seems that regulator coupling is a more appropriate generic -interface for it, so this patch introduces coupling to affected -device trees to ensure that memory interface voltage is also updated -whenever cpufreq switches between CPU OPPs. - -Note that other boards, such as Radxa Rock 5B, define both the CPU -and memory interface regulators as aliases to the same DT node, so -this doesn't apply there. - -Signed-off-by: Alexey Charkov -Link: https://lore.kernel.org/r/20240229-rk-dts-additions-v3-3-6afe8473a631@gmail.com -Signed-off-by: Sebastian Reichel ---- - arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts | 12 ++++++++++++ - arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts | 12 ++++++++++++ - 2 files changed, 24 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -index 7be2190244ba..7c5826da452e 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -@@ -878,6 +878,8 @@ regulators { - vdd_cpu_big1_s0: dcdc-reg1 { - regulator-always-on; - regulator-boot-on; -+ regulator-coupled-with = <&vdd_cpu_big1_mem_s0>; -+ regulator-coupled-max-spread = <10000>; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <1050000>; - regulator-ramp-delay = <12500>; -@@ -890,6 +892,8 @@ regulator-state-mem { - vdd_cpu_big0_s0: dcdc-reg2 { - regulator-always-on; - regulator-boot-on; -+ regulator-coupled-with = <&vdd_cpu_big0_mem_s0>; -+ regulator-coupled-max-spread = <10000>; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <1050000>; - regulator-ramp-delay = <12500>; -@@ -902,6 +906,8 @@ regulator-state-mem { - vdd_cpu_lit_s0: dcdc-reg3 { - regulator-always-on; - regulator-boot-on; -+ regulator-coupled-with = <&vdd_cpu_lit_mem_s0>; -+ regulator-coupled-max-spread = <10000>; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <950000>; - regulator-ramp-delay = <12500>; -@@ -926,6 +932,8 @@ regulator-state-mem { - vdd_cpu_big1_mem_s0: dcdc-reg5 { - regulator-always-on; - regulator-boot-on; -+ regulator-coupled-with = <&vdd_cpu_big1_s0>; -+ regulator-coupled-max-spread = <10000>; - regulator-min-microvolt = <675000>; - regulator-max-microvolt = <1050000>; - regulator-ramp-delay = <12500>; -@@ -939,6 +947,8 @@ regulator-state-mem { - vdd_cpu_big0_mem_s0: dcdc-reg6 { - regulator-always-on; - regulator-boot-on; -+ regulator-coupled-with = <&vdd_cpu_big0_s0>; -+ regulator-coupled-max-spread = <10000>; - regulator-min-microvolt = <675000>; - regulator-max-microvolt = <1050000>; - regulator-ramp-delay = <12500>; -@@ -963,6 +973,8 @@ regulator-state-mem { - vdd_cpu_lit_mem_s0: dcdc-reg8 { - regulator-always-on; - regulator-boot-on; -+ regulator-coupled-with = <&vdd_cpu_lit_s0>; -+ regulator-coupled-max-spread = <10000>; - regulator-min-microvolt = <675000>; - regulator-max-microvolt = <950000>; - regulator-ramp-delay = <12500>; -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts b/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts -index b4f22d95ac0e..baeb08d665c7 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts -@@ -832,6 +832,8 @@ vdd_cpu_big1_s0: dcdc-reg1 { - regulator-name = "vdd_cpu_big1_s0"; - regulator-always-on; - regulator-boot-on; -+ regulator-coupled-with = <&vdd_cpu_big1_mem_s0>; -+ regulator-coupled-max-spread = <10000>; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <1050000>; - regulator-ramp-delay = <12500>; -@@ -845,6 +847,8 @@ vdd_cpu_big0_s0: dcdc-reg2 { - regulator-name = "vdd_cpu_big0_s0"; - regulator-always-on; - regulator-boot-on; -+ regulator-coupled-with = <&vdd_cpu_big0_mem_s0>; -+ regulator-coupled-max-spread = <10000>; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <1050000>; - regulator-ramp-delay = <12500>; -@@ -858,6 +862,8 @@ vdd_cpu_lit_s0: dcdc-reg3 { - regulator-name = "vdd_cpu_lit_s0"; - regulator-always-on; - regulator-boot-on; -+ regulator-coupled-with = <&vdd_cpu_lit_mem_s0>; -+ regulator-coupled-max-spread = <10000>; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <950000>; - regulator-ramp-delay = <12500>; -@@ -884,6 +890,8 @@ vdd_cpu_big1_mem_s0: dcdc-reg5 { - regulator-name = "vdd_cpu_big1_mem_s0"; - regulator-always-on; - regulator-boot-on; -+ regulator-coupled-with = <&vdd_cpu_big1_s0>; -+ regulator-coupled-max-spread = <10000>; - regulator-min-microvolt = <675000>; - regulator-max-microvolt = <1050000>; - regulator-ramp-delay = <12500>; -@@ -898,6 +906,8 @@ vdd_cpu_big0_mem_s0: dcdc-reg6 { - regulator-name = "vdd_cpu_big0_mem_s0"; - regulator-always-on; - regulator-boot-on; -+ regulator-coupled-with = <&vdd_cpu_big0_s0>; -+ regulator-coupled-max-spread = <10000>; - regulator-min-microvolt = <675000>; - regulator-max-microvolt = <1050000>; - regulator-ramp-delay = <12500>; -@@ -924,6 +934,8 @@ vdd_cpu_lit_mem_s0: dcdc-reg8 { - regulator-name = "vdd_cpu_lit_mem_s0"; - regulator-always-on; - regulator-boot-on; -+ regulator-coupled-with = <&vdd_cpu_lit_s0>; -+ regulator-coupled-max-spread = <10000>; - regulator-min-microvolt = <675000>; - regulator-max-microvolt = <950000>; - regulator-ramp-delay = <12500>; --- -2.44.1 - - -From bfc28c478d96020a987e19b393762b92c5a62896 Mon Sep 17 00:00:00 2001 -From: Alexey Charkov -Date: Thu, 29 Feb 2024 23:26:35 +0400 -Subject: [PATCH 09/54] arm64: dts: rockchip: Add OPP data for CPU cores on - RK3588 - -By default the CPUs on RK3588 start up in a conservative performance -mode. Add frequency and voltage mappings to the device tree to enable -dynamic scaling via cpufreq. - -OPP values are adapted from Radxa's downstream kernel for Rock 5B [1], -stripping them down to the minimum frequency and voltage combinations -as expected by the generic upstream cpufreq-dt driver, and also dropping -those OPPs that don't differ in voltage but only in frequency (keeping -the top frequency OPP in each case). - -Note that this patch ignores voltage scaling for the CPU memory -interface which the downstream kernel does through a custom cpufreq -driver, and which is why the downstream version has two sets of voltage -values for each OPP (the second one being meant for the memory -interface supply regulator). This is done instead via regulator -coupling between CPU and memory interface supplies on affected boards. - -This has been tested on Rock 5B with u-boot 2023.11 compiled from -Collabora's integration tree [2] with binary bl31 and appears to be -stable both under active cooling and passive cooling (with throttling) - -[1] https://github.com/radxa/kernel/blob/stable-5.10-rock5/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -[2] https://gitlab.collabora.com/hardware-enablement/rockchip-3588/u-boot - -Signed-off-by: Alexey Charkov -Link: https://lore.kernel.org/r/20240229-rk-dts-additions-v3-4-6afe8473a631@gmail.com -Signed-off-by: Sebastian Reichel ---- - arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 122 ++++++++++++++++++++++ - 1 file changed, 122 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -index e2b24d4bfc2e..5104eebd563a 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -@@ -97,6 +97,7 @@ cpu_l0: cpu@0 { - clocks = <&scmi_clk SCMI_CLK_CPUL>; - assigned-clocks = <&scmi_clk SCMI_CLK_CPUL>; - assigned-clock-rates = <816000000>; -+ operating-points-v2 = <&cluster0_opp_table>; - cpu-idle-states = <&CPU_SLEEP>; - i-cache-size = <32768>; - i-cache-line-size = <64>; -@@ -116,6 +117,7 @@ cpu_l1: cpu@100 { - enable-method = "psci"; - capacity-dmips-mhz = <530>; - clocks = <&scmi_clk SCMI_CLK_CPUL>; -+ operating-points-v2 = <&cluster0_opp_table>; - cpu-idle-states = <&CPU_SLEEP>; - i-cache-size = <32768>; - i-cache-line-size = <64>; -@@ -135,6 +137,7 @@ cpu_l2: cpu@200 { - enable-method = "psci"; - capacity-dmips-mhz = <530>; - clocks = <&scmi_clk SCMI_CLK_CPUL>; -+ operating-points-v2 = <&cluster0_opp_table>; - cpu-idle-states = <&CPU_SLEEP>; - i-cache-size = <32768>; - i-cache-line-size = <64>; -@@ -154,6 +157,7 @@ cpu_l3: cpu@300 { - enable-method = "psci"; - capacity-dmips-mhz = <530>; - clocks = <&scmi_clk SCMI_CLK_CPUL>; -+ operating-points-v2 = <&cluster0_opp_table>; - cpu-idle-states = <&CPU_SLEEP>; - i-cache-size = <32768>; - i-cache-line-size = <64>; -@@ -175,6 +179,7 @@ cpu_b0: cpu@400 { - clocks = <&scmi_clk SCMI_CLK_CPUB01>; - assigned-clocks = <&scmi_clk SCMI_CLK_CPUB01>; - assigned-clock-rates = <816000000>; -+ operating-points-v2 = <&cluster1_opp_table>; - cpu-idle-states = <&CPU_SLEEP>; - i-cache-size = <65536>; - i-cache-line-size = <64>; -@@ -194,6 +199,7 @@ cpu_b1: cpu@500 { - enable-method = "psci"; - capacity-dmips-mhz = <1024>; - clocks = <&scmi_clk SCMI_CLK_CPUB01>; -+ operating-points-v2 = <&cluster1_opp_table>; - cpu-idle-states = <&CPU_SLEEP>; - i-cache-size = <65536>; - i-cache-line-size = <64>; -@@ -215,6 +221,7 @@ cpu_b2: cpu@600 { - clocks = <&scmi_clk SCMI_CLK_CPUB23>; - assigned-clocks = <&scmi_clk SCMI_CLK_CPUB23>; - assigned-clock-rates = <816000000>; -+ operating-points-v2 = <&cluster2_opp_table>; - cpu-idle-states = <&CPU_SLEEP>; - i-cache-size = <65536>; - i-cache-line-size = <64>; -@@ -234,6 +241,7 @@ cpu_b3: cpu@700 { - enable-method = "psci"; - capacity-dmips-mhz = <1024>; - clocks = <&scmi_clk SCMI_CLK_CPUB23>; -+ operating-points-v2 = <&cluster2_opp_table>; - cpu-idle-states = <&CPU_SLEEP>; - i-cache-size = <65536>; - i-cache-line-size = <64>; -@@ -348,6 +356,120 @@ l3_cache: l3-cache { - }; - }; - -+ cluster0_opp_table: opp-table-cluster0 { -+ compatible = "operating-points-v2"; -+ opp-shared; -+ -+ opp-1008000000 { -+ opp-hz = /bits/ 64 <1008000000>; -+ opp-microvolt = <675000 675000 950000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1200000000 { -+ opp-hz = /bits/ 64 <1200000000>; -+ opp-microvolt = <712500 712500 950000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1416000000 { -+ opp-hz = /bits/ 64 <1416000000>; -+ opp-microvolt = <762500 762500 950000>; -+ clock-latency-ns = <40000>; -+ opp-suspend; -+ }; -+ opp-1608000000 { -+ opp-hz = /bits/ 64 <1608000000>; -+ opp-microvolt = <850000 850000 950000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1800000000 { -+ opp-hz = /bits/ 64 <1800000000>; -+ opp-microvolt = <950000 950000 950000>; -+ clock-latency-ns = <40000>; -+ }; -+ }; -+ -+ cluster1_opp_table: opp-table-cluster1 { -+ compatible = "operating-points-v2"; -+ opp-shared; -+ -+ opp-1200000000 { -+ opp-hz = /bits/ 64 <1200000000>; -+ opp-microvolt = <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1416000000 { -+ opp-hz = /bits/ 64 <1416000000>; -+ opp-microvolt = <725000 725000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1608000000 { -+ opp-hz = /bits/ 64 <1608000000>; -+ opp-microvolt = <762500 762500 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1800000000 { -+ opp-hz = /bits/ 64 <1800000000>; -+ opp-microvolt = <850000 850000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2016000000 { -+ opp-hz = /bits/ 64 <2016000000>; -+ opp-microvolt = <925000 925000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2208000000 { -+ opp-hz = /bits/ 64 <2208000000>; -+ opp-microvolt = <987500 987500 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2400000000 { -+ opp-hz = /bits/ 64 <2400000000>; -+ opp-microvolt = <1000000 1000000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ }; -+ -+ cluster2_opp_table: opp-table-cluster2 { -+ compatible = "operating-points-v2"; -+ opp-shared; -+ -+ opp-1200000000 { -+ opp-hz = /bits/ 64 <1200000000>; -+ opp-microvolt = <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1416000000 { -+ opp-hz = /bits/ 64 <1416000000>; -+ opp-microvolt = <725000 725000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1608000000 { -+ opp-hz = /bits/ 64 <1608000000>; -+ opp-microvolt = <762500 762500 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1800000000 { -+ opp-hz = /bits/ 64 <1800000000>; -+ opp-microvolt = <850000 850000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2016000000 { -+ opp-hz = /bits/ 64 <2016000000>; -+ opp-microvolt = <925000 925000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2208000000 { -+ opp-hz = /bits/ 64 <2208000000>; -+ opp-microvolt = <987500 987500 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2400000000 { -+ opp-hz = /bits/ 64 <2400000000>; -+ opp-microvolt = <1000000 1000000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ }; -+ - display_subsystem: display-subsystem { - compatible = "rockchip,display-subsystem"; - ports = <&vop_out>; --- -2.44.1 - - -From d4c81e098ca05e31b6b6e3faae8bd278faa41b6c Mon Sep 17 00:00:00 2001 -From: Alexey Charkov -Date: Thu, 29 Feb 2024 23:26:36 +0400 -Subject: [PATCH 10/54] arm64: dts: rockchip: Add further granularity in RK3588 - CPU OPPs - -This introduces additional OPPs that share the same voltage as -another OPP already present in the .dtsi but with lower frequency. - -The idea is to try and limit system throughput more gradually upon -reaching the throttling condition for workloads that are close to -sustainable power already, thus avoiding needless performance loss. - -My limited synthetic benchmarking [1] showed around 3.8% performance -benefit when these are in place, other things equal (not meant to -be comprehensive). Though dmesg complains about these OPPs being -'inefficient': - -[ 9.009561] cpu cpu0: EM: OPP:816000 is inefficient -[ 9.009580] cpu cpu0: EM: OPP:600000 is inefficient -[ 9.009591] cpu cpu0: EM: OPP:408000 is inefficient -[ 9.011370] cpu cpu4: EM: OPP:2352000 is inefficient -[ 9.011379] cpu cpu4: EM: OPP:2304000 is inefficient -[ 9.011384] cpu cpu4: EM: OPP:2256000 is inefficient -[ 9.011389] cpu cpu4: EM: OPP:600000 is inefficient -[ 9.011393] cpu cpu4: EM: OPP:408000 is inefficient -[ 9.012978] cpu cpu6: EM: OPP:2352000 is inefficient -[ 9.012987] cpu cpu6: EM: OPP:2304000 is inefficient -[ 9.012992] cpu cpu6: EM: OPP:2256000 is inefficient -[ 9.012996] cpu cpu6: EM: OPP:600000 is inefficient -[ 9.013000] cpu cpu6: EM: OPP:408000 is inefficient - -[1] https://lore.kernel.org/linux-rockchip/CABjd4YxqarUCbZ-a2XLe3TWJ-qjphGkyq=wDnctnEhdoSdPPpw@mail.gmail.com/T/#me92aa0ee25e6eeb1d1501ce85f5af4e58b3b13c5 - -Signed-off-by: Alexey Charkov -Link: https://lore.kernel.org/r/20240229-rk-dts-additions-v3-5-6afe8473a631@gmail.com -Signed-off-by: Sebastian Reichel ---- - arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 87 +++++++++++++++++++++++ - 1 file changed, 87 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -index 5104eebd563a..ae3ccafe6871 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -@@ -360,6 +360,21 @@ cluster0_opp_table: opp-table-cluster0 { - compatible = "operating-points-v2"; - opp-shared; - -+ opp-408000000 { -+ opp-hz = /bits/ 64 <408000000>; -+ opp-microvolt = <675000 675000 950000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-600000000 { -+ opp-hz = /bits/ 64 <600000000>; -+ opp-microvolt = <675000 675000 950000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-816000000 { -+ opp-hz = /bits/ 64 <816000000>; -+ opp-microvolt = <675000 675000 950000>; -+ clock-latency-ns = <40000>; -+ }; - opp-1008000000 { - opp-hz = /bits/ 64 <1008000000>; - opp-microvolt = <675000 675000 950000>; -@@ -392,6 +407,27 @@ cluster1_opp_table: opp-table-cluster1 { - compatible = "operating-points-v2"; - opp-shared; - -+ opp-408000000 { -+ opp-hz = /bits/ 64 <408000000>; -+ opp-microvolt = <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ opp-suspend; -+ }; -+ opp-600000000 { -+ opp-hz = /bits/ 64 <600000000>; -+ opp-microvolt = <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-816000000 { -+ opp-hz = /bits/ 64 <816000000>; -+ opp-microvolt = <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1008000000 { -+ opp-hz = /bits/ 64 <1008000000>; -+ opp-microvolt = <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; - opp-1200000000 { - opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <675000 675000 1000000>; -@@ -422,6 +458,21 @@ opp-2208000000 { - opp-microvolt = <987500 987500 1000000>; - clock-latency-ns = <40000>; - }; -+ opp-2256000000 { -+ opp-hz = /bits/ 64 <2256000000>; -+ opp-microvolt = <1000000 1000000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2304000000 { -+ opp-hz = /bits/ 64 <2304000000>; -+ opp-microvolt = <1000000 1000000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2352000000 { -+ opp-hz = /bits/ 64 <2352000000>; -+ opp-microvolt = <1000000 1000000 1000000>; -+ clock-latency-ns = <40000>; -+ }; - opp-2400000000 { - opp-hz = /bits/ 64 <2400000000>; - opp-microvolt = <1000000 1000000 1000000>; -@@ -433,6 +484,27 @@ cluster2_opp_table: opp-table-cluster2 { - compatible = "operating-points-v2"; - opp-shared; - -+ opp-408000000 { -+ opp-hz = /bits/ 64 <408000000>; -+ opp-microvolt = <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ opp-suspend; -+ }; -+ opp-600000000 { -+ opp-hz = /bits/ 64 <600000000>; -+ opp-microvolt = <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-816000000 { -+ opp-hz = /bits/ 64 <816000000>; -+ opp-microvolt = <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1008000000 { -+ opp-hz = /bits/ 64 <1008000000>; -+ opp-microvolt = <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; - opp-1200000000 { - opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <675000 675000 1000000>; -@@ -463,6 +535,21 @@ opp-2208000000 { - opp-microvolt = <987500 987500 1000000>; - clock-latency-ns = <40000>; - }; -+ opp-2256000000 { -+ opp-hz = /bits/ 64 <2256000000>; -+ opp-microvolt = <1000000 1000000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2304000000 { -+ opp-hz = /bits/ 64 <2304000000>; -+ opp-microvolt = <1000000 1000000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2352000000 { -+ opp-hz = /bits/ 64 <2352000000>; -+ opp-microvolt = <1000000 1000000 1000000>; -+ clock-latency-ns = <40000>; -+ }; - opp-2400000000 { - opp-hz = /bits/ 64 <2400000000>; - opp-microvolt = <1000000 1000000 1000000>; --- -2.44.1 - - -From b81afac501f04f1137009cec98a1447321b84467 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Fri, 14 Jul 2023 17:38:24 +0200 -Subject: [PATCH 11/54] [BROKEN] arm64: dts: rockchip: rk3588-evb1: add PCIe2 - WLAN controller - -Enable PCIe bus used by on-board PCIe Broadcom WLAN controller. - -The WLAN controller is not detected. There are two reasons for -that. - -First of all it is necessary to keep the HYM8563 clock enabled, but it -is disabled because the kernel does not know about the dependency and -disables any clocks it deems unused. - -Apart from that it looks like the controller needs a long time to be -properly initialized. So detection only works when rescanning the bus -some time after boot. This still needs to be investigated. - -Both of these issues should be fixable by implementing a pwrseq driver -once the following series has landed: - -https://lore.kernel.org/all/20240104130123.37115-1-brgl@bgdev.pl/ - -In addition to the above issues, the mainline brcmfmac driver does -not yet support the chip version used by AP6275P. - -Signed-off-by: Sebastian Reichel ---- - .../boot/dts/rockchip/rk3588-evb1-v10.dts | 61 +++++++++++++++++++ - 1 file changed, 61 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -index 7c5826da452e..65e16410084a 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -@@ -120,6 +120,15 @@ backlight: backlight { - pwms = <&pwm2 0 25000 0>; - }; - -+ wlan-rfkill { -+ compatible = "rfkill-gpio"; -+ label = "rfkill-pcie-wlan"; -+ radio-type = "wlan"; -+ shutdown-gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_LOW>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&wifi_pwren>; -+ }; -+ - pcie20_avdd0v85: pcie20-avdd0v85-regulator { - compatible = "regulator-fixed"; - regulator-name = "pcie20_avdd0v85"; -@@ -237,12 +246,36 @@ vcc5v0_usb: vcc5v0-usb-regulator { - regulator-max-microvolt = <5000000>; - vin-supply = <&vcc5v0_usbdcin>; - }; -+ -+ vccio_wl: vccio-wl { -+ compatible = "regulator-fixed"; -+ regulator-name = "wlan-vddio"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vcc_1v8_s0>; -+ }; -+ -+ vcc3v3_pciewl_vbat: vcc3v3-pciewl-vbat { -+ compatible = "regulator-fixed"; -+ regulator-name = "wlan-vbat"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vcc_3v3_s0>; -+ }; - }; - - &combphy0_ps { - status = "okay"; - }; - -+&combphy1_ps { -+ status = "okay"; -+}; -+ - &combphy2_psu { - status = "okay"; - }; -@@ -408,6 +441,12 @@ rgmii_phy: ethernet-phy@1 { - }; - }; - -+&pcie2x1l0 { -+ reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>; -+ pinctrl-0 = <&pcie2_0_rst>, <&pcie2_0_wake>, <&pcie2_0_clkreq>, <&wifi_host_wake_irq>; -+ status = "okay"; -+}; -+ - &pcie2x1l1 { - reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; -@@ -462,6 +501,18 @@ hym8563_int: hym8563-int { - }; - - pcie2 { -+ pcie2_0_rst: pcie2-0-rst { -+ rockchip,pins = <4 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ -+ pcie2_0_wake: pcie2-0-wake { -+ rockchip,pins = <4 RK_PA4 4 &pcfg_pull_none>; -+ }; -+ -+ pcie2_0_clkreq: pcie2-0-clkreq { -+ rockchip,pins = <4 RK_PA3 4 &pcfg_pull_none>; -+ }; -+ - pcie2_1_rst: pcie2-1-rst { - rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; - }; -@@ -492,6 +543,16 @@ usbc0_int: usbc0-int { - rockchip,pins = <3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>; - }; - }; -+ -+ wlan { -+ wifi_host_wake_irq: wifi-host-wake-irq { -+ rockchip,pins = <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_down>; -+ }; -+ -+ wifi_pwren: wifi-pwren { -+ rockchip,pins = <3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>; -+ }; -+ }; - }; - - &pwm2 { --- -2.44.1 - - -From 9a4e298de029f488c6857b23eb98370dd861b6c7 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Mon, 11 Mar 2024 18:05:34 +0100 -Subject: [PATCH 12/54] clk: rockchip: rk3588: drop unused code - -All clocks are registered early using CLK_OF_DECLARE(), which marks -the DT node as processed. For the processed DT node the probe routine -is never called. Thus this whole code is never executed. This could -be "fixed" by using CLK_OF_DECLARE_DRIVER, which avoids marking the -DT node as processed. But then the probe routine would re-register -all the clocks by calling rk3588_clk_init() again. - -Signed-off-by: Sebastian Reichel ---- - drivers/clk/rockchip/clk-rk3588.c | 40 ------------------------------- - 1 file changed, 40 deletions(-) - -diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c -index b30279a96dc8..74051277ecea 100644 ---- a/drivers/clk/rockchip/clk-rk3588.c -+++ b/drivers/clk/rockchip/clk-rk3588.c -@@ -2502,43 +2502,3 @@ static void __init rk3588_clk_init(struct device_node *np) - } - - CLK_OF_DECLARE(rk3588_cru, "rockchip,rk3588-cru", rk3588_clk_init); -- --struct clk_rk3588_inits { -- void (*inits)(struct device_node *np); --}; -- --static const struct clk_rk3588_inits clk_3588_cru_init = { -- .inits = rk3588_clk_init, --}; -- --static const struct of_device_id clk_rk3588_match_table[] = { -- { -- .compatible = "rockchip,rk3588-cru", -- .data = &clk_3588_cru_init, -- }, -- { } --}; -- --static int __init clk_rk3588_probe(struct platform_device *pdev) --{ -- const struct clk_rk3588_inits *init_data; -- struct device *dev = &pdev->dev; -- -- init_data = device_get_match_data(dev); -- if (!init_data) -- return -EINVAL; -- -- if (init_data->inits) -- init_data->inits(dev->of_node); -- -- return 0; --} -- --static struct platform_driver clk_rk3588_driver = { -- .driver = { -- .name = "clk-rk3588", -- .of_match_table = clk_rk3588_match_table, -- .suppress_bind_attrs = true, -- }, --}; --builtin_platform_driver_probe(clk_rk3588_driver, clk_rk3588_probe); --- -2.44.1 - - -From 5b5631ef482995c737a805d126344e23b8d30c3e Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Fri, 8 Mar 2024 23:19:55 +0100 -Subject: [PATCH 13/54] clk: rockchip: handle missing clocks with -EPROBE_DEFER - -In the future some clocks will be registered using CLK_OF_DECLARE -and some are registered later from the driver probe routine. Any -clock handled by the probe routine should return -EPROBE_DEFER -until that routine has been called. - -Signed-off-by: Sebastian Reichel ---- - drivers/clk/rockchip/clk.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c -index 73d2cbdc716b..31b7cc243d82 100644 ---- a/drivers/clk/rockchip/clk.c -+++ b/drivers/clk/rockchip/clk.c -@@ -376,7 +376,7 @@ struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np, - goto err_free; - - for (i = 0; i < nr_clks; ++i) -- clk_table[i] = ERR_PTR(-ENOENT); -+ clk_table[i] = ERR_PTR(-EPROBE_DEFER); - - ctx->reg_base = base; - ctx->clk_data.clks = clk_table; --- -2.44.1 - - -From b7d54daa05c7ff7777eb6ed11de732e681ba3786 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Tue, 12 Mar 2024 16:12:18 +0100 -Subject: [PATCH 14/54] clk: rockchip: rk3588: register GATE_LINK later - -The proper GATE_LINK implementation will use runtime PM to handle the -linked gate clocks, which requires device context. Currently all clocks -are registered early via CLK_OF_DECLARE, which is before the kernel -knows about devices. - -Moving the full clocks registration to the probe routine does not work, -since the clocks needed for timers must be registered early. - -To work around this issue, most of the clock tree is registered early, -but GATE_LINK clocks are handled in the probe routine. Since the resets -are not needed early either, they have also been moved to the probe -routine. - -Signed-off-by: Sebastian Reichel ---- - drivers/clk/rockchip/clk-rk3588.c | 64 +++++++++++++++++++++++++++---- - 1 file changed, 56 insertions(+), 8 deletions(-) - -diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c -index 74051277ecea..29f31a5526fa 100644 ---- a/drivers/clk/rockchip/clk-rk3588.c -+++ b/drivers/clk/rockchip/clk-rk3588.c -@@ -266,6 +266,8 @@ static struct rockchip_pll_rate_table rk3588_pll_rates[] = { - }, \ - } - -+static struct rockchip_clk_provider *early_ctx; -+ - static struct rockchip_cpuclk_rate_table rk3588_cpub0clk_rates[] __initdata = { - RK3588_CPUB01CLK_RATE(2496000000, 1), - RK3588_CPUB01CLK_RATE(2400000000, 1), -@@ -694,7 +696,7 @@ static struct rockchip_pll_clock rk3588_pll_clks[] __initdata = { - RK3588_MODE_CON0, 10, 15, 0, rk3588_pll_rates), - }; - --static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { -+static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = { - /* - * CRU Clock-Architecture - */ -@@ -2428,7 +2430,9 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { - RK3588_CLKGATE_CON(68), 5, GFLAGS), - GATE(ACLK_AV1, "aclk_av1", "aclk_av1_pre", 0, - RK3588_CLKGATE_CON(68), 2, GFLAGS), -+}; - -+static struct rockchip_clk_branch rk3588_clk_branches[] = { - GATE_LINK(ACLK_ISP1_PRE, "aclk_isp1_pre", "aclk_isp1_root", ACLK_VI_ROOT, 0, RK3588_CLKGATE_CON(26), 6, GFLAGS), - GATE_LINK(HCLK_ISP1_PRE, "hclk_isp1_pre", "hclk_isp1_root", HCLK_VI_ROOT, 0, RK3588_CLKGATE_CON(26), 8, GFLAGS), - GATE_LINK(HCLK_NVM, "hclk_nvm", "hclk_nvm_root", ACLK_NVM_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(31), 2, GFLAGS), -@@ -2453,14 +2457,18 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { - GATE_LINK(PCLK_VO1GRF, "pclk_vo1grf", "pclk_vo1_root", HCLK_VO1, CLK_IGNORE_UNUSED, RK3588_CLKGATE_CON(59), 12, GFLAGS), - }; - --static void __init rk3588_clk_init(struct device_node *np) -+static void __init rk3588_clk_early_init(struct device_node *np) - { - struct rockchip_clk_provider *ctx; -- unsigned long clk_nr_clks; -+ unsigned long clk_nr_clks, max_clk_id1, max_clk_id2; - void __iomem *reg_base; - -- clk_nr_clks = rockchip_clk_find_max_clk_id(rk3588_clk_branches, -- ARRAY_SIZE(rk3588_clk_branches)) + 1; -+ max_clk_id1 = rockchip_clk_find_max_clk_id(rk3588_clk_branches, -+ ARRAY_SIZE(rk3588_clk_branches)); -+ max_clk_id2 = rockchip_clk_find_max_clk_id(rk3588_early_clk_branches, -+ ARRAY_SIZE(rk3588_early_clk_branches)); -+ clk_nr_clks = max(max_clk_id1, max_clk_id2) + 1; -+ - reg_base = of_iomap(np, 0); - if (!reg_base) { - pr_err("%s: could not map cru region\n", __func__); -@@ -2473,6 +2481,7 @@ static void __init rk3588_clk_init(struct device_node *np) - iounmap(reg_base); - return; - } -+ early_ctx = ctx; - - rockchip_clk_register_plls(ctx, rk3588_pll_clks, - ARRAY_SIZE(rk3588_pll_clks), -@@ -2491,14 +2500,53 @@ static void __init rk3588_clk_init(struct device_node *np) - &rk3588_cpub1clk_data, rk3588_cpub1clk_rates, - ARRAY_SIZE(rk3588_cpub1clk_rates)); - -+ rockchip_clk_register_branches(ctx, rk3588_early_clk_branches, -+ ARRAY_SIZE(rk3588_early_clk_branches)); -+ -+ rockchip_clk_of_add_provider(np, ctx); -+} -+CLK_OF_DECLARE_DRIVER(rk3588_cru, "rockchip,rk3588-cru", rk3588_clk_early_init); -+ -+static int clk_rk3588_probe(struct platform_device *pdev) -+{ -+ struct rockchip_clk_provider *ctx = early_ctx; -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ - rockchip_clk_register_branches(ctx, rk3588_clk_branches, - ARRAY_SIZE(rk3588_clk_branches)); - -- rk3588_rst_init(np, reg_base); -- -+ rk3588_rst_init(np, ctx->reg_base); - rockchip_register_restart_notifier(ctx, RK3588_GLB_SRST_FST, NULL); - -+ /* -+ * Re-add clock provider, so that the newly added clocks are also -+ * re-parented and get their defaults configured. -+ */ -+ of_clk_del_provider(np); - rockchip_clk_of_add_provider(np, ctx); -+ -+ return 0; - } - --CLK_OF_DECLARE(rk3588_cru, "rockchip,rk3588-cru", rk3588_clk_init); -+static const struct of_device_id clk_rk3588_match_table[] = { -+ { -+ .compatible = "rockchip,rk3588-cru", -+ }, -+ { } -+}; -+ -+static struct platform_driver clk_rk3588_driver = { -+ .probe = clk_rk3588_probe, -+ .driver = { -+ .name = "clk-rk3588", -+ .of_match_table = clk_rk3588_match_table, -+ .suppress_bind_attrs = true, -+ }, -+}; -+ -+static int __init rockchip_clk_rk3588_drv_register(void) -+{ -+ return platform_driver_register(&clk_rk3588_driver); -+} -+core_initcall(rockchip_clk_rk3588_drv_register); --- -2.44.1 - - -From 94082226ef32d0e97dc188cd9a065de6c55e8c77 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Mon, 25 Mar 2024 19:29:22 +0100 -Subject: [PATCH 15/54] clk: rockchip: expose rockchip_clk_set_lookup - -Move rockchip_clk_add_lookup to clk.h, so that it can be used -by sub-devices with their own driver. These might also have to -do a lookup, so rename the function to rockchip_clk_set_lookup -and add a matching rockchip_clk_add_lookup. - -Signed-off-by: Sebastian Reichel ---- - drivers/clk/rockchip/clk.c | 14 ++++---------- - drivers/clk/rockchip/clk.h | 12 ++++++++++++ - 2 files changed, 16 insertions(+), 10 deletions(-) - -diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c -index 31b7cc243d82..ef2408f10f39 100644 ---- a/drivers/clk/rockchip/clk.c -+++ b/drivers/clk/rockchip/clk.c -@@ -197,12 +197,6 @@ static void rockchip_fractional_approximation(struct clk_hw *hw, - clk_fractional_divider_general_approximation(hw, rate, parent_rate, m, n); - } - --static void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx, -- struct clk *clk, unsigned int id) --{ -- ctx->clk_data.clks[id] = clk; --} -- - static struct clk *rockchip_clk_register_frac_branch( - struct rockchip_clk_provider *ctx, const char *name, - const char *const *parent_names, u8 num_parents, -@@ -292,7 +286,7 @@ static struct clk *rockchip_clk_register_frac_branch( - return mux_clk; - } - -- rockchip_clk_add_lookup(ctx, mux_clk, child->id); -+ rockchip_clk_set_lookup(ctx, mux_clk, child->id); - - /* notifier on the fraction divider to catch rate changes */ - if (frac->mux_frac_idx >= 0) { -@@ -424,7 +418,7 @@ void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx, - continue; - } - -- rockchip_clk_add_lookup(ctx, clk, list->id); -+ rockchip_clk_set_lookup(ctx, clk, list->id); - } - } - EXPORT_SYMBOL_GPL(rockchip_clk_register_plls); -@@ -585,7 +579,7 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, - continue; - } - -- rockchip_clk_add_lookup(ctx, clk, list->id); -+ rockchip_clk_set_lookup(ctx, clk, list->id); - } - } - EXPORT_SYMBOL_GPL(rockchip_clk_register_branches); -@@ -609,7 +603,7 @@ void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx, - return; - } - -- rockchip_clk_add_lookup(ctx, clk, lookup_id); -+ rockchip_clk_set_lookup(ctx, clk, lookup_id); - } - EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk); - -diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h -index fd3b476dedda..e39392e1c2a2 100644 ---- a/drivers/clk/rockchip/clk.h -+++ b/drivers/clk/rockchip/clk.h -@@ -969,6 +969,18 @@ struct rockchip_clk_branch { - #define SGRF_GATE(_id, cname, pname) \ - FACTOR(_id, cname, pname, 0, 1, 1) - -+static inline struct clk *rockchip_clk_get_lookup(struct rockchip_clk_provider *ctx, -+ unsigned int id) -+{ -+ return ctx->clk_data.clks[id]; -+} -+ -+static inline void rockchip_clk_set_lookup(struct rockchip_clk_provider *ctx, -+ struct clk *clk, unsigned int id) -+{ -+ ctx->clk_data.clks[id] = clk; -+} -+ - struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np, - void __iomem *base, unsigned long nr_clks); - void rockchip_clk_of_add_provider(struct device_node *np, --- -2.44.1 - - -From 8af78be9475200087bbedcc6565ae5e50490901b Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Mon, 25 Mar 2024 19:31:59 +0100 -Subject: [PATCH 16/54] clk: rockchip: fix error for unknown clocks - -There is a clk == NULL check after the switch to check for -unsupported clk types. Since clk is re-assigned in a loop, -this check is useless right now for anything but the first -round. Let's fix this up by assigning clk = NULL in the -loop before the switch statement. - -Signed-off-by: Sebastian Reichel ---- - drivers/clk/rockchip/clk.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c -index ef2408f10f39..e150bc1fc319 100644 ---- a/drivers/clk/rockchip/clk.c -+++ b/drivers/clk/rockchip/clk.c -@@ -444,12 +444,13 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, - struct rockchip_clk_branch *list, - unsigned int nr_clk) - { -- struct clk *clk = NULL; -+ struct clk *clk; - unsigned int idx; - unsigned long flags; - - for (idx = 0; idx < nr_clk; idx++, list++) { - flags = list->flags; -+ clk = NULL; - - /* catch simple muxes */ - switch (list->branch_type) { --- -2.44.1 - - -From 75751a4bf52c74c6c742f0ed404307d1a894c623 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Mon, 25 Mar 2024 19:42:07 +0100 -Subject: [PATCH 17/54] clk: rockchip: implement linked gate clock support - -Recent Rockchip SoCs have a new hardware block called Native Interface -Unit (NIU), which gates clocks to devices behind them. These clock -gates will only have a running output clock when all of the following -conditions are met: - -1. the parent clock is enabled -2. the enable bit is set correctly -3. the linked clock is enabled - -To handle them this code registers them as a normal gate type clock, -which takes care of condition 1 + 2. The linked clock is handled by -using runtime PM clocks. Handling it via runtime PM requires setting -up a struct device for each of these clocks with a driver attached -to use the correct runtime PM operations. Thus the complete handling -of these clocks has been moved into its own driver. - -Signed-off-by: Sebastian Reichel ---- - drivers/clk/rockchip/Makefile | 1 + - drivers/clk/rockchip/clk-rk3588.c | 23 +------ - drivers/clk/rockchip/clk.c | 52 ++++++++++++++++ - drivers/clk/rockchip/clk.h | 25 ++++++++ - drivers/clk/rockchip/gate-link.c | 99 +++++++++++++++++++++++++++++++ - 5 files changed, 179 insertions(+), 21 deletions(-) - create mode 100644 drivers/clk/rockchip/gate-link.c - -diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile -index 36894f6a7022..179be95c6ffb 100644 ---- a/drivers/clk/rockchip/Makefile -+++ b/drivers/clk/rockchip/Makefile -@@ -13,6 +13,7 @@ clk-rockchip-y += clk-inverter.o - clk-rockchip-y += clk-mmc-phase.o - clk-rockchip-y += clk-muxgrf.o - clk-rockchip-y += clk-ddr.o -+clk-rockchip-y += gate-link.o - clk-rockchip-$(CONFIG_RESET_CONTROLLER) += softrst.o - - obj-$(CONFIG_CLK_PX30) += clk-px30.o -diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c -index 29f31a5526fa..1bf84ac44e85 100644 ---- a/drivers/clk/rockchip/clk-rk3588.c -+++ b/drivers/clk/rockchip/clk-rk3588.c -@@ -12,25 +12,6 @@ - #include - #include "clk.h" - --/* -- * Recent Rockchip SoCs have a new hardware block called Native Interface -- * Unit (NIU), which gates clocks to devices behind them. These effectively -- * need two parent clocks. -- * -- * Downstream enables the linked clock via runtime PM whenever the gate is -- * enabled. This implementation uses separate clock nodes for each of the -- * linked gate clocks, which leaks parts of the clock tree into DT. -- * -- * The GATE_LINK macro instead takes the second parent via 'linkname', but -- * ignores the information. Once the clock framework is ready to handle it, the -- * information should be passed on here. But since these clocks are required to -- * access multiple relevant IP blocks, such as PCIe or USB, we mark all linked -- * clocks critical until a better solution is available. This will waste some -- * power, but avoids leaking implementation details into DT or hanging the -- * system. -- */ --#define GATE_LINK(_id, cname, pname, linkedclk, f, o, b, gf) \ -- GATE(_id, cname, pname, f, o, b, gf) - #define RK3588_LINKED_CLK CLK_IS_CRITICAL - - -@@ -2513,8 +2494,8 @@ static int clk_rk3588_probe(struct platform_device *pdev) - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - -- rockchip_clk_register_branches(ctx, rk3588_clk_branches, -- ARRAY_SIZE(rk3588_clk_branches)); -+ rockchip_clk_register_late_branches(dev, ctx, rk3588_clk_branches, -+ ARRAY_SIZE(rk3588_clk_branches)); - - rk3588_rst_init(np, ctx->reg_base); - rockchip_register_restart_notifier(ctx, RK3588_GLB_SRST_FST, NULL); -diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c -index e150bc1fc319..f5f11cc60046 100644 ---- a/drivers/clk/rockchip/clk.c -+++ b/drivers/clk/rockchip/clk.c -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -440,6 +441,29 @@ unsigned long rockchip_clk_find_max_clk_id(struct rockchip_clk_branch *list, - } - EXPORT_SYMBOL_GPL(rockchip_clk_find_max_clk_id); - -+static struct platform_device *rockchip_clk_register_gate_link( -+ struct device *parent_dev, -+ struct rockchip_clk_provider *ctx, -+ struct rockchip_clk_branch *clkbr) -+{ -+ struct rockchip_gate_link_platdata gate_link_pdata = { -+ .ctx = ctx, -+ .clkbr = clkbr, -+ }; -+ -+ struct platform_device_info pdevinfo = { -+ .parent = parent_dev, -+ .name = "rockchip-gate-link-clk", -+ .id = clkbr->id, -+ .fwnode = dev_fwnode(parent_dev), -+ .of_node_reused = true, -+ .data = &gate_link_pdata, -+ .size_data = sizeof(gate_link_pdata), -+ }; -+ -+ return platform_device_register_full(&pdevinfo); -+} -+ - void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, - struct rockchip_clk_branch *list, - unsigned int nr_clk) -@@ -565,6 +589,9 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, - list->div_width, list->div_flags, - ctx->reg_base, &ctx->lock); - break; -+ case branch_linked_gate: -+ /* must be registered late, fall-through for error message */ -+ break; - } - - /* none of the cases above matched */ -@@ -585,6 +612,31 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, - } - EXPORT_SYMBOL_GPL(rockchip_clk_register_branches); - -+void rockchip_clk_register_late_branches(struct device *dev, -+ struct rockchip_clk_provider *ctx, -+ struct rockchip_clk_branch *list, -+ unsigned int nr_clk) -+{ -+ unsigned int idx; -+ -+ for (idx = 0; idx < nr_clk; idx++, list++) { -+ struct platform_device *pdev = NULL; -+ -+ switch (list->branch_type) { -+ case branch_linked_gate: -+ pdev = rockchip_clk_register_gate_link(dev, ctx, list); -+ break; -+ default: -+ dev_err(dev, "unknown clock type %d\n", list->branch_type); -+ break; -+ } -+ -+ if (!pdev) -+ dev_err(dev, "failed to register device for clock %s\n", list->name); -+ } -+} -+EXPORT_SYMBOL_GPL(rockchip_clk_register_late_branches); -+ - void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx, - unsigned int lookup_id, - const char *name, const char *const *parent_names, -diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h -index e39392e1c2a2..15aa2fd5265b 100644 ---- a/drivers/clk/rockchip/clk.h -+++ b/drivers/clk/rockchip/clk.h -@@ -517,6 +517,7 @@ enum rockchip_clk_branch_type { - branch_divider, - branch_fraction_divider, - branch_gate, -+ branch_linked_gate, - branch_mmc, - branch_inverter, - branch_factor, -@@ -544,6 +545,7 @@ struct rockchip_clk_branch { - int gate_offset; - u8 gate_shift; - u8 gate_flags; -+ unsigned int linked_clk_id; - struct rockchip_clk_branch *child; - }; - -@@ -842,6 +844,20 @@ struct rockchip_clk_branch { - .gate_flags = gf, \ - } - -+#define GATE_LINK(_id, cname, pname, linkedclk, f, o, b, gf) \ -+ { \ -+ .id = _id, \ -+ .branch_type = branch_linked_gate, \ -+ .name = cname, \ -+ .parent_names = (const char *[]){ pname }, \ -+ .linked_clk_id = linkedclk, \ -+ .num_parents = 1, \ -+ .flags = f, \ -+ .gate_offset = o, \ -+ .gate_shift = b, \ -+ .gate_flags = gf, \ -+ } -+ - #define MMC(_id, cname, pname, offset, shift) \ - { \ - .id = _id, \ -@@ -981,6 +997,11 @@ static inline void rockchip_clk_set_lookup(struct rockchip_clk_provider *ctx, - ctx->clk_data.clks[id] = clk; - } - -+struct rockchip_gate_link_platdata { -+ struct rockchip_clk_provider *ctx; -+ struct rockchip_clk_branch *clkbr; -+}; -+ - struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np, - void __iomem *base, unsigned long nr_clks); - void rockchip_clk_of_add_provider(struct device_node *np, -@@ -990,6 +1011,10 @@ unsigned long rockchip_clk_find_max_clk_id(struct rockchip_clk_branch *list, - void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, - struct rockchip_clk_branch *list, - unsigned int nr_clk); -+void rockchip_clk_register_late_branches(struct device *dev, -+ struct rockchip_clk_provider *ctx, -+ struct rockchip_clk_branch *list, -+ unsigned int nr_clk); - void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx, - struct rockchip_pll_clock *pll_list, - unsigned int nr_pll, int grf_lock_offset); -diff --git a/drivers/clk/rockchip/gate-link.c b/drivers/clk/rockchip/gate-link.c -new file mode 100644 -index 000000000000..47b6f3e7a6a2 ---- /dev/null -+++ b/drivers/clk/rockchip/gate-link.c -@@ -0,0 +1,99 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2024 Collabora Ltd. -+ * Author: Sebastian Reichel -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "clk.h" -+ -+static int rk_clk_gate_link_register(struct device *dev, -+ struct rockchip_clk_provider *ctx, -+ struct rockchip_clk_branch *clkbr) -+{ -+ unsigned long flags = clkbr->flags | CLK_SET_RATE_PARENT; -+ struct clk *clk; -+ -+ clk = clk_register_gate(dev, clkbr->name, clkbr->parent_names[0], -+ flags, ctx->reg_base + clkbr->gate_offset, -+ clkbr->gate_shift, clkbr->gate_flags, -+ &ctx->lock); -+ -+ if (IS_ERR(clk)) -+ return PTR_ERR(clk); -+ -+ rockchip_clk_set_lookup(ctx, clk, clkbr->id); -+ return 0; -+} -+ -+static int rk_clk_gate_link_probe(struct platform_device *pdev) -+{ -+ struct rockchip_gate_link_platdata *pdata; -+ struct device *dev = &pdev->dev; -+ struct clk *linked_clk; -+ int ret; -+ -+ pdata = dev_get_platdata(dev); -+ if (!pdata) -+ return dev_err_probe(dev, -ENODEV, "missing platform data"); -+ -+ ret = devm_pm_runtime_enable(dev); -+ if (ret) -+ return ret; -+ -+ ret = devm_pm_clk_create(dev); -+ if (ret) -+ return ret; -+ -+ linked_clk = rockchip_clk_get_lookup(pdata->ctx, pdata->clkbr->linked_clk_id); -+ ret = pm_clk_add_clk(dev, linked_clk); -+ if (ret) -+ return ret; -+ -+ ret = rk_clk_gate_link_register(dev, pdata->ctx, pdata->clkbr); -+ if (ret) -+ goto err; -+ -+ return 0; -+ -+err: -+ pm_clk_remove_clk(dev, linked_clk); -+ return ret; -+} -+ -+static void rk_clk_gate_link_remove(struct platform_device *pdev) -+{ -+ struct rockchip_gate_link_platdata *pdata; -+ struct device *dev = &pdev->dev; -+ struct clk *clk, *linked_clk; -+ -+ pdata = dev_get_platdata(dev); -+ clk = rockchip_clk_get_lookup(pdata->ctx, pdata->clkbr->id); -+ linked_clk = rockchip_clk_get_lookup(pdata->ctx, pdata->clkbr->linked_clk_id); -+ rockchip_clk_set_lookup(pdata->ctx, ERR_PTR(-ENODEV), pdata->clkbr->id); -+ clk_unregister_gate(clk); -+ pm_clk_remove_clk(dev, linked_clk); -+} -+ -+static const struct dev_pm_ops rk_clk_gate_link_pm_ops = { -+ SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) -+}; -+ -+struct platform_driver rk_clk_gate_link_driver = { -+ .probe = rk_clk_gate_link_probe, -+ .remove_new = rk_clk_gate_link_remove, -+ .driver = { -+ .name = "rockchip-gate-link-clk", -+ .pm = &rk_clk_gate_link_pm_ops, -+ }, -+}; -+ -+static int __init rk_clk_gate_link_drv_register(void) -+{ -+ return platform_driver_register(&rk_clk_gate_link_driver); -+} -+core_initcall(rk_clk_gate_link_drv_register); --- -2.44.1 - - -From 97f9b5fa575c07a80527abdf17bf9153d258df23 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Fri, 8 Mar 2024 23:32:05 +0100 -Subject: [PATCH 18/54] clk: rockchip: rk3588: drop RK3588_LINKED_CLK - -With the proper GATE_LINK support, we no longer need to keep the -linked clocks always on. Thus it's time to drop the CLK_IS_CRITICAL -flag for them. - -Signed-off-by: Sebastian Reichel ---- - drivers/clk/rockchip/clk-rk3588.c | 27 ++++++++++++--------------- - 1 file changed, 12 insertions(+), 15 deletions(-) - -diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c -index 1bf84ac44e85..42579b6f74b4 100644 ---- a/drivers/clk/rockchip/clk-rk3588.c -+++ b/drivers/clk/rockchip/clk-rk3588.c -@@ -12,9 +12,6 @@ - #include - #include "clk.h" - --#define RK3588_LINKED_CLK CLK_IS_CRITICAL -- -- - #define RK3588_GRF_SOC_STATUS0 0x600 - #define RK3588_PHYREF_ALT_GATE 0xc38 - -@@ -1439,7 +1436,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = { - COMPOSITE_NODIV(HCLK_NVM_ROOT, "hclk_nvm_root", mux_200m_100m_50m_24m_p, 0, - RK3588_CLKSEL_CON(77), 0, 2, MFLAGS, - RK3588_CLKGATE_CON(31), 0, GFLAGS), -- COMPOSITE(ACLK_NVM_ROOT, "aclk_nvm_root", gpll_cpll_p, RK3588_LINKED_CLK, -+ COMPOSITE(ACLK_NVM_ROOT, "aclk_nvm_root", gpll_cpll_p, 0, - RK3588_CLKSEL_CON(77), 7, 1, MFLAGS, 2, 5, DFLAGS, - RK3588_CLKGATE_CON(31), 1, GFLAGS), - GATE(ACLK_EMMC, "aclk_emmc", "aclk_nvm_root", 0, -@@ -1668,13 +1665,13 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = { - RK3588_CLKGATE_CON(42), 9, GFLAGS), - - /* vdpu */ -- COMPOSITE(ACLK_VDPU_ROOT, "aclk_vdpu_root", gpll_cpll_aupll_p, RK3588_LINKED_CLK, -+ COMPOSITE(ACLK_VDPU_ROOT, "aclk_vdpu_root", gpll_cpll_aupll_p, 0, - RK3588_CLKSEL_CON(98), 5, 2, MFLAGS, 0, 5, DFLAGS, - RK3588_CLKGATE_CON(44), 0, GFLAGS), - COMPOSITE_NODIV(ACLK_VDPU_LOW_ROOT, "aclk_vdpu_low_root", mux_400m_200m_100m_24m_p, 0, - RK3588_CLKSEL_CON(98), 7, 2, MFLAGS, - RK3588_CLKGATE_CON(44), 1, GFLAGS), -- COMPOSITE_NODIV(HCLK_VDPU_ROOT, "hclk_vdpu_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK, -+ COMPOSITE_NODIV(HCLK_VDPU_ROOT, "hclk_vdpu_root", mux_200m_100m_50m_24m_p, 0, - RK3588_CLKSEL_CON(98), 9, 2, MFLAGS, - RK3588_CLKGATE_CON(44), 2, GFLAGS), - COMPOSITE(ACLK_JPEG_DECODER_ROOT, "aclk_jpeg_decoder_root", gpll_cpll_aupll_spll_p, 0, -@@ -1725,9 +1722,9 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = { - COMPOSITE(ACLK_RKVENC0_ROOT, "aclk_rkvenc0_root", gpll_cpll_npll_p, 0, - RK3588_CLKSEL_CON(102), 7, 2, MFLAGS, 2, 5, DFLAGS, - RK3588_CLKGATE_CON(47), 1, GFLAGS), -- GATE(HCLK_RKVENC0, "hclk_rkvenc0", "hclk_rkvenc0_root", RK3588_LINKED_CLK, -+ GATE(HCLK_RKVENC0, "hclk_rkvenc0", "hclk_rkvenc0_root", 0, - RK3588_CLKGATE_CON(47), 4, GFLAGS), -- GATE(ACLK_RKVENC0, "aclk_rkvenc0", "aclk_rkvenc0_root", RK3588_LINKED_CLK, -+ GATE(ACLK_RKVENC0, "aclk_rkvenc0", "aclk_rkvenc0_root", 0, - RK3588_CLKGATE_CON(47), 5, GFLAGS), - COMPOSITE(CLK_RKVENC0_CORE, "clk_rkvenc0_core", gpll_cpll_aupll_npll_p, 0, - RK3588_CLKSEL_CON(102), 14, 2, MFLAGS, 9, 5, DFLAGS, -@@ -1737,10 +1734,10 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = { - RK3588_CLKGATE_CON(48), 6, GFLAGS), - - /* vi */ -- COMPOSITE(ACLK_VI_ROOT, "aclk_vi_root", gpll_cpll_npll_aupll_spll_p, RK3588_LINKED_CLK, -+ COMPOSITE(ACLK_VI_ROOT, "aclk_vi_root", gpll_cpll_npll_aupll_spll_p, 0, - RK3588_CLKSEL_CON(106), 5, 3, MFLAGS, 0, 5, DFLAGS, - RK3588_CLKGATE_CON(49), 0, GFLAGS), -- COMPOSITE_NODIV(HCLK_VI_ROOT, "hclk_vi_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK, -+ COMPOSITE_NODIV(HCLK_VI_ROOT, "hclk_vi_root", mux_200m_100m_50m_24m_p, 0, - RK3588_CLKSEL_CON(106), 8, 2, MFLAGS, - RK3588_CLKGATE_CON(49), 1, GFLAGS), - COMPOSITE_NODIV(PCLK_VI_ROOT, "pclk_vi_root", mux_100m_50m_24m_p, 0, -@@ -1910,10 +1907,10 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = { - COMPOSITE(ACLK_VOP_ROOT, "aclk_vop_root", gpll_cpll_dmyaupll_npll_spll_p, 0, - RK3588_CLKSEL_CON(110), 5, 3, MFLAGS, 0, 5, DFLAGS, - RK3588_CLKGATE_CON(52), 0, GFLAGS), -- COMPOSITE_NODIV(ACLK_VOP_LOW_ROOT, "aclk_vop_low_root", mux_400m_200m_100m_24m_p, RK3588_LINKED_CLK, -+ COMPOSITE_NODIV(ACLK_VOP_LOW_ROOT, "aclk_vop_low_root", mux_400m_200m_100m_24m_p, 0, - RK3588_CLKSEL_CON(110), 8, 2, MFLAGS, - RK3588_CLKGATE_CON(52), 1, GFLAGS), -- COMPOSITE_NODIV(HCLK_VOP_ROOT, "hclk_vop_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK, -+ COMPOSITE_NODIV(HCLK_VOP_ROOT, "hclk_vop_root", mux_200m_100m_50m_24m_p, 0, - RK3588_CLKSEL_CON(110), 10, 2, MFLAGS, - RK3588_CLKGATE_CON(52), 2, GFLAGS), - COMPOSITE_NODIV(PCLK_VOP_ROOT, "pclk_vop_root", mux_100m_50m_24m_p, 0, -@@ -2416,7 +2413,7 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = { - static struct rockchip_clk_branch rk3588_clk_branches[] = { - GATE_LINK(ACLK_ISP1_PRE, "aclk_isp1_pre", "aclk_isp1_root", ACLK_VI_ROOT, 0, RK3588_CLKGATE_CON(26), 6, GFLAGS), - GATE_LINK(HCLK_ISP1_PRE, "hclk_isp1_pre", "hclk_isp1_root", HCLK_VI_ROOT, 0, RK3588_CLKGATE_CON(26), 8, GFLAGS), -- GATE_LINK(HCLK_NVM, "hclk_nvm", "hclk_nvm_root", ACLK_NVM_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(31), 2, GFLAGS), -+ GATE_LINK(HCLK_NVM, "hclk_nvm", "hclk_nvm_root", ACLK_NVM_ROOT, 0, RK3588_CLKGATE_CON(31), 2, GFLAGS), - GATE_LINK(ACLK_USB, "aclk_usb", "aclk_usb_root", ACLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(42), 2, GFLAGS), - GATE_LINK(HCLK_USB, "hclk_usb", "hclk_usb_root", HCLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(42), 3, GFLAGS), - GATE_LINK(ACLK_JPEG_DECODER_PRE, "aclk_jpeg_decoder_pre", "aclk_jpeg_decoder_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(44), 7, GFLAGS), -@@ -2428,9 +2425,9 @@ static struct rockchip_clk_branch rk3588_clk_branches[] = { - GATE_LINK(HCLK_RKVDEC1_PRE, "hclk_rkvdec1_pre", "hclk_rkvdec1_root", HCLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(41), 4, GFLAGS), - GATE_LINK(ACLK_RKVDEC1_PRE, "aclk_rkvdec1_pre", "aclk_rkvdec1_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(41), 5, GFLAGS), - GATE_LINK(ACLK_HDCP0_PRE, "aclk_hdcp0_pre", "aclk_vo0_root", ACLK_VOP_LOW_ROOT, 0, RK3588_CLKGATE_CON(55), 9, GFLAGS), -- GATE_LINK(HCLK_VO0, "hclk_vo0", "hclk_vo0_root", HCLK_VOP_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(55), 5, GFLAGS), -+ GATE_LINK(HCLK_VO0, "hclk_vo0", "hclk_vo0_root", HCLK_VOP_ROOT, 0, RK3588_CLKGATE_CON(55), 5, GFLAGS), - GATE_LINK(ACLK_HDCP1_PRE, "aclk_hdcp1_pre", "aclk_hdcp1_root", ACLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(59), 6, GFLAGS), -- GATE_LINK(HCLK_VO1, "hclk_vo1", "hclk_vo1_root", HCLK_VO1USB_TOP_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(59), 9, GFLAGS), -+ GATE_LINK(HCLK_VO1, "hclk_vo1", "hclk_vo1_root", HCLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(59), 9, GFLAGS), - GATE_LINK(ACLK_AV1_PRE, "aclk_av1_pre", "aclk_av1_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(68), 1, GFLAGS), - GATE_LINK(PCLK_AV1_PRE, "pclk_av1_pre", "pclk_av1_root", HCLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(68), 4, GFLAGS), - GATE_LINK(HCLK_SDIO_PRE, "hclk_sdio_pre", "hclk_sdio_root", HCLK_NVM, 0, RK3588_CLKGATE_CON(75), 1, GFLAGS), --- -2.44.1 - - -From 70a3aa25bcb8fa0c5f63d613ee562d6b50e43843 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Tue, 2 Jan 2024 09:35:43 +0100 -Subject: [PATCH 19/54] arm64: dts: rockchip: rk3588-evb1: add bluetooth rfkill - -Add rfkill support for bluetooth. Bluetooth support itself is still -missing, but this ensures bluetooth can be powered off properly. - -Signed-off-by: Sebastian Reichel ---- - arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -index 65e16410084a..761e0108285d 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -@@ -120,6 +120,15 @@ backlight: backlight { - pwms = <&pwm2 0 25000 0>; - }; - -+ bluetooth-rfkill { -+ compatible = "rfkill-gpio"; -+ label = "rfkill-bluetooth"; -+ radio-type = "bluetooth"; -+ shutdown-gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_LOW>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&bluetooth_pwren>; -+ }; -+ - wlan-rfkill { - compatible = "rfkill-gpio"; - label = "rfkill-pcie-wlan"; -@@ -481,6 +490,12 @@ speaker_amplifier_en: speaker-amplifier-en { - }; - }; - -+ bluetooth { -+ bluetooth_pwren: bluetooth-pwren { -+ rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>; -+ }; -+ }; -+ - rtl8111 { - rtl8111_isolate: rtl8111-isolate { - rockchip,pins = <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>; --- -2.44.1 - - -From 40e20352a122c1fe1e35c3140034fedd5129199d Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Tue, 2 Jan 2024 09:39:11 +0100 -Subject: [PATCH 20/54] arm64: dts: rockchip: rk3588-evb1: improve PCIe - ethernet pin muxing - -Also describe clkreq and wake signals in the PCIe pinmux used -by the onboard LAN card. - -Signed-off-by: Sebastian Reichel ---- - arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -index 761e0108285d..dd2fb2515900 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -@@ -459,7 +459,7 @@ &pcie2x1l0 { - &pcie2x1l1 { - reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; -- pinctrl-0 = <&pcie2_1_rst>, <&rtl8111_isolate>; -+ pinctrl-0 = <&pcie2_1_rst>, <&pcie2_1_wake>, <&pcie2_1_clkreq>, <&rtl8111_isolate>; - status = "okay"; - }; - -@@ -531,6 +531,14 @@ pcie2_0_clkreq: pcie2-0-clkreq { - pcie2_1_rst: pcie2-1-rst { - rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; - }; -+ -+ pcie2_1_wake: pcie2-1-wake { -+ rockchip,pins = <4 RK_PA1 4 &pcfg_pull_none>; -+ }; -+ -+ pcie2_1_clkreq: pcie2-1-clkreq { -+ rockchip,pins = <4 RK_PA0 4 &pcfg_pull_none>; -+ }; - }; - - pcie3 { --- -2.44.1 - - -From 42bfdc60fdfa7d27754aaa9116def24f018ca4a9 Mon Sep 17 00:00:00 2001 -From: "Carsten Haitzler (Rasterman)" -Date: Tue, 6 Feb 2024 10:12:54 +0000 -Subject: [PATCH 21/54] arm64: dts: rockchip: Slow down EMMC a bit to keep IO - stable - -This drops to hs200 mode and 150Mhz as this is actually stable across -eMMC modules. There exist some that are incompatible at higher rates -with the rk3588 and to avoid your filesystem corrupting due to IO -errors, be more conservative and reduce the max. speed. - -Signed-off-by: Carsten Haitzler -Signed-off-by: Sebastian Reichel ---- - arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts | 4 ++-- - 1 file changed, 2 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 e18e970393a6..f311c8f9d437 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -@@ -475,8 +475,8 @@ &sdhci { - no-sdio; - no-sd; - non-removable; -- mmc-hs400-1_8v; -- mmc-hs400-enhanced-strobe; -+ max-frequency = <150000000>; -+ mmc-hs200-1_8v; - status = "okay"; - }; - --- -2.44.1 - - -From bddd59567560d46a3d9363db6692f3232199bd20 Mon Sep 17 00:00:00 2001 -From: Shreeya Patel -Date: Wed, 20 Dec 2023 18:30:13 +0530 -Subject: [PATCH 22/54] dt-bindings: media: Document bindings for HDMI RX - Controller - -Document bindings for the Synopsys DesignWare HDMI RX Controller. - -Reviewed-by: Dmitry Osipenko -Signed-off-by: Shreeya Patel ---- - .../bindings/media/snps,dw-hdmi-rx.yaml | 130 ++++++++++++++++++ - 1 file changed, 130 insertions(+) - create mode 100644 Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml - -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..903aa62d33ef ---- /dev/null -+++ b/Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml -@@ -0,0 +1,130 @@ -+# SPDX-License-Identifier: (GPL-3.0 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 -+ -+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: rst_a -+ - const: rst_p -+ - const: rst_ref -+ - const: rst_biu -+ -+ pinctrl-names: -+ const: default -+ -+ memory-region: -+ maxItems: 1 -+ -+ hdmirx-5v-detection-gpios: -+ description: GPIO specifier for 5V detection. -+ maxItems: 1 -+ -+ rockchip,grf: -+ $ref: /schemas/types.yaml#/definitions/phandle -+ description: -+ The phandle of the syscon node for the GRF register. -+ -+ rockchip,vo1_grf: -+ $ref: /schemas/types.yaml#/definitions/phandle -+ description: -+ The phandle of the syscon node for the VO1 GRF register. -+ -+required: -+ - compatible -+ - reg -+ - interrupts -+ - interrupt-names -+ - clocks -+ - clock-names -+ - power-domains -+ - resets -+ - pinctrl-0 -+ - pinctrl-names -+ - hdmirx-5v-detection-gpios -+ -+additionalProperties: false -+ -+examples: -+ - | -+ #include -+ #include -+ #include -+ #include -+ #include -+ #include -+ #include -+ hdmirx_ctrler: hdmirx-controller@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 = "rst_a", "rst_p", "rst_ref", "rst_biu"; -+ pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_5v_detection>; -+ pinctrl-names = "default"; -+ memory-region = <&hdmirx_cma>; -+ hdmirx-5v-detection-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_LOW>; -+ }; --- -2.44.1 - - -From 8353d22573a2b462a538a4b8e826f9fd9b4cdbae Mon Sep 17 00:00:00 2001 -From: Shreeya Patel -Date: Wed, 20 Dec 2023 16:50:14 +0530 -Subject: [PATCH 23/54] arm64: dts: rockchip: Add device tree support for HDMI - RX Controller - -Add device tree support for Synopsys DesignWare HDMI RX -Controller. - -Signed-off-by: Dingxian Wen -Co-developed-by: Shreeya Patel -Reviewed-by: Dmitry Osipenko -Tested-by: Dmitry Osipenko -Signed-off-by: Shreeya Patel ---- - .../boot/dts/rockchip/rk3588-pinctrl.dtsi | 41 +++++++++++++++ - .../boot/dts/rockchip/rk3588-rock-5b.dts | 18 +++++++ - arch/arm64/boot/dts/rockchip/rk3588.dtsi | 50 +++++++++++++++++++ - 3 files changed, 109 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-pinctrl.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-pinctrl.dtsi -index 244c66faa161..e5f3d0acbd55 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-pinctrl.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-pinctrl.dtsi -@@ -169,6 +169,47 @@ hdmim0_tx1_sda: hdmim0-tx1-sda { - /* hdmim0_tx1_sda */ - <2 RK_PB4 4 &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 = -+ /* hdmim1_rx_cec */ -+ <3 RK_PD1 5 &pcfg_pull_none>; -+ }; -+ -+ /omit-if-no-ref/ -+ hdmim1_rx_hpdin: hdmim1-rx-hpdin { -+ rockchip,pins = -+ /* hdmim1_rx_hpdin */ -+ <3 RK_PD4 5 &pcfg_pull_none>; -+ }; -+ -+ /omit-if-no-ref/ -+ hdmim1_rx_scl: hdmim1-rx-scl { -+ rockchip,pins = -+ /* hdmim1_rx_scl */ -+ <3 RK_PD2 5 &pcfg_pull_none>; -+ }; -+ -+ /omit-if-no-ref/ -+ hdmim1_rx_sda: hdmim1-rx-sda { -+ rockchip,pins = -+ /* hdmim1_rx_sda */ -+ <3 RK_PD3 5 &pcfg_pull_none>; -+ }; - }; - - i2c0 { -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -index f311c8f9d437..f013d7841e89 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -@@ -196,6 +196,18 @@ &gpu { - status = "okay"; - }; - -+&hdmirx_cma { -+ status = "okay"; -+}; -+ -+&hdmirx_ctrler { -+ status = "okay"; -+ hdmirx-5v-detection-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_LOW>; -+ pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_5v_detection>; -+ pinctrl-names = "default"; -+ memory-region = <&hdmirx_cma>; -+}; -+ - &i2c0 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c0m2_xfer>; -@@ -408,6 +420,12 @@ &pcie3x4 { - }; - - &pinctrl { -+ hdmirx { -+ hdmirx_5v_detection: hdmirx-5v-detection { -+ rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ - hym8563 { - hym8563_int: hym8563-int { - rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; -diff --git a/arch/arm64/boot/dts/rockchip/rk3588.dtsi b/arch/arm64/boot/dts/rockchip/rk3588.dtsi -index 5984016b5f96..534c42262c73 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588.dtsi -@@ -7,6 +7,24 @@ - #include "rk3588-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. -+ */ -+ hdmirx_cma: hdmirx_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 +153,38 @@ i2s10_8ch: i2s@fde00000 { - status = "disabled"; - }; - -+ hdmirx_ctrler: hdmirx-controller@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 = "rst_a", "rst_p", "rst_ref", "rst_biu"; -+ pinctrl-0 = <&hdmim1_rx>; -+ pinctrl-names = "default"; -+ status = "disabled"; -+ }; -+ - pcie3x4: pcie@fe150000 { - compatible = "rockchip,rk3588-pcie", "rockchip,rk3568-pcie"; - #address-cells = <3>; --- -2.44.1 - - -From 820dbb912706cdfc378cd4e344a92aca94a6dc57 Mon Sep 17 00:00:00 2001 -From: Shreeya Patel -Date: Wed, 20 Dec 2023 16:52:01 +0530 -Subject: [PATCH 24/54] 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. - -Signed-off-by: Dingxian Wen -Co-developed-by: Shreeya Patel -Reviewed-by: Dmitry Osipenko -Tested-by: Dmitry Osipenko -Signed-off-by: Shreeya Patel ---- - drivers/media/platform/Kconfig | 1 + - drivers/media/platform/Makefile | 1 + - drivers/media/platform/synopsys/Kconfig | 3 + - drivers/media/platform/synopsys/Makefile | 2 + - .../media/platform/synopsys/hdmirx/Kconfig | 18 + - .../media/platform/synopsys/hdmirx/Makefile | 4 + - .../platform/synopsys/hdmirx/snps_hdmirx.c | 2856 +++++++++++++++++ - .../platform/synopsys/hdmirx/snps_hdmirx.h | 394 +++ - .../synopsys/hdmirx/snps_hdmirx_cec.c | 289 ++ - .../synopsys/hdmirx/snps_hdmirx_cec.h | 46 + - 10 files changed, 3614 insertions(+) - create mode 100644 drivers/media/platform/synopsys/Kconfig - create mode 100644 drivers/media/platform/synopsys/Makefile - create mode 100644 drivers/media/platform/synopsys/hdmirx/Kconfig - create mode 100644 drivers/media/platform/synopsys/hdmirx/Makefile - create mode 100644 drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c - create mode 100644 drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h - create mode 100644 drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c - create mode 100644 drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.h - -diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig -index 2d79bfc68c15..a7b84d45cb86 100644 ---- a/drivers/media/platform/Kconfig -+++ b/drivers/media/platform/Kconfig -@@ -83,6 +83,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 da17301f7439..3b7aff947f91 100644 ---- a/drivers/media/platform/Makefile -+++ b/drivers/media/platform/Makefile -@@ -26,6 +26,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..4fd521f78425 ---- /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..3b12c574dd67 ---- /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..adcdb7c2ed79 ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/Kconfig -@@ -0,0 +1,18 @@ -+# 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. -diff --git a/drivers/media/platform/synopsys/hdmirx/Makefile b/drivers/media/platform/synopsys/hdmirx/Makefile -new file mode 100644 -index 000000000000..2fa2d9e25300 ---- /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..63a38ee089ec ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -@@ -0,0 +1,2856 @@ -+// 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 "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_edid_version { -+ HDMIRX_EDID_USER = 0, -+ HDMIRX_EDID_340M = 1, -+ HDMIRX_EDID_600M = 2, -+}; -+ -+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_output_fmt { -+ u32 fourcc; -+ u8 cplanes; -+ u8 mplanes; -+ u8 bpp[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 hdmirx_output_fmt *out_fmt; -+ struct mutex vlock; -+ spinlock_t vbq_lock; -+ 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_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; -+ struct mutex work_lock; -+ 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_edid_version edid_version; -+ 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; -+}; -+ -+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 u8 edid_init_data_600M[] = { -+ 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, 0x00, 0x00, 0x00, 0x01, 0x01, -+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0xE8, -+ 0x00, 0x30, 0xF2, 0x70, 0x5A, 0x80, 0xB0, 0x58, -+ 0x8A, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00, 0x1E, -+ 0x08, 0xE8, 0x00, 0x30, 0xF2, 0x70, 0x5A, 0x80, -+ 0xB0, 0x58, 0x8A, 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, 0x39, -+ -+ 0x02, 0x03, 0x21, 0xD2, 0x41, 0x61, 0x23, 0x09, -+ 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x66, 0x03, -+ 0x0C, 0x00, 0x30, 0x00, 0x10, 0x67, 0xD8, 0x5D, -+ 0xC4, 0x01, 0x78, 0xC0, 0x07, 0xE3, 0x05, 0x03, -+ 0x01, 0x08, 0xE8, 0x00, 0x30, 0xF2, 0x70, 0x5A, -+ 0x80, 0xB0, 0x58, 0x8A, 0x00, 0xC4, 0x8E, 0x21, -+ 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, -+}; -+ -+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 const struct hdmirx_output_fmt g_out_fmts[] = { -+ { -+ .fourcc = V4L2_PIX_FMT_BGR24, -+ .cplanes = 1, -+ .mplanes = 1, -+ .bpp = { 24 }, -+ }, { -+ .fourcc = V4L2_PIX_FMT_NV24, -+ .cplanes = 2, -+ .mplanes = 1, -+ .bpp = { 8, 16 }, -+ }, { -+ .fourcc = V4L2_PIX_FMT_NV16, -+ .cplanes = 2, -+ .mplanes = 1, -+ .bpp = { 8, 16 }, -+ }, { -+ .fourcc = V4L2_PIX_FMT_NV12, -+ .cplanes = 2, -+ .mplanes = 1, -+ .bpp = { 8, 16 }, -+ } -+}; -+ -+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: -+ return v4l2_ctrl_subscribe_event(fh, sub); -+ } -+ -+ 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 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_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; -+ } -+ -+ /* -+ * query dv timings is during preview, dma's timing is stable, -+ * so we can get from DMA. If the current resolution is negative, -+ * get timing from CTRL need to change polarity of sync, -+ * maybe cause DMA errors. -+ */ -+ 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; -+ } -+ -+ 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)) -+ 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; -+ hdmirx_dev->edid_version = HDMIRX_EDID_USER; -+ -+ 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; -+ } -+ -+ if (!v4l2_match_dv_timings(&hdmirx_dev->timings, &timings, 0, false)) { -+ /* automatically set timing rather than set by userspace */ -+ hdmirx_dev->timings = timings; -+ v4l2_print_dv_timings(hdmirx_dev->v4l2_dev.name, -+ "New format: ", &timings, false); -+ } -+ -+ 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, "hdmirx", 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 int fcc_xysubs(u32 fcc, u32 *xsubs, u32 *ysubs) -+{ -+ /* Note: cbcr plane bpp is 16 bit */ -+ switch (fcc) { -+ case V4L2_PIX_FMT_NV24: -+ *xsubs = 1; -+ *ysubs = 1; -+ break; -+ case V4L2_PIX_FMT_NV16: -+ *xsubs = 2; -+ *ysubs = 1; -+ break; -+ case V4L2_PIX_FMT_NV12: -+ *xsubs = 2; -+ *ysubs = 2; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static u32 hdmirx_align_bits_per_pixel(const struct hdmirx_output_fmt *fmt, -+ int plane_index) -+{ -+ u32 bpp = 0; -+ -+ if (fmt) { -+ switch (fmt->fourcc) { -+ case V4L2_PIX_FMT_NV24: -+ case V4L2_PIX_FMT_NV16: -+ case V4L2_PIX_FMT_NV12: -+ case V4L2_PIX_FMT_BGR24: -+ bpp = fmt->bpp[plane_index]; -+ break; -+ default: -+ pr_err("fourcc: %#x is not supported\n", fmt->fourcc); -+ break; -+ } -+ } -+ -+ return bpp; -+} -+ -+static const struct hdmirx_output_fmt *find_output_fmt(u32 pixelfmt) -+{ -+ const struct hdmirx_output_fmt *fmt; -+ u32 i; -+ -+ for (i = 0; i < ARRAY_SIZE(g_out_fmts); i++) { -+ fmt = &g_out_fmts[i]; -+ if (fmt->fourcc == pixelfmt) -+ return fmt; -+ } -+ -+ return NULL; -+} -+ -+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 hdmirx_output_fmt *fmt; -+ unsigned int imagesize = 0, planes; -+ u32 xsubs = 1, ysubs = 1, i; -+ -+ memset(&pixm->plane_fmt[0], 0, sizeof(struct v4l2_plane_pix_format)); -+ fmt = find_output_fmt(pixm->pixelformat); -+ if (!fmt) { -+ fmt = &g_out_fmts[0]; -+ v4l2_err(v4l2_dev, -+ "%s: set_fmt:%#x not supported, use def_fmt:%x\n", -+ __func__, pixm->pixelformat, fmt->fourcc); -+ } -+ -+ if (!bt->width || !bt->height) -+ v4l2_err(v4l2_dev, "%s: invalid resolution:%#xx%#x\n", -+ __func__, bt->width, bt->height); -+ -+ pixm->pixelformat = fmt->fourcc; -+ pixm->width = bt->width; -+ pixm->height = bt->height; -+ pixm->num_planes = fmt->mplanes; -+ 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)); -+ -+ /* calculate plane size and image size */ -+ fcc_xysubs(fmt->fourcc, &xsubs, &ysubs); -+ planes = fmt->cplanes ? fmt->cplanes : fmt->mplanes; -+ -+ for (i = 0; i < planes; i++) { -+ struct v4l2_plane_pix_format *plane_fmt; -+ int width, height, bpl, size, bpp; -+ -+ if (!i) { -+ width = pixm->width; -+ height = pixm->height; -+ } else { -+ width = pixm->width / xsubs; -+ height = pixm->height / ysubs; -+ } -+ -+ bpp = hdmirx_align_bits_per_pixel(fmt, i); -+ bpl = ALIGN(width * bpp / HDMIRX_STORED_BIT_WIDTH, -+ MEMORY_ALIGN_ROUND_UP_BYTES); -+ size = bpl * height; -+ imagesize += size; -+ -+ if (fmt->mplanes > 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. -+ * It's important since we want to unify non-MPLANE and MPLANE. -+ */ -+ if (fmt->mplanes == 1) -+ pixm->plane_fmt[0].sizeimage = imagesize; -+ -+ if (!try) { -+ stream->out_fmt = fmt; -+ 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, fmt->fourcc); -+ } -+} -+ -+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)); -+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: snps_hdmirx"); -+ -+ 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 hdmirx_output_fmt *out_fmt; -+ u32 i, height; -+ -+ pixm = &stream->pixm; -+ out_fmt = stream->out_fmt; -+ -+ if (!num_planes || !out_fmt) { -+ 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; -+ } -+ -+ *num_planes = out_fmt->mplanes; -+ height = pixm->height; -+ -+ for (i = 0; i < out_fmt->mplanes; i++) { -+ const struct v4l2_plane_pix_format *plane_fmt; -+ int h = height; -+ -+ plane_fmt = &pixm->plane_fmt[i]; -+ sizes[i] = plane_fmt->sizeimage / height * h; -+ } -+ -+ 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 hdmirx_output_fmt *out_fmt; -+ 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_fmt = stream->out_fmt; -+ -+ 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_fmt->mplanes; i++) -+ hdmirx_buf->buff_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); -+ -+ if (out_fmt->mplanes == 1) { -+ if (out_fmt->cplanes == 1) { -+ hdmirx_buf->buff_addr[HDMIRX_PLANE_CBCR] = -+ hdmirx_buf->buff_addr[HDMIRX_PLANE_Y]; -+ } else { -+ for (i = 0; i < out_fmt->cplanes - 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_err(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; -+ 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); -+ -+ if (!stream->curr_buf) { -+ mutex_unlock(&hdmirx_dev->stream_lock); -+ return -ENOMEM; -+ } -+ -+ 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; -+ q->allow_cache_hints = 0; -+ q->bidirectional = 1; -+ 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, -+ .read = vb2_fop_read, -+ .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; -+ char *vdev_name; -+ int ret = 0; -+ -+ vdev_name = "stream_hdmirx"; -+ strscpy(vdev->name, vdev_name, 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 hdmirx_output_fmt *fmt = stream->out_fmt; -+ u32 i; -+ -+ /* Dequeue a filled buffer */ -+ for (i = 0; i < fmt->mplanes; 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 = "rst_a"; -+ hdmirx_dev->resets[HDMIRX_RST_P].id = "rst_p"; -+ hdmirx_dev->resets[HDMIRX_RST_REF].id = "rst_ref"; -+ hdmirx_dev->resets[HDMIRX_RST_BIU].id = "rst_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, "hdmirx-5v-detection", GPIOD_IN); -+ -+ if (IS_ERR(hdmirx_dev->detect_5v_gpio)) { -+ dev_err(dev, "failed to get hdmirx 5v 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_edid_init_config(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ int ret; -+ struct v4l2_edid def_edid; -+ -+ /* disable hpd and write edid */ -+ def_edid.pad = 0; -+ def_edid.start_block = 0; -+ def_edid.blocks = EDID_NUM_BLOCKS_MAX; -+ if (hdmirx_dev->edid_version == HDMIRX_EDID_600M) -+ def_edid.edid = edid_init_data_600M; -+ else -+ def_edid.edid = edid_init_data_340M; -+ ret = hdmirx_write_edid(hdmirx_dev, &def_edid, false); -+ 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); -+ -+ hdmirx_edid_init_config(hdmirx_dev); -+ -+ 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; -+ cec_data.edid = edid_init_data_340M; -+ -+ 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); -+ hdmirx_dev->edid_version = HDMIRX_EDID_340M; -+ -+ 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); -+ 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_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 int 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); -+ -+ return 0; -+} -+ -+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 v2"); -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..220ab99ca611 ---- /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..8554cbc4ccde ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c -@@ -0,0 +1,289 @@ -+// 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; -+} -+ -+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; -+ if (msg->len > 16) -+ msg_len = 16; -+ if (msg_len <= 0) -+ return 0; -+ -+ 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 = msg_len / 4 + 1; -+ 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; -+ } -+ -+ 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; -+ -+ if (!data) -+ return NULL; -+ -+ /* -+ * 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; -+ cec->edid = (struct edid *)data->edid; -+ -+ 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, "rk-hdmirx", -+ CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | -+ CEC_CAP_RC | CEC_CAP_PASSTHROUGH, -+ 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; -+ } -+ -+ cec_s_phys_addr_from_edid(cec->adap, cec->edid); -+ -+ 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) -+{ -+ if (!cec) -+ return; -+ -+ 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..ae43f74d471d ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.h -@@ -0,0 +1,46 @@ -+/* 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; -+ u8 *edid; -+}; -+ -+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 edid *edid; -+}; -+ -+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 */ --- -2.44.1 - - -From d3f4d04e3feba524c6e2fa0a2f8e25739a936396 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Wed, 15 May 2024 18:30:14 +0200 -Subject: [PATCH 25/54] usb: typec: tcpm: print error on hard reset - -A USB-C hard reset involves removing the voltage from VBUS for some -time. So basically it has the same effect as removing the USB-C plug -for a short moment. If the machine is powered from the USB-C port and -does not have a fallback supply (e.g. a battery), this will result in -a full machine reset due to power loss. - -Ideally we want to avoid triggering a hard reset on these boards. A -non-working USB-C port is probably better than unplanned reboots. But -boards with a backup supply should do the hard reset to get everything -working again. - -In theory it would be enough to check the self_powered property, but -it seems the property might not be configured consistently enough in -system firmwares. - -So let's start with just printing an error message when a hard reset is -triggered on systems we expect to be affected. This at least makes -debugging issues on affected systems easier without impacting unaffected -systems too much. - -Signed-off-by: Sebastian Reichel ---- - drivers/usb/typec/tcpm/tcpm.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c -index 8a1af08f71b6..375bc84d14a2 100644 ---- a/drivers/usb/typec/tcpm/tcpm.c -+++ b/drivers/usb/typec/tcpm/tcpm.c -@@ -5185,6 +5185,8 @@ static void run_state_machine(struct tcpm_port *port) - case HARD_RESET_SEND: - if (port->ams != NONE_AMS) - tcpm_ams_finish(port); -+ if (!port->self_powered && port->port_type == TYPEC_PORT_SNK) -+ dev_err(port->dev, "Initiating hard-reset, which might result in machine power-loss.\n"); - /* - * State machine will be directed to HARD_RESET_START, - * thus set upcoming_state to INVALID_STATE. --- -2.44.1 - - -From e394b2e700e3fe42e9240f1e1640b2e9c715f179 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Tue, 14 May 2024 17:29:32 +0200 -Subject: [PATCH 26/54] usb: typec: tcpm: avoid resets for missing source - capability messages - -When the Linux Type-C controller drivers probe, they requests a soft -reset, which should result in the source restarting to send Source -Capability messages again independently of the previous state. -Unfortunately some USB PD sources do not follow the specification and -do not send them after a soft reset when they already negotiated a -specific contract before. The current way (and what is described in the -specificiation) to resolve this problem is triggering a hard reset. - -But a hard reset is fatal on batteryless platforms powered via USB-C PD, -since that removes VBUS for some time. Since this is triggered at boot -time, the system will be stuck in a boot loop. Examples for platforms -affected by this are the Radxa Rock 5B or the Libre Computer Renegade -Elite ROC-RK3399-PC. - -Instead of directly trying a hard reset when no Source Capability -message is send by the USB-PD source automatically, this changes the -state machine to try explicitly asking for the capabilities by sending -a Get Source Capability control message. - -For me this solves issues with 2 different USB-PD sources - a RAVPower -powerbank and a Lemorele USB-C dock. Every other PD source I own -follows the specification and automatically sends the Source Capability -message after a soft reset, which works with or without this change. - -I decided against making this extra step limited to devices not having -the self_powered flag set, since I don't see any huge drawbacks in this -approach and it keeps the logic simpler. The worst case scenario would -be a power source, which is really stuck. In that case the hard reset -is delayed by another 310ms. - -Signed-off-by: Sebastian Reichel ---- - drivers/usb/typec/tcpm/tcpm.c | 27 +++++++++++++++++++++++++-- - 1 file changed, 25 insertions(+), 2 deletions(-) - -diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c -index 375bc84d14a2..bac6866617c8 100644 ---- a/drivers/usb/typec/tcpm/tcpm.c -+++ b/drivers/usb/typec/tcpm/tcpm.c -@@ -57,6 +57,7 @@ - S(SNK_DISCOVERY_DEBOUNCE), \ - S(SNK_DISCOVERY_DEBOUNCE_DONE), \ - S(SNK_WAIT_CAPABILITIES), \ -+ S(SNK_WAIT_CAPABILITIES_TIMEOUT), \ - S(SNK_NEGOTIATE_CAPABILITIES), \ - S(SNK_NEGOTIATE_PPS_CAPABILITIES), \ - S(SNK_TRANSITION_SINK), \ -@@ -3108,7 +3109,8 @@ static void tcpm_pd_data_request(struct tcpm_port *port, - PD_MSG_CTRL_REJECT : - PD_MSG_CTRL_NOT_SUPP, - NONE_AMS); -- } else if (port->state == SNK_WAIT_CAPABILITIES) { -+ } else if (port->state == SNK_WAIT_CAPABILITIES || -+ port->state == SNK_WAIT_CAPABILITIES_TIMEOUT) { - /* - * This message may be received even if VBUS is not - * present. This is quite unexpected; see USB PD -@@ -5039,10 +5041,31 @@ static void run_state_machine(struct tcpm_port *port) - tcpm_set_state(port, SNK_SOFT_RESET, - PD_T_SINK_WAIT_CAP); - } else { -- tcpm_set_state(port, hard_reset_state(port), -+ tcpm_set_state(port, SNK_WAIT_CAPABILITIES_TIMEOUT, - PD_T_SINK_WAIT_CAP); - } - break; -+ case SNK_WAIT_CAPABILITIES_TIMEOUT: -+ /* -+ * There are some USB PD sources in the field, which do not -+ * properly implement the specification and fail to start -+ * sending Source Capability messages after a soft reset. The -+ * specification suggests to do a hard reset when no Source -+ * capability message is received within PD_T_SINK_WAIT_CAP, -+ * but that might effectively kil the machine's power source. -+ * -+ * This slightly diverges from the specification and tries to -+ * recover from this by explicitly asking for the capabilities -+ * using the Get_Source_Cap control message before falling back -+ * to a hard reset. The control message should also be supported -+ * and handled by all USB PD source and dual role devices -+ * according to the specification. -+ */ -+ if (tcpm_pd_send_control(port, PD_CTRL_GET_SOURCE_CAP, TCPC_TX_SOP)) -+ tcpm_set_state_cond(port, hard_reset_state(port), 0); -+ else -+ tcpm_set_state(port, hard_reset_state(port), PD_T_SINK_WAIT_CAP); -+ break; - case SNK_NEGOTIATE_CAPABILITIES: - port->pd_capable = true; - tcpm_set_partner_usb_comm_capable(port, --- -2.44.1 - - -From d39959cd76c8f219df1de5ba951dec83cdb5c288 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Mon, 5 Feb 2024 01:38:48 +0200 -Subject: [PATCH 27/54] [WIP] phy: phy-rockchip-samsung-hdptx: Add FRL & EARC - support - -For upstreaming, this requires extending the standard PHY API to support -HDMI configuration options [1]. - -Currently, the bus_width PHY attribute is used to pass clock rate and -flags for 10-bit color depth, FRL and EARC. This is done by the HDMI -bridge driver via phy_set_bus_width(). - -[1]: https://lore.kernel.org/all/59d5595a24bbcca897e814440179fa2caf3dff38.1707040881.git.Sandor.yu@nxp.com/ - -Signed-off-by: Cristian Ciocaltea ---- - .../phy/rockchip/phy-rockchip-samsung-hdptx.c | 434 +++++++++++++++++- - 1 file changed, 431 insertions(+), 3 deletions(-) - -diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c -index 946c01210ac8..44acea3f86af 100644 ---- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c -+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c -@@ -190,6 +190,12 @@ - #define LN3_TX_SER_RATE_SEL_HBR2 BIT(3) - #define LN3_TX_SER_RATE_SEL_HBR3 BIT(2) - -+#define HDMI20_MAX_RATE 600000000 -+#define DATA_RATE_MASK 0xFFFFFFF -+#define COLOR_DEPTH_MASK BIT(31) -+#define HDMI_MODE_MASK BIT(30) -+#define HDMI_EARC_MASK BIT(29) -+ - struct lcpll_config { - u32 bit_rate; - u8 lcvco_mode_en; -@@ -272,6 +278,25 @@ struct rk_hdptx_phy { - struct clk_bulk_data *clks; - int nr_clks; - struct reset_control_bulk_data rsts[RST_MAX]; -+ bool earc_en; -+}; -+ -+static const struct lcpll_config lcpll_cfg[] = { -+ { 48000000, 1, 0, 0, 0x7d, 0x7d, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 2, -+ 0, 0x13, 0x18, 1, 0, 0x20, 0x0c, 1, 0, }, -+ { 40000000, 1, 1, 0, 0x68, 0x68, 1, 1, 0, 0, 0, 1, 1, 1, 1, 9, 0, 1, 1, -+ 0, 2, 3, 1, 0, 0x20, 0x0c, 1, 0, }, -+ { 32000000, 1, 1, 1, 0x6b, 0x6b, 1, 1, 0, 1, 2, 1, 1, 1, 1, 9, 1, 2, 1, -+ 0, 0x0d, 0x18, 1, 0, 0x20, 0x0c, 1, 1, }, -+}; -+ -+static const struct ropll_config ropll_frl_cfg[] = { -+ { 24000000, 0x19, 0x19, 1, 1, 0, 1, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, -+ 0, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, -+ { 18000000, 0x7d, 0x7d, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, -+ 0, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, -+ { 9000000, 0x7d, 0x7d, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, -+ 0, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, - }; - - static const struct ropll_config ropll_tmds_cfg[] = { -@@ -449,6 +474,73 @@ static const struct reg_sequence rk_hdtpx_tmds_cmn_init_seq[] = { - REG_SEQ0(CMN_REG(009b), 0x00), - }; - -+static const struct reg_sequence rk_hdtpx_frl_cmn_init_seq[] = { -+ REG_SEQ0(CMN_REG(0011), 0x00), -+ REG_SEQ0(CMN_REG(0017), 0x00), -+ REG_SEQ0(CMN_REG(0026), 0x53), -+ REG_SEQ0(CMN_REG(0030), 0x00), -+ REG_SEQ0(CMN_REG(0031), 0x20), -+ REG_SEQ0(CMN_REG(0032), 0x30), -+ REG_SEQ0(CMN_REG(0033), 0x0b), -+ REG_SEQ0(CMN_REG(0034), 0x23), -+ REG_SEQ0(CMN_REG(0042), 0xb8), -+ REG_SEQ0(CMN_REG(004e), 0x14), -+ REG_SEQ0(CMN_REG(0074), 0x00), -+ REG_SEQ0(CMN_REG(0081), 0x09), -+ REG_SEQ0(CMN_REG(0086), 0x01), -+ REG_SEQ0(CMN_REG(0087), 0x0c), -+ REG_SEQ0(CMN_REG(009b), 0x10), -+}; -+ -+static const struct reg_sequence rk_hdtpx_frl_ropll_cmn_init_seq[] = { -+ REG_SEQ0(CMN_REG(0008), 0x00), -+ REG_SEQ0(CMN_REG(001e), 0x14), -+ REG_SEQ0(CMN_REG(0020), 0x00), -+ REG_SEQ0(CMN_REG(0021), 0x00), -+ REG_SEQ0(CMN_REG(0022), 0x11), -+ REG_SEQ0(CMN_REG(0023), 0x00), -+ REG_SEQ0(CMN_REG(0025), 0x00), -+ REG_SEQ0(CMN_REG(0027), 0x00), -+ REG_SEQ0(CMN_REG(0028), 0x00), -+ REG_SEQ0(CMN_REG(002a), 0x01), -+ REG_SEQ0(CMN_REG(002b), 0x00), -+ REG_SEQ0(CMN_REG(002c), 0x00), -+ REG_SEQ0(CMN_REG(002d), 0x00), -+ REG_SEQ0(CMN_REG(002e), 0x00), -+ REG_SEQ0(CMN_REG(002f), 0x04), -+ REG_SEQ0(CMN_REG(003d), 0x40), -+ REG_SEQ0(CMN_REG(005c), 0x25), -+ REG_SEQ0(CMN_REG(0089), 0x00), -+ REG_SEQ0(CMN_REG(0094), 0x00), -+ REG_SEQ0(CMN_REG(0097), 0x02), -+ REG_SEQ0(CMN_REG(0099), 0x04), -+}; -+ -+static const struct reg_sequence rk_hdtpx_frl_lcpll_cmn_init_seq[] = { -+ REG_SEQ0(CMN_REG(0025), 0x10), -+ REG_SEQ0(CMN_REG(0027), 0x01), -+ REG_SEQ0(CMN_REG(0028), 0x0d), -+ REG_SEQ0(CMN_REG(002e), 0x02), -+ REG_SEQ0(CMN_REG(002f), 0x0d), -+ REG_SEQ0(CMN_REG(003d), 0x00), -+ REG_SEQ0(CMN_REG(0051), 0x00), -+ REG_SEQ0(CMN_REG(0055), 0x00), -+ REG_SEQ0(CMN_REG(0059), 0x11), -+ REG_SEQ0(CMN_REG(005a), 0x03), -+ REG_SEQ0(CMN_REG(005c), 0x05), -+ REG_SEQ0(CMN_REG(005e), 0x07), -+ REG_SEQ0(CMN_REG(0060), 0x01), -+ REG_SEQ0(CMN_REG(0064), 0x07), -+ REG_SEQ0(CMN_REG(0065), 0x00), -+ REG_SEQ0(CMN_REG(0069), 0x00), -+ REG_SEQ0(CMN_REG(006c), 0x00), -+ REG_SEQ0(CMN_REG(0070), 0x01), -+ REG_SEQ0(CMN_REG(0089), 0x02), -+ REG_SEQ0(CMN_REG(0095), 0x00), -+ REG_SEQ0(CMN_REG(0097), 0x00), -+ REG_SEQ0(CMN_REG(0099), 0x00), -+}; -+ - static const struct reg_sequence rk_hdtpx_common_sb_init_seq[] = { - REG_SEQ0(SB_REG(0114), 0x00), - REG_SEQ0(SB_REG(0115), 0x00), -@@ -472,6 +564,17 @@ static const struct reg_sequence rk_hdtpx_tmds_lntop_lowbr_seq[] = { - REG_SEQ0(LNTOP_REG(0205), 0x1f), - }; - -+static const struct reg_sequence rk_hdtpx_frl_lntop_init_seq[] = { -+ REG_SEQ0(LNTOP_REG(0200), 0x04), -+ REG_SEQ0(LNTOP_REG(0201), 0x00), -+ REG_SEQ0(LNTOP_REG(0202), 0x00), -+ REG_SEQ0(LNTOP_REG(0203), 0xf0), -+ REG_SEQ0(LNTOP_REG(0204), 0xff), -+ REG_SEQ0(LNTOP_REG(0205), 0xff), -+ REG_SEQ0(LNTOP_REG(0206), 0x05), -+ REG_SEQ0(LNTOP_REG(0207), 0x0f), -+}; -+ - static const struct reg_sequence rk_hdtpx_common_lane_init_seq[] = { - REG_SEQ0(LANE_REG(0303), 0x0c), - REG_SEQ0(LANE_REG(0307), 0x20), -@@ -550,6 +653,40 @@ static const struct reg_sequence rk_hdtpx_tmds_lane_init_seq[] = { - REG_SEQ0(LANE_REG(0606), 0x1c), - }; - -+static const struct reg_sequence rk_hdtpx_frl_ropll_lane_init_seq[] = { -+ REG_SEQ0(LANE_REG(0312), 0x3c), -+ REG_SEQ0(LANE_REG(0412), 0x3c), -+ REG_SEQ0(LANE_REG(0512), 0x3c), -+ REG_SEQ0(LANE_REG(0612), 0x3c), -+}; -+ -+static const struct reg_sequence rk_hdtpx_frl_lcpll_lane_init_seq[] = { -+ REG_SEQ0(LANE_REG(0312), 0x3c), -+ REG_SEQ0(LANE_REG(0412), 0x3c), -+ REG_SEQ0(LANE_REG(0512), 0x3c), -+ REG_SEQ0(LANE_REG(0612), 0x3c), -+ REG_SEQ0(LANE_REG(0303), 0x2f), -+ REG_SEQ0(LANE_REG(0403), 0x2f), -+ REG_SEQ0(LANE_REG(0503), 0x2f), -+ REG_SEQ0(LANE_REG(0603), 0x2f), -+ REG_SEQ0(LANE_REG(0305), 0x03), -+ REG_SEQ0(LANE_REG(0405), 0x03), -+ REG_SEQ0(LANE_REG(0505), 0x03), -+ REG_SEQ0(LANE_REG(0605), 0x03), -+ REG_SEQ0(LANE_REG(0306), 0xfc), -+ REG_SEQ0(LANE_REG(0406), 0xfc), -+ REG_SEQ0(LANE_REG(0506), 0xfc), -+ REG_SEQ0(LANE_REG(0606), 0xfc), -+ REG_SEQ0(LANE_REG(0305), 0x4f), -+ REG_SEQ0(LANE_REG(0405), 0x4f), -+ REG_SEQ0(LANE_REG(0505), 0x4f), -+ REG_SEQ0(LANE_REG(0605), 0x4f), -+ REG_SEQ0(LANE_REG(0304), 0x14), -+ REG_SEQ0(LANE_REG(0404), 0x14), -+ REG_SEQ0(LANE_REG(0504), 0x14), -+ REG_SEQ0(LANE_REG(0604), 0x14), -+}; -+ - static bool rk_hdptx_phy_is_rw_reg(struct device *dev, unsigned int reg) - { - switch (reg) { -@@ -651,6 +788,47 @@ static int rk_hdptx_post_enable_pll(struct rk_hdptx_phy *hdptx) - return 0; - } - -+static int rk_hdptx_post_power_up(struct rk_hdptx_phy *hdptx) -+{ -+ u32 val; -+ int ret; -+ -+ val = (HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16 | -+ HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN; -+ regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); -+ -+ usleep_range(10, 15); -+ reset_control_deassert(hdptx->rsts[RST_INIT].rstc); -+ -+ usleep_range(10, 15); -+ val = HDPTX_I_PLL_EN << 16 | HDPTX_I_PLL_EN; -+ regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); -+ -+ usleep_range(10, 15); -+ reset_control_deassert(hdptx->rsts[RST_CMN].rstc); -+ -+ ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, val, -+ val & HDPTX_O_PLL_LOCK_DONE, 20, 400); -+ if (ret) { -+ dev_err(hdptx->dev, "Failed to get PHY PLL lock: %d\n", ret); -+ return ret; -+ } -+ -+ usleep_range(20, 30); -+ reset_control_deassert(hdptx->rsts[RST_LANE].rstc); -+ -+ ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, val, -+ val & HDPTX_O_PHY_RDY, 100, 5000); -+ if (ret) { -+ dev_err(hdptx->dev, "Failed to get PHY ready: %d\n", ret); -+ return ret; -+ } -+ -+ dev_dbg(hdptx->dev, "PHY ready\n"); -+ -+ return 0; -+} -+ - static void rk_hdptx_phy_disable(struct rk_hdptx_phy *hdptx) - { - u32 val; -@@ -680,6 +858,99 @@ static void rk_hdptx_phy_disable(struct rk_hdptx_phy *hdptx) - regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); - } - -+static void rk_hdptx_earc_config(struct rk_hdptx_phy *hdptx) -+{ -+ regmap_update_bits(hdptx->regmap, SB_REG(0113), SB_RX_RCAL_OPT_CODE_MASK, -+ FIELD_PREP(SB_RX_RCAL_OPT_CODE_MASK, 1)); -+ regmap_write(hdptx->regmap, SB_REG(011c), 0x04); -+ regmap_update_bits(hdptx->regmap, SB_REG(011b), SB_AFC_TOL_MASK, -+ FIELD_PREP(SB_AFC_TOL_MASK, 3)); -+ regmap_write(hdptx->regmap, SB_REG(0109), 0x05); -+ -+ regmap_update_bits(hdptx->regmap, SB_REG(0120), -+ SB_EARC_EN_MASK | SB_EARC_AFC_EN_MASK, -+ FIELD_PREP(SB_EARC_EN_MASK, 1) | -+ FIELD_PREP(SB_EARC_AFC_EN_MASK, 1)); -+ regmap_update_bits(hdptx->regmap, SB_REG(011b), SB_EARC_SIG_DET_BYPASS_MASK, -+ FIELD_PREP(SB_EARC_SIG_DET_BYPASS_MASK, 1)); -+ regmap_update_bits(hdptx->regmap, SB_REG(011f), -+ SB_PWM_AFC_CTRL_MASK | SB_RCAL_RSTN_MASK, -+ FIELD_PREP(SB_PWM_AFC_CTRL_MASK, 0xc) | -+ FIELD_PREP(SB_RCAL_RSTN_MASK, 1)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0115), SB_READY_DELAY_TIME_MASK, -+ FIELD_PREP(SB_READY_DELAY_TIME_MASK, 2)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0113), SB_RX_RTERM_CTRL_MASK, -+ FIELD_PREP(SB_RX_RTERM_CTRL_MASK, 3)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0102), ANA_SB_RXTERM_OFFSP_MASK, -+ FIELD_PREP(ANA_SB_RXTERM_OFFSP_MASK, 3)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0103), ANA_SB_RXTERM_OFFSN_MASK, -+ FIELD_PREP(ANA_SB_RXTERM_OFFSN_MASK, 3)); -+ -+ regmap_write(hdptx->regmap, SB_REG(011a), 0x03); -+ regmap_write(hdptx->regmap, SB_REG(0118), 0x0a); -+ regmap_write(hdptx->regmap, SB_REG(011e), 0x6a); -+ regmap_write(hdptx->regmap, SB_REG(011d), 0x67); -+ -+ regmap_update_bits(hdptx->regmap, SB_REG(0117), FAST_PULSE_TIME_MASK, -+ FIELD_PREP(FAST_PULSE_TIME_MASK, 4)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0114), -+ SB_TG_SB_EN_DELAY_TIME_MASK | SB_TG_RXTERM_EN_DELAY_TIME_MASK, -+ FIELD_PREP(SB_TG_SB_EN_DELAY_TIME_MASK, 2) | -+ FIELD_PREP(SB_TG_RXTERM_EN_DELAY_TIME_MASK, 2)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0105), ANA_SB_TX_HLVL_PROG_MASK, -+ FIELD_PREP(ANA_SB_TX_HLVL_PROG_MASK, 7)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0106), ANA_SB_TX_LLVL_PROG_MASK, -+ FIELD_PREP(ANA_SB_TX_LLVL_PROG_MASK, 7)); -+ regmap_update_bits(hdptx->regmap, SB_REG(010f), ANA_SB_VREG_GAIN_CTRL_MASK, -+ FIELD_PREP(ANA_SB_VREG_GAIN_CTRL_MASK, 0)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0110), ANA_SB_VREG_REF_SEL_MASK, -+ FIELD_PREP(ANA_SB_VREG_REF_SEL_MASK, 1)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0115), SB_TG_OSC_EN_DELAY_TIME_MASK, -+ FIELD_PREP(SB_TG_OSC_EN_DELAY_TIME_MASK, 2)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0116), AFC_RSTN_DELAY_TIME_MASK, -+ FIELD_PREP(AFC_RSTN_DELAY_TIME_MASK, 2)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0109), ANA_SB_DMRX_AFC_DIV_RATIO_MASK, -+ FIELD_PREP(ANA_SB_DMRX_AFC_DIV_RATIO_MASK, 5)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0103), OVRD_SB_RX_RESCAL_DONE_MASK, -+ FIELD_PREP(OVRD_SB_RX_RESCAL_DONE_MASK, 1)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0104), OVRD_SB_EN_MASK, -+ FIELD_PREP(OVRD_SB_EN_MASK, 1)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0102), OVRD_SB_RXTERM_EN_MASK, -+ FIELD_PREP(OVRD_SB_RXTERM_EN_MASK, 1)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0105), OVRD_SB_EARC_CMDC_EN_MASK, -+ FIELD_PREP(OVRD_SB_EARC_CMDC_EN_MASK, 1)); -+ regmap_update_bits(hdptx->regmap, SB_REG(010f), -+ OVRD_SB_VREG_EN_MASK | OVRD_SB_VREG_LPF_BYPASS_MASK, -+ FIELD_PREP(OVRD_SB_VREG_EN_MASK, 1) | -+ FIELD_PREP(OVRD_SB_VREG_LPF_BYPASS_MASK, 1)); -+ regmap_update_bits(hdptx->regmap, SB_REG(0123), OVRD_SB_READY_MASK, -+ FIELD_PREP(OVRD_SB_READY_MASK, 1)); -+ -+ usleep_range(1000, 1100); -+ regmap_update_bits(hdptx->regmap, SB_REG(0103), SB_RX_RESCAL_DONE_MASK, -+ FIELD_PREP(SB_RX_RESCAL_DONE_MASK, 1)); -+ usleep_range(50, 60); -+ regmap_update_bits(hdptx->regmap, SB_REG(0104), SB_EN_MASK, -+ FIELD_PREP(SB_EN_MASK, 1)); -+ usleep_range(50, 60); -+ regmap_update_bits(hdptx->regmap, SB_REG(0102), SB_RXTERM_EN_MASK, -+ FIELD_PREP(SB_RXTERM_EN_MASK, 1)); -+ usleep_range(50, 60); -+ regmap_update_bits(hdptx->regmap, SB_REG(0105), SB_EARC_CMDC_EN_MASK, -+ FIELD_PREP(SB_EARC_CMDC_EN_MASK, 1)); -+ regmap_update_bits(hdptx->regmap, SB_REG(010f), SB_VREG_EN_MASK, -+ FIELD_PREP(SB_VREG_EN_MASK, 1)); -+ usleep_range(50, 60); -+ regmap_update_bits(hdptx->regmap, SB_REG(010f), OVRD_SB_VREG_LPF_BYPASS_MASK, -+ FIELD_PREP(OVRD_SB_VREG_LPF_BYPASS_MASK, 1)); -+ usleep_range(250, 300); -+ regmap_update_bits(hdptx->regmap, SB_REG(010f), OVRD_SB_VREG_LPF_BYPASS_MASK, -+ FIELD_PREP(OVRD_SB_VREG_LPF_BYPASS_MASK, 0)); -+ usleep_range(100, 120); -+ regmap_update_bits(hdptx->regmap, SB_REG(0123), SB_READY_MASK, -+ FIELD_PREP(SB_READY_MASK, 1)); -+} -+ - static bool rk_hdptx_phy_clk_pll_calc(unsigned int data_rate, - struct ropll_config *cfg) - { -@@ -755,9 +1026,13 @@ static bool rk_hdptx_phy_clk_pll_calc(unsigned int data_rate, - static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx, - unsigned int rate) - { -+ int i, bus_width = phy_get_bus_width(hdptx->phy); -+ u8 color_depth = (bus_width & COLOR_DEPTH_MASK) ? 1 : 0; - const struct ropll_config *cfg = NULL; - struct ropll_config rc = {0}; -- int i; -+ -+ if (color_depth) -+ rate = rate * 10 / 8; - - for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++) - if (rate == ropll_tmds_cfg[i].bit_rate) { -@@ -813,6 +1088,9 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx, - regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK, - FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv)); - -+ regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_SEL_MASK, -+ FIELD_PREP(PLL_PCG_CLK_SEL_MASK, color_depth)); -+ - regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN, - PLL_PCG_CLK_EN); - -@@ -853,9 +1131,146 @@ static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx, - rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_lane_init_seq); - rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lane_init_seq); - -+ if (hdptx->earc_en) -+ rk_hdptx_earc_config(hdptx); -+ - return rk_hdptx_post_enable_lane(hdptx); - } - -+static int rk_hdptx_ropll_frl_mode_config(struct rk_hdptx_phy *hdptx, -+ u32 bus_width) -+{ -+ u32 bit_rate = bus_width & DATA_RATE_MASK; -+ u8 color_depth = (bus_width & COLOR_DEPTH_MASK) ? 1 : 0; -+ const struct ropll_config *cfg = NULL; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(ropll_frl_cfg); i++) -+ if (bit_rate == ropll_frl_cfg[i].bit_rate) { -+ cfg = &ropll_frl_cfg[i]; -+ break; -+ } -+ -+ if (!cfg) { -+ dev_err(hdptx->dev, "%s cannot find pll cfg\n", __func__); -+ return -EINVAL; -+ } -+ -+ rk_hdptx_pre_power_up(hdptx); -+ -+ reset_control_assert(hdptx->rsts[RST_ROPLL].rstc); -+ usleep_range(10, 20); -+ reset_control_deassert(hdptx->rsts[RST_ROPLL].rstc); -+ -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_cmn_init_seq); -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_frl_cmn_init_seq); -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_frl_ropll_cmn_init_seq); -+ -+ regmap_write(hdptx->regmap, CMN_REG(0051), cfg->pms_mdiv); -+ regmap_write(hdptx->regmap, CMN_REG(0055), cfg->pms_mdiv_afc); -+ regmap_write(hdptx->regmap, CMN_REG(0059), -+ (cfg->pms_pdiv << 4) | cfg->pms_refdiv); -+ regmap_write(hdptx->regmap, CMN_REG(005a), cfg->pms_sdiv << 4); -+ -+ regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDM_EN_MASK, -+ FIELD_PREP(ROPLL_SDM_EN_MASK, cfg->sdm_en)); -+ if (!cfg->sdm_en) -+ regmap_update_bits(hdptx->regmap, CMN_REG(005e), 0xf, 0); -+ -+ regmap_update_bits(hdptx->regmap, CMN_REG(0064), ROPLL_SDM_NUM_SIGN_RBR_MASK, -+ FIELD_PREP(ROPLL_SDM_NUM_SIGN_RBR_MASK, cfg->sdm_num_sign)); -+ -+ regmap_write(hdptx->regmap, CMN_REG(0060), cfg->sdm_deno); -+ regmap_write(hdptx->regmap, CMN_REG(0065), cfg->sdm_num); -+ -+ regmap_update_bits(hdptx->regmap, CMN_REG(0069), ROPLL_SDC_N_RBR_MASK, -+ FIELD_PREP(ROPLL_SDC_N_RBR_MASK, cfg->sdc_n)); -+ -+ regmap_write(hdptx->regmap, CMN_REG(006c), cfg->sdc_num); -+ regmap_write(hdptx->regmap, CMN_REG(0070), cfg->sdc_deno); -+ -+ regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK, -+ FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv)); -+ regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_SEL_MASK, -+ FIELD_PREP(PLL_PCG_CLK_SEL_MASK, color_depth)); -+ -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq); -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_frl_lntop_init_seq); -+ -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_lane_init_seq); -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_frl_ropll_lane_init_seq); -+ -+ if (hdptx->earc_en) -+ rk_hdptx_earc_config(hdptx); -+ -+ return rk_hdptx_post_power_up(hdptx); -+} -+ -+static int rk_hdptx_lcpll_frl_mode_config(struct rk_hdptx_phy *hdptx, -+ u32 bus_width) -+{ -+ u32 bit_rate = bus_width & DATA_RATE_MASK; -+ u8 color_depth = (bus_width & COLOR_DEPTH_MASK) ? 1 : 0; -+ const struct lcpll_config *cfg = NULL; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(lcpll_cfg); i++) -+ if (bit_rate == lcpll_cfg[i].bit_rate) { -+ cfg = &lcpll_cfg[i]; -+ break; -+ } -+ -+ if (!cfg) { -+ dev_err(hdptx->dev, "%s cannot find pll cfg\n", __func__); -+ return -EINVAL; -+ } -+ -+ rk_hdptx_pre_power_up(hdptx); -+ -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_cmn_init_seq); -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_frl_cmn_init_seq); -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_frl_lcpll_cmn_init_seq); -+ -+ regmap_update_bits(hdptx->regmap, CMN_REG(0008), -+ LCPLL_EN_MASK | LCPLL_LCVCO_MODE_EN_MASK, -+ FIELD_PREP(LCPLL_EN_MASK, 1) | -+ FIELD_PREP(LCPLL_LCVCO_MODE_EN_MASK, cfg->lcvco_mode_en)); -+ -+ regmap_update_bits(hdptx->regmap, CMN_REG(001e), -+ LCPLL_PI_EN_MASK | LCPLL_100M_CLK_EN_MASK, -+ FIELD_PREP(LCPLL_PI_EN_MASK, cfg->pi_en) | -+ FIELD_PREP(LCPLL_100M_CLK_EN_MASK, cfg->clk_en_100m)); -+ -+ regmap_write(hdptx->regmap, CMN_REG(0020), cfg->pms_mdiv); -+ regmap_write(hdptx->regmap, CMN_REG(0021), cfg->pms_mdiv_afc); -+ regmap_write(hdptx->regmap, CMN_REG(0022), -+ (cfg->pms_pdiv << 4) | cfg->pms_refdiv); -+ regmap_write(hdptx->regmap, CMN_REG(0023), -+ (cfg->pms_sdiv << 4) | cfg->pms_sdiv); -+ regmap_write(hdptx->regmap, CMN_REG(002a), cfg->sdm_deno); -+ regmap_write(hdptx->regmap, CMN_REG(002b), cfg->sdm_num_sign); -+ regmap_write(hdptx->regmap, CMN_REG(002c), cfg->sdm_num); -+ -+ regmap_update_bits(hdptx->regmap, CMN_REG(002d), LCPLL_SDC_N_MASK, -+ FIELD_PREP(LCPLL_SDC_N_MASK, cfg->sdc_n)); -+ -+ regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK, -+ FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv)); -+ regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_SEL_MASK, -+ FIELD_PREP(PLL_PCG_CLK_SEL_MASK, color_depth)); -+ -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq); -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_frl_lntop_init_seq); -+ -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_lane_init_seq); -+ rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_frl_lcpll_lane_init_seq); -+ -+ if (hdptx->earc_en) -+ rk_hdptx_earc_config(hdptx); -+ -+ return rk_hdptx_post_power_up(hdptx); -+} -+ - static int rk_hdptx_phy_power_on(struct phy *phy) - { - struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); -@@ -865,7 +1280,7 @@ static int rk_hdptx_phy_power_on(struct phy *phy) - * from the HDMI bridge driver until phy_configure_opts_hdmi - * becomes available in the PHY API. - */ -- unsigned int rate = bus_width & 0xfffffff; -+ unsigned int rate = bus_width & DATA_RATE_MASK; - - dev_dbg(hdptx->dev, "%s bus_width=%x rate=%u\n", - __func__, bus_width, rate); -@@ -876,7 +1291,20 @@ static int rk_hdptx_phy_power_on(struct phy *phy) - return ret; - } - -- ret = rk_hdptx_ropll_tmds_mode_config(hdptx, rate); -+ if (bus_width & HDMI_EARC_MASK) -+ hdptx->earc_en = true; -+ else -+ hdptx->earc_en = false; -+ -+ if (bus_width & HDMI_MODE_MASK) { -+ if (rate > 24000000) -+ ret = rk_hdptx_lcpll_frl_mode_config(hdptx, bus_width); -+ else -+ ret = rk_hdptx_ropll_frl_mode_config(hdptx, bus_width); -+ } else { -+ ret = rk_hdptx_ropll_tmds_mode_config(hdptx, rate); -+ } -+ - if (ret) - pm_runtime_put(hdptx->dev); - --- -2.44.1 - - -From f3967b5c3262f3a19e84a3246e737ac39ec131e3 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Mon, 19 Feb 2024 21:53:24 +0200 -Subject: [PATCH 28/54] [WIP] dt-bindings: phy: rockchip,rk3588-hdptx-phy: Add - #clock-cells - -The PHY can be used as a clock provider on RK3588, hence add the missing -'#clock-cells' property. - -Signed-off-by: Cristian Ciocaltea ---- - .../devicetree/bindings/phy/rockchip,rk3588-hdptx-phy.yaml | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/Documentation/devicetree/bindings/phy/rockchip,rk3588-hdptx-phy.yaml b/Documentation/devicetree/bindings/phy/rockchip,rk3588-hdptx-phy.yaml -index 54e822c715f3..84fe59dbcf48 100644 ---- a/Documentation/devicetree/bindings/phy/rockchip,rk3588-hdptx-phy.yaml -+++ b/Documentation/devicetree/bindings/phy/rockchip,rk3588-hdptx-phy.yaml -@@ -27,6 +27,9 @@ properties: - - const: ref - - const: apb - -+ "#clock-cells": -+ const: 0 -+ - "#phy-cells": - const: 0 - --- -2.44.1 - - -From 3f89224fd82432d536350eb5291f906a7cc637e0 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Tue, 16 Jan 2024 19:27:40 +0200 -Subject: [PATCH 29/54] [WIP] phy: phy-rockchip-samsung-hdptx: Add clock - provider - -The HDMI PHY PLL can be used as an alternative dclk source to SoC CRU. -It provides more accurate clock rates required to properly support -various display modes, e.g. those relying on non-integer refresh rates. - -Also note this only works for HDMI 2.0 or bellow, e.g. cannot be used to -support HDMI 2.1 4K@120Hz mode. - -Signed-off-by: Cristian Ciocaltea ---- - .../phy/rockchip/phy-rockchip-samsung-hdptx.c | 148 +++++++++++++++++- - 1 file changed, 143 insertions(+), 5 deletions(-) - -diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c -index 44acea3f86af..a3ac4f3835bc 100644 ---- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c -+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c -@@ -8,6 +8,7 @@ - */ - #include - #include -+#include - #include - #include - #include -@@ -279,6 +280,12 @@ struct rk_hdptx_phy { - int nr_clks; - struct reset_control_bulk_data rsts[RST_MAX]; - bool earc_en; -+ -+ /* clk provider */ -+ struct clk_hw hw; -+ unsigned long rate; -+ int id; -+ int count; - }; - - static const struct lcpll_config lcpll_cfg[] = { -@@ -1031,6 +1038,8 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx, - const struct ropll_config *cfg = NULL; - struct ropll_config rc = {0}; - -+ hdptx->rate = rate * 100; -+ - if (color_depth) - rate = rate * 10 / 8; - -@@ -1315,11 +1324,13 @@ static int rk_hdptx_phy_power_off(struct phy *phy) - { - struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); - u32 val; -- int ret; -+ int ret = 0; - -- ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &val); -- if (ret == 0 && (val & HDPTX_O_PLL_LOCK_DONE)) -- rk_hdptx_phy_disable(hdptx); -+ if (hdptx->count == 0) { -+ ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &val); -+ if (ret == 0 && (val & HDPTX_O_PLL_LOCK_DONE)) -+ rk_hdptx_phy_disable(hdptx); -+ } - - pm_runtime_put(hdptx->dev); - -@@ -1332,6 +1343,129 @@ static const struct phy_ops rk_hdptx_phy_ops = { - .owner = THIS_MODULE, - }; - -+static struct rk_hdptx_phy *to_rk_hdptx_phy(struct clk_hw *hw) -+{ -+ return container_of(hw, struct rk_hdptx_phy, hw); -+} -+ -+static int rk_hdptx_phy_clk_prepare(struct clk_hw *hw) -+{ -+ struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); -+ int ret; -+ -+ ret = pm_runtime_resume_and_get(hdptx->dev); -+ if (ret) { -+ dev_err(hdptx->dev, "Failed to resume phy clk: %d\n", ret); -+ return ret; -+ } -+ -+ if (!hdptx->count && hdptx->rate) { -+ ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, hdptx->rate / 100); -+ if (ret < 0) { -+ dev_err(hdptx->dev, "Failed to init PHY PLL: %d\n", ret); -+ pm_runtime_put(hdptx->dev); -+ return ret; -+ } -+ } -+ -+ hdptx->count++; -+ -+ return 0; -+} -+ -+static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw) -+{ -+ struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); -+ -+ if (hdptx->count == 1) { -+ u32 val; -+ int ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &val); -+ if (ret == 0 && (val & HDPTX_O_PLL_LOCK_DONE)) -+ rk_hdptx_phy_disable(hdptx); -+ } -+ -+ hdptx->count--; -+ pm_runtime_put(hdptx->dev); -+} -+ -+static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); -+ -+ return hdptx->rate; -+} -+ -+static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *parent_rate) -+{ -+ const struct ropll_config *cfg = NULL; -+ u32 bit_rate = rate / 100; -+ int i; -+ -+ if (rate > HDMI20_MAX_RATE) -+ return rate; -+ -+ for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++) -+ if (bit_rate == ropll_tmds_cfg[i].bit_rate) { -+ cfg = &ropll_tmds_cfg[i]; -+ break; -+ } -+ -+ if (!cfg && !rk_hdptx_phy_clk_pll_calc(bit_rate, NULL)) -+ return -EINVAL; -+ -+ return rate; -+} -+ -+static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); -+ u32 val; -+ int ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &val); -+ if (ret == 0 && (val & HDPTX_O_PLL_LOCK_DONE)) -+ rk_hdptx_phy_disable(hdptx); -+ -+ return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate / 100); -+} -+ -+static const struct clk_ops hdptx_phy_clk_ops = { -+ .prepare = rk_hdptx_phy_clk_prepare, -+ .unprepare = rk_hdptx_phy_clk_unprepare, -+ .recalc_rate = rk_hdptx_phy_clk_recalc_rate, -+ .round_rate = rk_hdptx_phy_clk_round_rate, -+ .set_rate = rk_hdptx_phy_clk_set_rate, -+}; -+ -+static int rk_hdptx_phy_clk_register(struct rk_hdptx_phy *hdptx) -+{ -+ struct device *dev = hdptx->dev; -+ const char *name, *pname; -+ struct clk *refclk; -+ int ret; -+ -+ refclk = devm_clk_get(dev, "ref"); -+ if (IS_ERR(refclk)) -+ return dev_err_probe(dev, PTR_ERR(refclk), -+ "Failed to get ref clock\n"); -+ -+ pname = __clk_get_name(refclk); -+ name = hdptx->id ? "clk_hdmiphy_pixel1" : "clk_hdmiphy_pixel0"; -+ hdptx->hw.init = CLK_HW_INIT(name, pname, &hdptx_phy_clk_ops, -+ CLK_GET_RATE_NOCACHE); -+ -+ ret = devm_clk_hw_register(dev, &hdptx->hw); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to register clock\n"); -+ -+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &hdptx->hw); -+ if (ret) -+ return dev_err_probe(dev, ret, -+ "Failed to register clk provider\n"); -+ return 0; -+} -+ - static int rk_hdptx_phy_runtime_suspend(struct device *dev) - { - struct rk_hdptx_phy *hdptx = dev_get_drvdata(dev); -@@ -1367,6 +1501,10 @@ static int rk_hdptx_phy_probe(struct platform_device *pdev) - - hdptx->dev = dev; - -+ hdptx->id = of_alias_get_id(dev->of_node, "hdptxphy"); -+ if (hdptx->id < 0) -+ hdptx->id = 0; -+ - regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(regs)) - return dev_err_probe(dev, PTR_ERR(regs), -@@ -1426,7 +1564,7 @@ static int rk_hdptx_phy_probe(struct platform_device *pdev) - reset_control_deassert(hdptx->rsts[RST_CMN].rstc); - reset_control_deassert(hdptx->rsts[RST_INIT].rstc); - -- return 0; -+ return rk_hdptx_phy_clk_register(hdptx); - } - - static const struct dev_pm_ops rk_hdptx_phy_pm_ops = { --- -2.44.1 - - -From c7dbc888875e205bbfbf81d8174b6412642c429f Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Wed, 27 Mar 2024 20:36:15 +0200 -Subject: [PATCH 30/54] [WIP] dt-bindings: display: rockchip-drm: Add optional - clocks property - -Allow using the clock provided by HDMI0 PHY PLL to improve HDMI output -support on RK3588 SoC. - -Signed-off-by: Cristian Ciocaltea ---- - .../bindings/display/rockchip/rockchip-drm.yaml | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.yaml -index a8d18a37cb23..9d000760dd6e 100644 ---- a/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.yaml -+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.yaml -@@ -28,6 +28,14 @@ properties: - of vop devices. vop definitions as defined in - Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml - -+ clocks: -+ maxItems: 1 -+ description: Optional clock provided by HDMI0 PLL -+ -+ clock-names: -+ items: -+ - const: hdmi0_phy_pll -+ - required: - - compatible - - ports --- -2.44.1 - - -From 05c5f1c19d33c6c5404a68adb6d264387133d352 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Fri, 3 Nov 2023 19:58:02 +0200 -Subject: [PATCH 31/54] [WIP] drm/rockchip: vop2: Improve display modes - handling on rk3588 - -The initial vop2 support for rk3588 in mainline is not able to handle -all display modes supported by connected displays, e.g. -2560x1440-75.00Hz, 2048x1152-60.00Hz, 1024x768-60.00Hz. - -Additionally, it doesn't cope with non-integer refresh rates like 59.94, -29.97, 23.98, etc. - -Improve HDMI0 clocking in order to support the additional display modes. - -Fixes: 5a028e8f062f ("drm/rockchip: vop2: Add support for rk3588") -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 553 ++++++++++++++++++- - 1 file changed, 552 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -index 62ebbdb16253..86d2c15af39f 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -@@ -5,6 +5,8 @@ - */ - #include - #include -+#include -+#include - #include - #include - #include -@@ -212,6 +214,10 @@ struct vop2 { - struct clk *hclk; - struct clk *aclk; - struct clk *pclk; -+ // [CC:] hack to support additional display modes -+ struct clk *hdmi0_phy_pll; -+ /* list_head of internal clk */ -+ struct list_head clk_list_head; - - /* optional internal rgb encoder */ - struct rockchip_rgb *rgb; -@@ -220,6 +226,19 @@ struct vop2 { - struct vop2_win win[]; - }; - -+struct vop2_clk { -+ struct vop2 *vop2; -+ struct list_head list; -+ unsigned long rate; -+ struct clk_hw hw; -+ struct clk_divider div; -+ int div_val; -+ u8 parent_index; -+}; -+ -+#define to_vop2_clk(_hw) container_of(_hw, struct vop2_clk, hw) -+#define VOP2_MAX_DCLK_RATE 600000 /* kHz */ -+ - #define vop2_output_if_is_hdmi(x) ((x) == ROCKCHIP_VOP2_EP_HDMI0 || \ - (x) == ROCKCHIP_VOP2_EP_HDMI1) - -@@ -1476,9 +1495,30 @@ static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) - { -+ struct vop2_video_port *vp = to_vop2_video_port(crtc); -+ struct drm_connector *connector; -+ struct drm_connector_list_iter conn_iter; -+ struct drm_crtc_state *new_crtc_state = container_of(mode, struct drm_crtc_state, mode); - drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V | - CRTC_STEREO_DOUBLE); - -+ if (mode->flags & DRM_MODE_FLAG_DBLCLK) -+ adj_mode->crtc_clock *= 2; -+ -+ drm_connector_list_iter_begin(crtc->dev, &conn_iter); -+ drm_for_each_connector_iter(connector, &conn_iter) { -+ if ((new_crtc_state->connector_mask & drm_connector_mask(connector)) && -+ ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) || -+ (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA))) { -+ drm_connector_list_iter_end(&conn_iter); -+ return true; -+ } -+ } -+ drm_connector_list_iter_end(&conn_iter); -+ -+ if (adj_mode->crtc_clock <= VOP2_MAX_DCLK_RATE) -+ adj_mode->crtc_clock = DIV_ROUND_UP(clk_round_rate(vp->dclk, -+ adj_mode->crtc_clock * 1000), 1000); - return true; - } - -@@ -1663,6 +1703,31 @@ static unsigned long rk3588_calc_dclk(unsigned long child_clk, unsigned long max - return 0; - } - -+static struct vop2_clk *vop2_clk_get(struct vop2 *vop2, const char *name); -+ -+static int vop2_cru_set_rate(struct vop2_clk *if_pixclk, struct vop2_clk *if_dclk) -+{ -+ int ret = 0; -+ -+ if (if_pixclk) { -+ ret = clk_set_rate(if_pixclk->hw.clk, if_pixclk->rate); -+ if (ret < 0) { -+ DRM_DEV_ERROR(if_pixclk->vop2->dev, "set %s to %ld failed: %d\n", -+ clk_hw_get_name(&if_pixclk->hw), if_pixclk->rate, ret); -+ return ret; -+ } -+ } -+ -+ if (if_dclk) { -+ ret = clk_set_rate(if_dclk->hw.clk, if_dclk->rate); -+ if (ret < 0) -+ DRM_DEV_ERROR(if_dclk->vop2->dev, "set %s to %ld failed %d\n", -+ clk_hw_get_name(&if_dclk->hw), if_dclk->rate, ret); -+ } -+ -+ return ret; -+} -+ - /* - * 4 pixclk/cycle on rk3588 - * RGB/eDP/HDMI: if_pixclk >= dclk_core -@@ -1686,6 +1751,72 @@ static unsigned long rk3588_calc_cru_cfg(struct vop2_video_port *vp, int id, - int K = 1; - - if (vop2_output_if_is_hdmi(id)) { -+ if (vop2->data->soc_id == 3588 && id == ROCKCHIP_VOP2_EP_HDMI0 && -+ vop2->hdmi0_phy_pll) { -+ const char *clk_src_name = "hdmi_edp0_clk_src"; -+ const char *clk_parent_name = "dclk"; -+ const char *pixclk_name = "hdmi_edp0_pixclk"; -+ const char *dclk_name = "hdmi_edp0_dclk"; -+ struct vop2_clk *if_clk_src, *if_clk_parent, *if_pixclk, *if_dclk, *dclk, *dclk_core, *dclk_out; -+ char clk_name[32]; -+ int ret; -+ -+ if_clk_src = vop2_clk_get(vop2, clk_src_name); -+ snprintf(clk_name, sizeof(clk_name), "%s%d", clk_parent_name, vp->id); -+ if_clk_parent = vop2_clk_get(vop2, clk_name); -+ if_pixclk = vop2_clk_get(vop2, pixclk_name); -+ if_dclk = vop2_clk_get(vop2, dclk_name); -+ if (!if_pixclk || !if_clk_parent) { -+ DRM_DEV_ERROR(vop2->dev, "failed to get connector interface clk\n"); -+ return -ENODEV; -+ } -+ -+ ret = clk_set_parent(if_clk_src->hw.clk, if_clk_parent->hw.clk); -+ if (ret < 0) { -+ DRM_DEV_ERROR(vop2->dev, "failed to set parent(%s) for %s: %d\n", -+ __clk_get_name(if_clk_parent->hw.clk), -+ __clk_get_name(if_clk_src->hw.clk), ret); -+ return ret; -+ } -+ -+ if (output_mode == ROCKCHIP_OUT_MODE_YUV420) -+ K = 2; -+ -+ if_pixclk->rate = (dclk_core_rate << 1) / K; -+ if_dclk->rate = dclk_core_rate / K; -+ -+ snprintf(clk_name, sizeof(clk_name), "dclk_core%d", vp->id); -+ dclk_core = vop2_clk_get(vop2, clk_name); -+ -+ snprintf(clk_name, sizeof(clk_name), "dclk_out%d", vp->id); -+ dclk_out = vop2_clk_get(vop2, clk_name); -+ -+ snprintf(clk_name, sizeof(clk_name), "dclk%d", vp->id); -+ dclk = vop2_clk_get(vop2, clk_name); -+ if (v_pixclk <= (VOP2_MAX_DCLK_RATE * 1000)) { -+ if (output_mode == ROCKCHIP_OUT_MODE_YUV420) -+ v_pixclk = v_pixclk >> 1; -+ } else { -+ v_pixclk = v_pixclk >> 2; -+ } -+ clk_set_rate(dclk->hw.clk, v_pixclk); -+ -+ if (dclk_core_rate > if_pixclk->rate) { -+ clk_set_rate(dclk_core->hw.clk, dclk_core_rate); -+ ret = vop2_cru_set_rate(if_pixclk, if_dclk); -+ } else { -+ ret = vop2_cru_set_rate(if_pixclk, if_dclk); -+ clk_set_rate(dclk_core->hw.clk, dclk_core_rate); -+ } -+ -+ *dclk_core_div = dclk_core->div_val; -+ *dclk_out_div = dclk_out->div_val; -+ *if_pixclk_div = if_pixclk->div_val; -+ *if_dclk_div = if_dclk->div_val; -+ -+ return dclk->rate; -+ } -+ - /* - * K = 2: dclk_core = if_pixclk_rate > if_dclk_rate - * K = 1: dclk_core = hdmie_edp_dclk > if_pixclk_rate -@@ -1917,6 +2048,22 @@ static int us_to_vertical_line(struct drm_display_mode *mode, int us) - return us * mode->clock / mode->htotal / 1000; - } - -+// [CC:] rework virtual clock -+static struct vop2_clk *vop2_clk_get(struct vop2 *vop2, const char *name) -+{ -+ struct vop2_clk *clk, *n; -+ -+ if (!name) -+ return NULL; -+ -+ list_for_each_entry_safe(clk, n, &vop2->clk_list_head, list) { -+ if (!strcmp(clk_hw_get_name(&clk->hw), name)) -+ return clk; -+ } -+ -+ return NULL; -+} -+ - static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - struct drm_atomic_state *state) - { -@@ -1944,6 +2091,8 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - u32 val, polflags; - int ret; - struct drm_encoder *encoder; -+ char clk_name[32]; -+ struct vop2_clk *dclk; - - drm_dbg(vop2->drm, "Update mode to %dx%d%s%d, type: %d for vp%d\n", - hdisplay, vdisplay, mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p", -@@ -2044,11 +2193,38 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - - if (mode->flags & DRM_MODE_FLAG_DBLCLK) { - dsp_ctrl |= RK3568_VP_DSP_CTRL__CORE_DCLK_DIV; -- clock *= 2; -+ // [CC:] done via mode_fixup -+ // clock *= 2; - } - - vop2_vp_write(vp, RK3568_VP_MIPI_CTRL, 0); - -+ snprintf(clk_name, sizeof(clk_name), "dclk%d", vp->id); -+ dclk = vop2_clk_get(vop2, clk_name); -+ if (dclk) { -+ /* -+ * use HDMI_PHY_PLL as dclk source under 4K@60 if it is available, -+ * otherwise use system cru as dclk source. -+ */ -+ drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { -+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); -+ -+ // [CC:] Using PHY PLL to handle all display modes -+ if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) { -+ clk_get_rate(vop2->hdmi0_phy_pll); -+ -+ if (mode->crtc_clock <= VOP2_MAX_DCLK_RATE) { -+ ret = clk_set_parent(vp->dclk, vop2->hdmi0_phy_pll); -+ if (ret < 0) -+ DRM_WARN("failed to set clock parent for %s\n", -+ __clk_get_name(vp->dclk)); -+ } -+ -+ clock = dclk->rate; -+ } -+ } -+ } -+ - clk_set_rate(vp->dclk, clock); - - vop2_post_config(crtc); -@@ -2504,7 +2680,43 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, - spin_unlock_irq(&crtc->dev->event_lock); - } - -+static enum drm_mode_status -+vop2_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) -+{ -+ struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); -+ struct vop2_video_port *vp = to_vop2_video_port(crtc); -+ struct vop2 *vop2 = vp->vop2; -+ const struct vop2_data *vop2_data = vop2->data; -+ const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; -+ int request_clock = mode->clock; -+ int clock; -+ -+ if (mode->hdisplay > vp_data->max_output.width) -+ return MODE_BAD_HVALUE; -+ -+ if (mode->flags & DRM_MODE_FLAG_DBLCLK) -+ request_clock *= 2; -+ -+ if (request_clock <= VOP2_MAX_DCLK_RATE) { -+ clock = request_clock; -+ } else { -+ request_clock = request_clock >> 2; -+ clock = clk_round_rate(vp->dclk, request_clock * 1000) / 1000; -+ } -+ -+ /* -+ * Hdmi or DisplayPort request a Accurate clock. -+ */ -+ if (vcstate->output_type == DRM_MODE_CONNECTOR_HDMIA || -+ vcstate->output_type == DRM_MODE_CONNECTOR_DisplayPort) -+ if (clock != request_clock) -+ return MODE_CLOCK_RANGE; -+ -+ return MODE_OK; -+} -+ - static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = { -+ .mode_valid = vop2_crtc_mode_valid, - .mode_fixup = vop2_crtc_mode_fixup, - .atomic_check = vop2_crtc_atomic_check, - .atomic_begin = vop2_crtc_atomic_begin, -@@ -3074,6 +3286,336 @@ static const struct regmap_config vop2_regmap_config = { - .cache_type = REGCACHE_MAPLE, - }; - -+/* -+ * BEGIN virtual clock -+ */ -+#define PLL_RATE_MIN 30000000 -+ -+#define cru_dbg(format, ...) do { \ -+ if (cru_debug) \ -+ pr_info("%s: " format, __func__, ## __VA_ARGS__); \ -+ } while (0) -+ -+#define PNAME(x) static const char *const x[] -+ -+enum vop_clk_branch_type { -+ branch_mux, -+ branch_divider, -+ branch_factor, -+ branch_virtual, -+}; -+ -+#define VIR(cname) \ -+ { \ -+ .branch_type = branch_virtual, \ -+ .name = cname, \ -+ } -+ -+ -+#define MUX(cname, pnames, f) \ -+ { \ -+ .branch_type = branch_mux, \ -+ .name = cname, \ -+ .parent_names = pnames, \ -+ .num_parents = ARRAY_SIZE(pnames), \ -+ .flags = f, \ -+ } -+ -+#define FACTOR(cname, pname, f) \ -+ { \ -+ .branch_type = branch_factor, \ -+ .name = cname, \ -+ .parent_names = (const char *[]){ pname }, \ -+ .num_parents = 1, \ -+ .flags = f, \ -+ } -+ -+#define DIV(cname, pname, f, w) \ -+ { \ -+ .branch_type = branch_divider, \ -+ .name = cname, \ -+ .parent_names = (const char *[]){ pname }, \ -+ .num_parents = 1, \ -+ .flags = f, \ -+ .div_width = w, \ -+ } -+ -+struct vop2_clk_branch { -+ enum vop_clk_branch_type branch_type; -+ const char *name; -+ const char *const *parent_names; -+ u8 num_parents; -+ unsigned long flags; -+ u8 div_shift; -+ u8 div_width; -+ u8 div_flags; -+}; -+ -+PNAME(mux_port0_dclk_src_p) = { "dclk0", "dclk1" }; -+PNAME(mux_port2_dclk_src_p) = { "dclk2", "dclk1" }; -+PNAME(mux_dp_pixclk_p) = { "dclk_out0", "dclk_out1", "dclk_out2" }; -+PNAME(mux_hdmi_edp_clk_src_p) = { "dclk0", "dclk1", "dclk2" }; -+PNAME(mux_mipi_clk_src_p) = { "dclk_out1", "dclk_out2", "dclk_out3" }; -+PNAME(mux_dsc_8k_clk_src_p) = { "dclk0", "dclk1", "dclk2", "dclk3" }; -+PNAME(mux_dsc_4k_clk_src_p) = { "dclk0", "dclk1", "dclk2", "dclk3" }; -+ -+/* -+ * We only use this clk driver calculate the div -+ * of dclk_core/dclk_out/if_pixclk/if_dclk and -+ * the rate of the dclk from the soc. -+ * -+ * We don't touch the cru in the vop here, as -+ * these registers has special read andy write -+ * limits. -+ */ -+static struct vop2_clk_branch rk3588_vop_clk_branches[] = { -+ VIR("dclk0"), -+ VIR("dclk1"), -+ VIR("dclk2"), -+ VIR("dclk3"), -+ -+ MUX("port0_dclk_src", mux_port0_dclk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("dclk_core0", "port0_dclk_src", CLK_SET_RATE_PARENT, 2), -+ DIV("dclk_out0", "port0_dclk_src", CLK_SET_RATE_PARENT, 2), -+ -+ FACTOR("port1_dclk_src", "dclk1", CLK_SET_RATE_PARENT), -+ DIV("dclk_core1", "port1_dclk_src", CLK_SET_RATE_PARENT, 2), -+ DIV("dclk_out1", "port1_dclk_src", CLK_SET_RATE_PARENT, 2), -+ -+ MUX("port2_dclk_src", mux_port2_dclk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("dclk_core2", "port2_dclk_src", CLK_SET_RATE_PARENT, 2), -+ DIV("dclk_out2", "port2_dclk_src", CLK_SET_RATE_PARENT, 2), -+ -+ FACTOR("port3_dclk_src", "dclk3", CLK_SET_RATE_PARENT), -+ DIV("dclk_core3", "port3_dclk_src", CLK_SET_RATE_PARENT, 2), -+ DIV("dclk_out3", "port3_dclk_src", CLK_SET_RATE_PARENT, 2), -+ -+ MUX("dp0_pixclk", mux_dp_pixclk_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ MUX("dp1_pixclk", mux_dp_pixclk_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ -+ MUX("hdmi_edp0_clk_src", mux_hdmi_edp_clk_src_p, -+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("hdmi_edp0_dclk", "hdmi_edp0_clk_src", 0, 2), -+ DIV("hdmi_edp0_pixclk", "hdmi_edp0_clk_src", CLK_SET_RATE_PARENT, 1), -+ -+ MUX("hdmi_edp1_clk_src", mux_hdmi_edp_clk_src_p, -+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("hdmi_edp1_dclk", "hdmi_edp1_clk_src", 0, 2), -+ DIV("hdmi_edp1_pixclk", "hdmi_edp1_clk_src", CLK_SET_RATE_PARENT, 1), -+ -+ MUX("mipi0_clk_src", mux_mipi_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("mipi0_pixclk", "mipi0_clk_src", CLK_SET_RATE_PARENT, 2), -+ -+ MUX("mipi1_clk_src", mux_mipi_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("mipi1_pixclk", "mipi1_clk_src", CLK_SET_RATE_PARENT, 2), -+ -+ FACTOR("rgb_pixclk", "port3_dclk_src", CLK_SET_RATE_PARENT), -+ -+ MUX("dsc_8k_txp_clk_src", mux_dsc_8k_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("dsc_8k_txp_clk", "dsc_8k_txp_clk_src", 0, 2), -+ DIV("dsc_8k_pxl_clk", "dsc_8k_txp_clk_src", 0, 2), -+ DIV("dsc_8k_cds_clk", "dsc_8k_txp_clk_src", 0, 2), -+ -+ MUX("dsc_4k_txp_clk_src", mux_dsc_4k_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("dsc_4k_txp_clk", "dsc_4k_txp_clk_src", 0, 2), -+ DIV("dsc_4k_pxl_clk", "dsc_4k_txp_clk_src", 0, 2), -+ DIV("dsc_4k_cds_clk", "dsc_4k_txp_clk_src", 0, 2), -+}; -+ -+static unsigned long clk_virtual_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ -+ return (unsigned long)vop2_clk->rate; -+} -+ -+static long clk_virtual_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ -+ vop2_clk->rate = rate; -+ -+ return rate; -+} -+ -+static int clk_virtual_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ return 0; -+} -+ -+const struct clk_ops clk_virtual_ops = { -+ .round_rate = clk_virtual_round_rate, -+ .set_rate = clk_virtual_set_rate, -+ .recalc_rate = clk_virtual_recalc_rate, -+}; -+ -+static u8 vop2_mux_get_parent(struct clk_hw *hw) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ -+ // cru_dbg("%s index: %d\n", clk_hw_get_name(hw), vop2_clk->parent_index); -+ return vop2_clk->parent_index; -+} -+ -+static int vop2_mux_set_parent(struct clk_hw *hw, u8 index) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ -+ vop2_clk->parent_index = index; -+ -+ // cru_dbg("%s index: %d\n", clk_hw_get_name(hw), index); -+ return 0; -+} -+ -+static int vop2_clk_mux_determine_rate(struct clk_hw *hw, -+ struct clk_rate_request *req) -+{ -+ // cru_dbg("%s %ld(min: %ld max: %ld)\n", -+ // clk_hw_get_name(hw), req->rate, req->min_rate, req->max_rate); -+ return __clk_mux_determine_rate(hw, req); -+} -+ -+static const struct clk_ops vop2_mux_clk_ops = { -+ .get_parent = vop2_mux_get_parent, -+ .set_parent = vop2_mux_set_parent, -+ .determine_rate = vop2_clk_mux_determine_rate, -+}; -+ -+#define div_mask(width) ((1 << (width)) - 1) -+ -+static int vop2_div_get_val(unsigned long rate, unsigned long parent_rate) -+{ -+ unsigned int div, value; -+ -+ div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); -+ -+ value = ilog2(div); -+ -+ return value; -+} -+ -+static unsigned long vop2_clk_div_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ unsigned long rate; -+ unsigned int div; -+ -+ div = 1 << vop2_clk->div_val; -+ rate = parent_rate / div; -+ -+ // cru_dbg("%s rate: %ld(prate: %ld)\n", clk_hw_get_name(hw), rate, parent_rate); -+ return rate; -+} -+ -+static long vop2_clk_div_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ -+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { -+ if (*prate < rate) -+ *prate = rate; -+ if ((*prate >> vop2_clk->div.width) > rate) -+ *prate = rate; -+ -+ if ((*prate % rate)) -+ *prate = rate; -+ -+ /* SOC PLL can't output a too low pll freq */ -+ if (*prate < PLL_RATE_MIN) -+ *prate = rate << vop2_clk->div.width; -+ } -+ -+ // cru_dbg("%s rate: %ld(prate: %ld)\n", clk_hw_get_name(hw), rate, *prate); -+ return rate; -+} -+ -+static int vop2_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ int div_val; -+ -+ div_val = vop2_div_get_val(rate, parent_rate); -+ vop2_clk->div_val = div_val; -+ -+ // cru_dbg("%s prate: %ld rate: %ld div_val: %d\n", -+ // clk_hw_get_name(hw), parent_rate, rate, div_val); -+ return 0; -+} -+ -+static const struct clk_ops vop2_div_clk_ops = { -+ .recalc_rate = vop2_clk_div_recalc_rate, -+ .round_rate = vop2_clk_div_round_rate, -+ .set_rate = vop2_clk_div_set_rate, -+}; -+ -+static struct clk *vop2_clk_register(struct vop2 *vop2, struct vop2_clk_branch *branch) -+{ -+ struct clk_init_data init = {}; -+ struct vop2_clk *vop2_clk; -+ struct clk *clk; -+ -+ vop2_clk = devm_kzalloc(vop2->dev, sizeof(*vop2_clk), GFP_KERNEL); -+ if (!vop2_clk) -+ return ERR_PTR(-ENOMEM); -+ -+ vop2_clk->vop2 = vop2; -+ vop2_clk->hw.init = &init; -+ vop2_clk->div.shift = branch->div_shift; -+ vop2_clk->div.width = branch->div_width; -+ -+ init.name = branch->name; -+ init.flags = branch->flags; -+ init.num_parents = branch->num_parents; -+ init.parent_names = branch->parent_names; -+ if (branch->branch_type == branch_divider) { -+ init.ops = &vop2_div_clk_ops; -+ } else if (branch->branch_type == branch_virtual) { -+ init.ops = &clk_virtual_ops; -+ init.num_parents = 0; -+ init.parent_names = NULL; -+ } else { -+ init.ops = &vop2_mux_clk_ops; -+ } -+ -+ clk = devm_clk_register(vop2->dev, &vop2_clk->hw); -+ if (!IS_ERR(clk)) -+ list_add_tail(&vop2_clk->list, &vop2->clk_list_head); -+ else -+ DRM_DEV_ERROR(vop2->dev, "Register %s failed\n", branch->name); -+ -+ return clk; -+} -+ -+static int vop2_clk_init(struct vop2 *vop2) -+{ -+ struct vop2_clk_branch *branch = rk3588_vop_clk_branches; -+ unsigned int nr_clk = ARRAY_SIZE(rk3588_vop_clk_branches); -+ unsigned int idx; -+ struct vop2_clk *clk, *n; -+ -+ INIT_LIST_HEAD(&vop2->clk_list_head); -+ -+ if (vop2->data->soc_id < 3588 || vop2->hdmi0_phy_pll == NULL) -+ return 0; -+ -+ list_for_each_entry_safe(clk, n, &vop2->clk_list_head, list) { -+ list_del(&clk->list); -+ } -+ -+ for (idx = 0; idx < nr_clk; idx++, branch++) -+ vop2_clk_register(vop2, branch); -+ -+ return 0; -+} -+/* -+ * END virtual clock -+ */ -+ - static int vop2_bind(struct device *dev, struct device *master, void *data) - { - struct platform_device *pdev = to_platform_device(dev); -@@ -3167,6 +3709,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) - return PTR_ERR(vop2->pclk); - } - -+ vop2->hdmi0_phy_pll = devm_clk_get_optional(vop2->drm->dev, "hdmi0_phy_pll"); -+ if (IS_ERR(vop2->hdmi0_phy_pll)) { -+ DRM_DEV_ERROR(vop2->dev, "failed to get hdmi0_phy_pll source\n"); -+ return PTR_ERR(vop2->hdmi0_phy_pll); -+ } -+ - vop2->irq = platform_get_irq(pdev, 0); - if (vop2->irq < 0) { - drm_err(vop2->drm, "cannot find irq for vop2\n"); -@@ -3183,6 +3731,9 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) - if (ret) - return ret; - -+ // [CC:] rework virtual clock -+ vop2_clk_init(vop2); -+ - ret = vop2_find_rgb_encoder(vop2); - if (ret >= 0) { - vop2->rgb = rockchip_rgb_init(dev, &vop2->vps[ret].crtc, --- -2.44.1 - - -From 63daa1b92854f3c1f7f1c46fac5af1bcf3c103e5 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Mon, 15 Jan 2024 22:47:41 +0200 -Subject: [PATCH 32/54] arm64: dts: rockchip: Add HDMI0 bridge to rk3588 - -Add DT node for the HDMI0 bridge found on RK3588 SoC. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 46 +++++++++++++++++++++++ - 1 file changed, 46 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -index ae3ccafe6871..dd576b87354b 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -@@ -1501,6 +1501,52 @@ i2s9_8ch: i2s@fddfc000 { - status = "disabled"; - }; - -+ hdmi0: hdmi@fde80000 { -+ compatible = "rockchip,rk3588-dw-hdmi"; -+ reg = <0x0 0xfde80000 0x0 0x20000>; -+ interrupts = , -+ , -+ , -+ , -+ ; -+ clocks = <&cru PCLK_HDMITX0>, -+ <&cru CLK_HDMIHDP0>, -+ <&cru CLK_HDMITX0_EARC>, -+ <&cru CLK_HDMITX0_REF>, -+ <&cru MCLK_I2S5_8CH_TX>, -+ <&cru HCLK_VO1>; -+ clock-names = "pclk", -+ "hdp", -+ "earc", -+ "ref", -+ "aud", -+ "hclk_vo1"; -+ resets = <&cru SRST_HDMITX0_REF>, <&cru SRST_HDMIHDP0>; -+ reset-names = "ref", "hdp"; -+ power-domains = <&power RK3588_PD_VO1>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&hdmim0_tx0_cec &hdmim0_tx0_hpd -+ &hdmim0_tx0_scl &hdmim0_tx0_sda>; -+ rockchip,grf = <&sys_grf>; -+ rockchip,vo1_grf = <&vo1_grf>; -+ phys = <&hdptxphy_hdmi0>; -+ phy-names = "hdmi"; -+ status = "disabled"; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ hdmi0_in: port@0 { -+ reg = <0>; -+ }; -+ -+ hdmi0_out: port@1 { -+ reg = <1>; -+ }; -+ }; -+ }; -+ - qos_gpu_m0: qos@fdf35000 { - compatible = "rockchip,rk3588-qos", "syscon"; - reg = <0x0 0xfdf35000 0x0 0x20>; --- -2.44.1 - - -From e2c386a032c2076f06d92da94805185f02252187 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Mon, 15 Jan 2024 22:51:17 +0200 -Subject: [PATCH 33/54] arm64: dts: rockchip: Enable HDMI0 on rock-5b - -Add the necessary DT changes to enable HDMI0 on Rock 5B. - -Signed-off-by: Cristian Ciocaltea ---- - .../boot/dts/rockchip/rk3588-rock-5b.dts | 30 +++++++++++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -index f013d7841e89..cd3fd9cf9402 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -@@ -4,6 +4,7 @@ - - #include - #include -+#include - #include - #include "rk3588.dtsi" - -@@ -196,6 +197,16 @@ &gpu { - status = "okay"; - }; - -+&hdmi0 { -+ status = "okay"; -+}; -+ -+&hdmi0_in { -+ hdmi0_in_vp0: endpoint { -+ remote-endpoint = <&vp0_out_hdmi0>; -+ }; -+}; -+ - &hdmirx_cma { - status = "okay"; - }; -@@ -208,6 +219,10 @@ &hdmirx_ctrler { - memory-region = <&hdmirx_cma>; - }; - -+&hdptxphy_hdmi0 { -+ status = "okay"; -+}; -+ - &i2c0 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c0m2_xfer>; -@@ -969,3 +984,18 @@ &usb_host1_xhci { - &usb_host2_xhci { - status = "okay"; - }; -+ -+&vop_mmu { -+ status = "okay"; -+}; -+ -+&vop { -+ status = "okay"; -+}; -+ -+&vp0 { -+ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { -+ reg = ; -+ remote-endpoint = <&hdmi0_in_vp0>; -+ }; -+}; --- -2.44.1 - - -From f6c1ee98ba1c9dd9f92428ada473c2119a66079b Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Wed, 17 Jan 2024 01:53:38 +0200 -Subject: [PATCH 34/54] arm64: dts: rockchip: Enable HDMI0 on rk3588-evb1 - -Add the necessary DT changes to enable HDMI0 on Rockchip RK3588 EVB1. - -Signed-off-by: Cristian Ciocaltea ---- - .../boot/dts/rockchip/rk3588-evb1-v10.dts | 30 +++++++++++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -index dd2fb2515900..e172647ba058 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -@@ -9,6 +9,7 @@ - #include - #include - #include -+#include - #include - #include "rk3588.dtsi" - -@@ -342,6 +343,20 @@ &gpu { - status = "okay"; - }; - -+&hdmi0 { -+ status = "okay"; -+}; -+ -+&hdmi0_in { -+ hdmi0_in_vp0: endpoint { -+ remote-endpoint = <&vp0_out_hdmi0>; -+ }; -+}; -+ -+&hdptxphy_hdmi0 { -+ status = "okay"; -+}; -+ - &i2c2 { - status = "okay"; - -@@ -1336,3 +1351,18 @@ &usb_host1_xhci { - dr_mode = "host"; - status = "okay"; - }; -+ -+&vop_mmu { -+ status = "okay"; -+}; -+ -+&vop { -+ status = "okay"; -+}; -+ -+&vp0 { -+ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { -+ reg = ; -+ remote-endpoint = <&hdmi0_in_vp0>; -+ }; -+}; --- -2.44.1 - - -From 15af3f84555104275cf534724431641a9763d172 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Tue, 16 Jan 2024 03:13:38 +0200 -Subject: [PATCH 35/54] [WIP] arm64: dts: rockchip: Enable HDMI0 PHY clk - provider on rk3588 - -The HDMI0 PHY can be used as a clock provider on RK3588, hence add the -missing #clock-cells property. ---- - arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -index dd576b87354b..eb1aa7d8e475 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -@@ -2954,6 +2954,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>, --- -2.44.1 - - -From c490fa08603e50bd609a6c47c7f1d0fa3b53b268 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Fri, 3 Nov 2023 20:05:05 +0200 -Subject: [PATCH 36/54] [WIP] arm64: dts: rockchip: Make use of HDMI0 PHY PLL - on rock-5b - -The initial vop2 support for rk3588 in mainline is not able to handle -all display modes supported by connected displays, e.g. -2560x1440-75.00Hz, 2048x1152-60.00Hz, 1024x768-60.00Hz. - -Additionally, it doesn't cope with non-integer refresh rates like 59.94, -29.97, 23.98, etc. - -Make use of the HDMI0 PHY PLL to support the additional display modes. - -Note this requires commit "drm/rockchip: vop2: Improve display modes -handling on rk3588", which needs a rework to be upstreamable. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -index cd3fd9cf9402..c551b676860c 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -@@ -192,6 +192,11 @@ &cpu_l3 { - cpu-supply = <&vdd_cpu_lit_s0>; - }; - -+&display_subsystem { -+ clocks = <&hdptxphy_hdmi0>; -+ clock-names = "hdmi0_phy_pll"; -+}; -+ - &gpu { - mali-supply = <&vdd_gpu_s0>; - status = "okay"; --- -2.44.1 - - -From c7b836ef5634362651e8ce268962156c852cca26 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Wed, 17 Jan 2024 02:00:41 +0200 -Subject: [PATCH 37/54] [WIP] arm64: dts: rockchip: Make use of HDMI0 PHY PLL - on rk3588-evb1 - -The initial vop2 support for rk3588 in mainline is not able to handle -all display modes supported by connected displays, e.g. -2560x1440-75.00Hz, 2048x1152-60.00Hz, 1024x768-60.00Hz. - -Additionally, it doesn't cope with non-integer refresh rates like 59.94, -29.97, 23.98, etc. - -Make use of the HDMI0 PHY PLL to support the additional display modes. - -Note this requires commit "drm/rockchip: vop2: Improve display modes -handling on rk3588", which needs a rework to be upstreamable. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -index e172647ba058..cb3925d6c7ba 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -@@ -322,6 +322,11 @@ &cpu_l3 { - cpu-supply = <&vdd_cpu_lit_s0>; - }; - -+&display_subsystem { -+ clocks = <&hdptxphy_hdmi0>; -+ clock-names = "hdmi0_phy_pll"; -+}; -+ - &gmac0 { - clock_in_out = "output"; - phy-handle = <&rgmii_phy>; --- -2.44.1 - - -From 3ca942418bedc7a8a28ed1ee8f4c92bdabf1e378 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 18 May 2024 02:49:30 +0300 -Subject: [PATCH 38/54] drm/bridge: dw-hdmi: Simplify clock handling - -Make use of devm_clk_get_enabled() to replace devm_clk_get() and -clk_prepare_enable() for isfr and iahb clocks, and drop the now -unnecessary calls to clk_disable_unprepare(). - -Similarly, use devm_clk_get_optional_enabled() helper for cec clock, -which additionally allows to remove the -ENOENT test. - -Moreover, the clock related members of struct dw_hdmi are not required -anymore, hence drop them. - -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 66 ++++++----------------- - 1 file changed, 16 insertions(+), 50 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 9f2bc932c371..0031f3c54882 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -138,9 +138,6 @@ struct dw_hdmi { - struct platform_device *audio; - struct platform_device *cec; - struct device *dev; -- struct clk *isfr_clk; -- struct clk *iahb_clk; -- struct clk *cec_clk; - struct dw_hdmi_i2c *i2c; - - struct hdmi_data_info hdmi_data; -@@ -3326,6 +3323,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, - struct device_node *ddc_node; - struct dw_hdmi_cec_data cec; - struct dw_hdmi *hdmi; -+ struct clk *clk; - struct resource *iores = NULL; - int irq; - int ret; -@@ -3405,50 +3403,27 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, - hdmi->regm = plat_data->regm; - } - -- hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); -- if (IS_ERR(hdmi->isfr_clk)) { -- ret = PTR_ERR(hdmi->isfr_clk); -+ clk = devm_clk_get_enabled(hdmi->dev, "isfr"); -+ if (IS_ERR(clk)) { -+ ret = PTR_ERR(clk); - dev_err(hdmi->dev, "Unable to get HDMI isfr clk: %d\n", ret); - goto err_res; - } - -- ret = clk_prepare_enable(hdmi->isfr_clk); -- if (ret) { -- dev_err(hdmi->dev, "Cannot enable HDMI isfr clock: %d\n", ret); -- goto err_res; -- } -- -- hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb"); -- if (IS_ERR(hdmi->iahb_clk)) { -- ret = PTR_ERR(hdmi->iahb_clk); -+ clk = devm_clk_get_enabled(hdmi->dev, "iahb"); -+ if (IS_ERR(clk)) { -+ ret = PTR_ERR(clk); - dev_err(hdmi->dev, "Unable to get HDMI iahb clk: %d\n", ret); -- goto err_isfr; -- } -- -- ret = clk_prepare_enable(hdmi->iahb_clk); -- if (ret) { -- dev_err(hdmi->dev, "Cannot enable HDMI iahb clock: %d\n", ret); -- goto err_isfr; -+ goto err_res; - } - -- hdmi->cec_clk = devm_clk_get(hdmi->dev, "cec"); -- if (PTR_ERR(hdmi->cec_clk) == -ENOENT) { -- hdmi->cec_clk = NULL; -- } else if (IS_ERR(hdmi->cec_clk)) { -- ret = PTR_ERR(hdmi->cec_clk); -+ clk = devm_clk_get_optional_enabled(hdmi->dev, "cec"); -+ if (IS_ERR(clk)) { -+ ret = PTR_ERR(clk); - if (ret != -EPROBE_DEFER) - dev_err(hdmi->dev, "Cannot get HDMI cec clock: %d\n", - ret); -- -- hdmi->cec_clk = NULL; -- goto err_iahb; -- } else { -- ret = clk_prepare_enable(hdmi->cec_clk); -- if (ret) { -- dev_err(hdmi->dev, "Cannot enable HDMI cec clock: %d\n", -- ret); -- goto err_iahb; -- } -+ goto err_res; - } - - /* Product and revision IDs */ -@@ -3462,12 +3437,12 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, - dev_err(dev, "Unsupported HDMI controller (%04x:%02x:%02x)\n", - hdmi->version, prod_id0, prod_id1); - ret = -ENODEV; -- goto err_iahb; -+ goto err_res; - } - - ret = dw_hdmi_detect_phy(hdmi); - if (ret < 0) -- goto err_iahb; -+ goto err_res; - - dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n", - hdmi->version >> 12, hdmi->version & 0xfff, -@@ -3479,14 +3454,14 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; -- goto err_iahb; -+ goto err_res; - } - - ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq, - dw_hdmi_irq, IRQF_SHARED, - dev_name(dev), hdmi); - if (ret) -- goto err_iahb; -+ goto err_res; - - /* - * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator -@@ -3603,11 +3578,6 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, - - return hdmi; - --err_iahb: -- clk_disable_unprepare(hdmi->iahb_clk); -- clk_disable_unprepare(hdmi->cec_clk); --err_isfr: -- clk_disable_unprepare(hdmi->isfr_clk); - err_res: - i2c_put_adapter(hdmi->ddc); - -@@ -3627,10 +3597,6 @@ void dw_hdmi_remove(struct dw_hdmi *hdmi) - /* Disable all interrupts */ - hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); - -- clk_disable_unprepare(hdmi->iahb_clk); -- clk_disable_unprepare(hdmi->isfr_clk); -- clk_disable_unprepare(hdmi->cec_clk); -- - if (hdmi->i2c) - i2c_del_adapter(&hdmi->i2c->adap); - else --- -2.44.1 - - -From 03f4db37d31eb559828bec3f1bd5abcee19d843b Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Wed, 24 Apr 2024 14:35:06 +0300 -Subject: [PATCH 39/54] drm/bridge: dw-hdmi: Move common data to separate - header - -In preparation to add support for the HDMI 2.1 Quad-Pixel TX Controller, -move structs and common function declarations to a new dw-hdmi-common.h -header file. - -Signed-off-by: Cristian Ciocaltea ---- - .../gpu/drm/bridge/synopsys/dw-hdmi-common.h | 166 +++++++++++++++++ - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 170 +++--------------- - 2 files changed, 193 insertions(+), 143 deletions(-) - create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -new file mode 100644 -index 000000000000..9182564278e4 ---- /dev/null -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -@@ -0,0 +1,166 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+#ifndef __DW_HDMI_COMMON_H__ -+#define __DW_HDMI_COMMON_H__ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+struct cec_notifier; -+struct device; -+struct drm_bridge_state; -+struct drm_crtc_state; -+struct drm_edid; -+struct pinctrl; -+struct pinctrl_state; -+struct platform_device; -+struct regmap; -+ -+#define DDC_CI_ADDR 0x37 -+#define DDC_SEGMENT_ADDR 0x30 -+ -+#define HDMI_EDID_LEN 512 -+ -+/* DW-HDMI Controller >= 0x200a are at least compliant with SCDC version 1 */ -+#define SCDC_MIN_SOURCE_VERSION 0x1 -+ -+#define HDMI14_MAX_TMDSCLK 340000000 -+ -+struct hdmi_vmode { -+ bool mdataenablepolarity; -+ -+ unsigned int mpixelclock; -+ unsigned int mpixelrepetitioninput; -+ unsigned int mpixelrepetitionoutput; -+ unsigned int mtmdsclock; -+}; -+ -+struct hdmi_data_info { -+ unsigned int enc_in_bus_format; -+ unsigned int enc_out_bus_format; -+ unsigned int enc_in_encoding; -+ unsigned int enc_out_encoding; -+ unsigned int pix_repet_factor; -+ unsigned int hdcp_enable; -+ struct hdmi_vmode video_mode; -+ bool rgb_limited_range; -+}; -+ -+struct dw_hdmi_i2c { -+ struct i2c_adapter adap; -+ -+ struct mutex lock; /* used to serialize data transfers */ -+ struct completion cmp; -+ u8 stat; -+ -+ u8 slave_reg; -+ bool is_regaddr; -+ bool is_segment; -+}; -+ -+struct dw_hdmi_phy_data { -+ enum dw_hdmi_phy_type type; -+ const char *name; -+ unsigned int gen; -+ bool has_svsret; -+ int (*configure)(struct dw_hdmi *hdmi, -+ const struct dw_hdmi_plat_data *pdata, -+ unsigned long mpixelclock); -+}; -+ -+struct dw_hdmi { -+ struct drm_connector connector; -+ struct drm_bridge bridge; -+ struct drm_bridge *next_bridge; -+ -+ unsigned int version; -+ -+ struct platform_device *audio; -+ struct platform_device *cec; -+ struct device *dev; -+ struct dw_hdmi_i2c *i2c; -+ -+ struct hdmi_data_info hdmi_data; -+ const struct dw_hdmi_plat_data *plat_data; -+ -+ int vic; -+ -+ u8 edid[HDMI_EDID_LEN]; -+ -+ struct { -+ const struct dw_hdmi_phy_ops *ops; -+ const char *name; -+ void *data; -+ bool enabled; -+ } phy; -+ -+ struct drm_display_mode previous_mode; -+ -+ struct i2c_adapter *ddc; -+ void __iomem *regs; -+ bool sink_is_hdmi; -+ bool sink_has_audio; -+ -+ struct pinctrl *pinctrl; -+ struct pinctrl_state *default_state; -+ struct pinctrl_state *unwedge_state; -+ -+ struct mutex mutex; /* for state below and previous_mode */ -+ enum drm_connector_force force; /* mutex-protected force state */ -+ struct drm_connector *curr_conn;/* current connector (only valid when !disabled) */ -+ bool disabled; /* DRM has disabled our bridge */ -+ bool bridge_is_on; /* indicates the bridge is on */ -+ bool rxsense; /* rxsense state */ -+ u8 phy_mask; /* desired phy int mask settings */ -+ u8 mc_clkdis; /* clock disable register */ -+ -+ spinlock_t audio_lock; -+ struct mutex audio_mutex; -+ unsigned int sample_non_pcm; -+ unsigned int sample_width; -+ unsigned int sample_rate; -+ unsigned int channels; -+ unsigned int audio_cts; -+ unsigned int audio_n; -+ bool audio_enable; -+ -+ unsigned int reg_shift; -+ struct regmap *regm; -+ void (*enable_audio)(struct dw_hdmi *hdmi); -+ void (*disable_audio)(struct dw_hdmi *hdmi); -+ -+ struct mutex cec_notifier_mutex; -+ struct cec_notifier *cec_notifier; -+ -+ hdmi_codec_plugged_cb plugged_cb; -+ struct device *codec_dev; -+ enum drm_connector_status last_connector_result; -+}; -+ -+void dw_handle_plugged_change(struct dw_hdmi *hdmi, bool plugged); -+bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi, -+ const struct drm_display_info *display); -+ -+enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector *connector, -+ bool force); -+ -+int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge, -+ struct drm_bridge_state *bridge_state, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state); -+void dw_hdmi_bridge_detach(struct drm_bridge *bridge); -+void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, -+ const struct drm_display_mode *orig_mode, -+ const struct drm_display_mode *mode); -+enum drm_connector_status dw_hdmi_bridge_detect(struct drm_bridge *bridge); -+const struct drm_edid *dw_hdmi_bridge_edid_read(struct drm_bridge *bridge, -+ struct drm_connector *connector); -+#endif /* __DW_HDMI_COMMON_H__ */ -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 0031f3c54882..b66877771f56 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -10,10 +10,8 @@ - #include - #include - #include --#include - #include - #include --#include - #include - #include - #include -@@ -25,12 +23,10 @@ - #include - #include - --#include - #include - #include - #include - #include --#include - #include - #include - #include -@@ -38,18 +34,9 @@ - - #include "dw-hdmi-audio.h" - #include "dw-hdmi-cec.h" -+#include "dw-hdmi-common.h" - #include "dw-hdmi.h" - --#define DDC_CI_ADDR 0x37 --#define DDC_SEGMENT_ADDR 0x30 -- --#define HDMI_EDID_LEN 512 -- --/* DW-HDMI Controller >= 0x200a are at least compliant with SCDC version 1 */ --#define SCDC_MIN_SOURCE_VERSION 0x1 -- --#define HDMI14_MAX_TMDSCLK 340000000 -- - static const u16 csc_coeff_default[3][4] = { - { 0x2000, 0x0000, 0x0000, 0x0000 }, - { 0x0000, 0x2000, 0x0000, 0x0000 }, -@@ -86,117 +73,6 @@ static const u16 csc_coeff_rgb_full_to_rgb_limited[3][4] = { - { 0x0000, 0x0000, 0x1b7c, 0x0020 } - }; - --struct hdmi_vmode { -- bool mdataenablepolarity; -- -- unsigned int mpixelclock; -- unsigned int mpixelrepetitioninput; -- unsigned int mpixelrepetitionoutput; -- unsigned int mtmdsclock; --}; -- --struct hdmi_data_info { -- unsigned int enc_in_bus_format; -- unsigned int enc_out_bus_format; -- unsigned int enc_in_encoding; -- unsigned int enc_out_encoding; -- unsigned int pix_repet_factor; -- unsigned int hdcp_enable; -- struct hdmi_vmode video_mode; -- bool rgb_limited_range; --}; -- --struct dw_hdmi_i2c { -- struct i2c_adapter adap; -- -- struct mutex lock; /* used to serialize data transfers */ -- struct completion cmp; -- u8 stat; -- -- u8 slave_reg; -- bool is_regaddr; -- bool is_segment; --}; -- --struct dw_hdmi_phy_data { -- enum dw_hdmi_phy_type type; -- const char *name; -- unsigned int gen; -- bool has_svsret; -- int (*configure)(struct dw_hdmi *hdmi, -- const struct dw_hdmi_plat_data *pdata, -- unsigned long mpixelclock); --}; -- --struct dw_hdmi { -- struct drm_connector connector; -- struct drm_bridge bridge; -- struct drm_bridge *next_bridge; -- -- unsigned int version; -- -- struct platform_device *audio; -- struct platform_device *cec; -- struct device *dev; -- struct dw_hdmi_i2c *i2c; -- -- struct hdmi_data_info hdmi_data; -- const struct dw_hdmi_plat_data *plat_data; -- -- int vic; -- -- u8 edid[HDMI_EDID_LEN]; -- -- struct { -- const struct dw_hdmi_phy_ops *ops; -- const char *name; -- void *data; -- bool enabled; -- } phy; -- -- struct drm_display_mode previous_mode; -- -- struct i2c_adapter *ddc; -- void __iomem *regs; -- bool sink_is_hdmi; -- bool sink_has_audio; -- -- struct pinctrl *pinctrl; -- struct pinctrl_state *default_state; -- struct pinctrl_state *unwedge_state; -- -- struct mutex mutex; /* for state below and previous_mode */ -- enum drm_connector_force force; /* mutex-protected force state */ -- struct drm_connector *curr_conn;/* current connector (only valid when !disabled) */ -- bool disabled; /* DRM has disabled our bridge */ -- bool bridge_is_on; /* indicates the bridge is on */ -- bool rxsense; /* rxsense state */ -- u8 phy_mask; /* desired phy int mask settings */ -- u8 mc_clkdis; /* clock disable register */ -- -- spinlock_t audio_lock; -- struct mutex audio_mutex; -- unsigned int sample_non_pcm; -- unsigned int sample_width; -- unsigned int sample_rate; -- unsigned int channels; -- unsigned int audio_cts; -- unsigned int audio_n; -- bool audio_enable; -- -- unsigned int reg_shift; -- struct regmap *regm; -- void (*enable_audio)(struct dw_hdmi *hdmi); -- void (*disable_audio)(struct dw_hdmi *hdmi); -- -- struct mutex cec_notifier_mutex; -- struct cec_notifier *cec_notifier; -- -- hdmi_codec_plugged_cb plugged_cb; -- struct device *codec_dev; -- enum drm_connector_status last_connector_result; --}; -- - #define HDMI_IH_PHY_STAT0_RX_SENSE \ - (HDMI_IH_PHY_STAT0_RX_SENSE0 | HDMI_IH_PHY_STAT0_RX_SENSE1 | \ - HDMI_IH_PHY_STAT0_RX_SENSE2 | HDMI_IH_PHY_STAT0_RX_SENSE3) -@@ -219,11 +95,12 @@ static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset) - return val; - } - --static void handle_plugged_change(struct dw_hdmi *hdmi, bool plugged) -+void dw_handle_plugged_change(struct dw_hdmi *hdmi, bool plugged) - { - if (hdmi->plugged_cb && hdmi->codec_dev) - hdmi->plugged_cb(hdmi->codec_dev, plugged); - } -+EXPORT_SYMBOL_GPL(dw_handle_plugged_change); - - int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn, - struct device *codec_dev) -@@ -234,7 +111,7 @@ int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn, - hdmi->plugged_cb = fn; - hdmi->codec_dev = codec_dev; - plugged = hdmi->last_connector_result == connector_status_connected; -- handle_plugged_change(hdmi, plugged); -+ dw_handle_plugged_change(hdmi, plugged); - mutex_unlock(&hdmi->mutex); - - return 0; -@@ -1361,8 +1238,8 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, - EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write); - - /* Filter out invalid setups to avoid configuring SCDC and scrambling */ --static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi, -- const struct drm_display_info *display) -+bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi, -+ const struct drm_display_info *display) - { - /* Completely disable SCDC support for older controllers */ - if (hdmi->version < 0x200a) -@@ -1387,6 +1264,7 @@ static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi, - - return true; - } -+EXPORT_SYMBOL_GPL(dw_hdmi_support_scdc); - - /* - * HDMI2.0 Specifies the following procedure for High TMDS Bit Rates: -@@ -2486,13 +2364,14 @@ static const struct drm_edid *dw_hdmi_edid_read(struct dw_hdmi *hdmi, - * DRM Connector Operations - */ - --static enum drm_connector_status -+enum drm_connector_status - dw_hdmi_connector_detect(struct drm_connector *connector, bool force) - { - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, - connector); - return dw_hdmi_detect(hdmi); - } -+EXPORT_SYMBOL_GPL(dw_hdmi_connector_detect); - - static int dw_hdmi_connector_get_modes(struct drm_connector *connector) - { -@@ -2868,10 +2747,10 @@ static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, - return input_fmts; - } - --static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge, -- struct drm_bridge_state *bridge_state, -- struct drm_crtc_state *crtc_state, -- struct drm_connector_state *conn_state) -+int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge, -+ struct drm_bridge_state *bridge_state, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state) - { - struct dw_hdmi *hdmi = bridge->driver_private; - -@@ -2887,6 +2766,7 @@ static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge, - - return 0; - } -+EXPORT_SYMBOL_GPL(dw_hdmi_bridge_atomic_check); - - static int dw_hdmi_bridge_attach(struct drm_bridge *bridge, - enum drm_bridge_attach_flags flags) -@@ -2900,7 +2780,7 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge, - return dw_hdmi_connector_create(hdmi); - } - --static void dw_hdmi_bridge_detach(struct drm_bridge *bridge) -+void dw_hdmi_bridge_detach(struct drm_bridge *bridge) - { - struct dw_hdmi *hdmi = bridge->driver_private; - -@@ -2909,6 +2789,7 @@ static void dw_hdmi_bridge_detach(struct drm_bridge *bridge) - hdmi->cec_notifier = NULL; - mutex_unlock(&hdmi->cec_notifier_mutex); - } -+EXPORT_SYMBOL_GPL(dw_hdmi_bridge_detach); - - static enum drm_mode_status - dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, -@@ -2930,9 +2811,9 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, - return mode_status; - } - --static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, -- const struct drm_display_mode *orig_mode, -- const struct drm_display_mode *mode) -+void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, -+ const struct drm_display_mode *orig_mode, -+ const struct drm_display_mode *mode) - { - struct dw_hdmi *hdmi = bridge->driver_private; - -@@ -2943,6 +2824,7 @@ static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, - - mutex_unlock(&hdmi->mutex); - } -+EXPORT_SYMBOL_GPL(dw_hdmi_bridge_mode_set); - - static void dw_hdmi_bridge_atomic_disable(struct drm_bridge *bridge, - struct drm_bridge_state *old_state) -@@ -2954,7 +2836,7 @@ static void dw_hdmi_bridge_atomic_disable(struct drm_bridge *bridge, - hdmi->curr_conn = NULL; - dw_hdmi_update_power(hdmi); - dw_hdmi_update_phy_mask(hdmi); -- handle_plugged_change(hdmi, false); -+ dw_handle_plugged_change(hdmi, false); - mutex_unlock(&hdmi->mutex); - } - -@@ -2973,24 +2855,26 @@ static void dw_hdmi_bridge_atomic_enable(struct drm_bridge *bridge, - hdmi->curr_conn = connector; - dw_hdmi_update_power(hdmi); - dw_hdmi_update_phy_mask(hdmi); -- handle_plugged_change(hdmi, true); -+ dw_handle_plugged_change(hdmi, true); - mutex_unlock(&hdmi->mutex); - } - --static enum drm_connector_status dw_hdmi_bridge_detect(struct drm_bridge *bridge) -+enum drm_connector_status dw_hdmi_bridge_detect(struct drm_bridge *bridge) - { - struct dw_hdmi *hdmi = bridge->driver_private; - - return dw_hdmi_detect(hdmi); - } -+EXPORT_SYMBOL_GPL(dw_hdmi_bridge_detect); - --static const struct drm_edid *dw_hdmi_bridge_edid_read(struct drm_bridge *bridge, -- struct drm_connector *connector) -+const struct drm_edid *dw_hdmi_bridge_edid_read(struct drm_bridge *bridge, -+ struct drm_connector *connector) - { - struct dw_hdmi *hdmi = bridge->driver_private; - - return dw_hdmi_edid_read(hdmi, connector); - } -+EXPORT_SYMBOL_GPL(dw_hdmi_bridge_edid_read); - - static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { - .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, --- -2.44.1 - - -From 69b642c3b37d51e9022633382f7834479d34e0e1 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Tue, 30 Apr 2024 12:48:34 +0300 -Subject: [PATCH 40/54] drm/bridge: dw-hdmi: Commonize dw_hdmi_i2c_adapter() - -In preparation to support DW HDMI QP variant, add a new parameter to -dw_hdmi_i2c_adapter() which allows using a different i2c_algorithm and -move the function to the common header. - -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h | 2 ++ - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 +++++--- - 2 files changed, 7 insertions(+), 3 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -index 9182564278e4..a83c2873854c 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -@@ -146,6 +146,8 @@ struct dw_hdmi { - }; - - void dw_handle_plugged_change(struct dw_hdmi *hdmi, bool plugged); -+struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi, -+ const struct i2c_algorithm *algo); - bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi, - const struct drm_display_info *display); - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index b66877771f56..5dd0e2bc080d 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -376,7 +376,8 @@ static const struct i2c_algorithm dw_hdmi_algorithm = { - .functionality = dw_hdmi_i2c_func, - }; - --static struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi) -+struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi, -+ const struct i2c_algorithm *algo) - { - struct i2c_adapter *adap; - struct dw_hdmi_i2c *i2c; -@@ -392,7 +393,7 @@ static struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi) - adap = &i2c->adap; - adap->owner = THIS_MODULE; - adap->dev.parent = hdmi->dev; -- adap->algo = &dw_hdmi_algorithm; -+ adap->algo = algo ? algo : &dw_hdmi_algorithm; - strscpy(adap->name, "DesignWare HDMI", sizeof(adap->name)); - i2c_set_adapdata(adap, hdmi); - -@@ -409,6 +410,7 @@ static struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi) - - return adap; - } -+EXPORT_SYMBOL_GPL(dw_hdmi_i2c_adapter); - - static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts, - unsigned int n) -@@ -3373,7 +3375,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, - } - } - -- hdmi->ddc = dw_hdmi_i2c_adapter(hdmi); -+ hdmi->ddc = dw_hdmi_i2c_adapter(hdmi, NULL); - if (IS_ERR(hdmi->ddc)) - hdmi->ddc = NULL; - } --- -2.44.1 - - -From 2a111c90c36baf2529bf90669a2fed0d33753a0b Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Tue, 30 Apr 2024 13:06:11 +0300 -Subject: [PATCH 41/54] drm/bridge: dw-hdmi: Commonize AVI infoframe setup - -In preparation to support DW HDMI QP variant and minimize code -duplication, split hdmi_config_AVI() into a common -dw_hdmi_prep_avi_infoframe() function to be shared by the two drivers. - -Signed-off-by: Cristian Ciocaltea ---- - .../gpu/drm/bridge/synopsys/dw-hdmi-common.h | 4 ++ - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 57 +++++++++++-------- - 2 files changed, 37 insertions(+), 24 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -index a83c2873854c..d34c979a48cd 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -@@ -150,6 +150,10 @@ struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi, - const struct i2c_algorithm *algo); - bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi, - const struct drm_display_info *display); -+void dw_hdmi_prep_avi_infoframe(struct hdmi_avi_infoframe *frame, -+ struct dw_hdmi *hdmi, -+ const struct drm_connector *connector, -+ const struct drm_display_mode *mode); - - enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector *connector, - bool force); -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 5dd0e2bc080d..81d73fbcb2e6 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -1638,66 +1638,75 @@ static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi) - HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1); - } - --static void hdmi_config_AVI(struct dw_hdmi *hdmi, -- const struct drm_connector *connector, -- const struct drm_display_mode *mode) -+void dw_hdmi_prep_avi_infoframe(struct hdmi_avi_infoframe *frame, -+ struct dw_hdmi *hdmi, -+ const struct drm_connector *connector, -+ const struct drm_display_mode *mode) - { -- struct hdmi_avi_infoframe frame; -- u8 val; -- - /* Initialise info frame from DRM mode */ -- drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); -+ drm_hdmi_avi_infoframe_from_display_mode(frame, connector, mode); - - if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) { -- drm_hdmi_avi_infoframe_quant_range(&frame, connector, mode, -+ drm_hdmi_avi_infoframe_quant_range(frame, connector, mode, - hdmi->hdmi_data.rgb_limited_range ? - HDMI_QUANTIZATION_RANGE_LIMITED : - HDMI_QUANTIZATION_RANGE_FULL); - } else { -- frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; -- frame.ycc_quantization_range = -+ frame->quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; -+ frame->ycc_quantization_range = - HDMI_YCC_QUANTIZATION_RANGE_LIMITED; - } - - if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) -- frame.colorspace = HDMI_COLORSPACE_YUV444; -+ frame->colorspace = HDMI_COLORSPACE_YUV444; - else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) -- frame.colorspace = HDMI_COLORSPACE_YUV422; -+ frame->colorspace = HDMI_COLORSPACE_YUV422; - else if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) -- frame.colorspace = HDMI_COLORSPACE_YUV420; -+ frame->colorspace = HDMI_COLORSPACE_YUV420; - else -- frame.colorspace = HDMI_COLORSPACE_RGB; -+ frame->colorspace = HDMI_COLORSPACE_RGB; - - /* Set up colorimetry */ - if (!hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) { - switch (hdmi->hdmi_data.enc_out_encoding) { - case V4L2_YCBCR_ENC_601: - if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601) -- frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; -+ frame->colorimetry = HDMI_COLORIMETRY_EXTENDED; - else -- frame.colorimetry = HDMI_COLORIMETRY_ITU_601; -- frame.extended_colorimetry = -+ frame->colorimetry = HDMI_COLORIMETRY_ITU_601; -+ frame->extended_colorimetry = - HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - break; - case V4L2_YCBCR_ENC_709: - if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709) -- frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; -+ frame->colorimetry = HDMI_COLORIMETRY_EXTENDED; - else -- frame.colorimetry = HDMI_COLORIMETRY_ITU_709; -- frame.extended_colorimetry = -+ frame->colorimetry = HDMI_COLORIMETRY_ITU_709; -+ frame->extended_colorimetry = - HDMI_EXTENDED_COLORIMETRY_XV_YCC_709; - break; - default: /* Carries no data */ -- frame.colorimetry = HDMI_COLORIMETRY_ITU_601; -- frame.extended_colorimetry = -+ frame->colorimetry = HDMI_COLORIMETRY_ITU_601; -+ frame->extended_colorimetry = - HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - break; - } - } else { -- frame.colorimetry = HDMI_COLORIMETRY_NONE; -- frame.extended_colorimetry = -+ frame->colorimetry = HDMI_COLORIMETRY_NONE; -+ frame->extended_colorimetry = - HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - } -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_prep_avi_infoframe); -+ -+static void hdmi_config_AVI(struct dw_hdmi *hdmi, -+ const struct drm_connector *connector, -+ const struct drm_display_mode *mode) -+{ -+ struct hdmi_avi_infoframe frame; -+ u8 val; -+ -+ dw_hdmi_prep_avi_infoframe(&frame, hdmi, connector, mode); - - /* - * The Designware IP uses a different byte format from standard --- -2.44.1 - - -From ae857523d29c06985e85bed4e5b5477d5757ed6c Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Tue, 30 Apr 2024 21:47:36 +0300 -Subject: [PATCH 42/54] drm/bridge: dw-hdmi: Commonize vmode setup - -In preparation to support DW HDMI QP variant and minimize code -duplication, split hdmi_av_composer() into a common dw_hdmi_prep_vmode() -function to be shared by the two drivers. - -Signed-off-by: Cristian Ciocaltea ---- - .../gpu/drm/bridge/synopsys/dw-hdmi-common.h | 2 ++ - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 23 +++++++++++++------ - 2 files changed, 18 insertions(+), 7 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -index d34c979a48cd..b594be2c6337 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -@@ -154,6 +154,8 @@ void dw_hdmi_prep_avi_infoframe(struct hdmi_avi_infoframe *frame, - struct dw_hdmi *hdmi, - const struct drm_connector *connector, - const struct drm_display_mode *mode); -+struct hdmi_vmode *dw_hdmi_prep_vmode(struct dw_hdmi *hdmi, -+ const struct drm_display_mode *mode); - - enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector *connector, - bool force); -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 81d73fbcb2e6..5cf929f68ae9 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -1864,15 +1864,10 @@ static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi, - HDMI_FC_PACKET_TX_EN_DRM_MASK, HDMI_FC_PACKET_TX_EN); - } - --static void hdmi_av_composer(struct dw_hdmi *hdmi, -- const struct drm_display_info *display, -- const struct drm_display_mode *mode) -+struct hdmi_vmode *dw_hdmi_prep_vmode(struct dw_hdmi *hdmi, -+ const struct drm_display_mode *mode) - { -- u8 inv_val, bytes; -- const struct drm_hdmi_info *hdmi_info = &display->hdmi; - struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode; -- int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len; -- unsigned int vdisplay, hdisplay; - - vmode->mpixelclock = mode->clock * 1000; - -@@ -1900,6 +1895,20 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, - - dev_dbg(hdmi->dev, "final tmdsclock = %d\n", vmode->mtmdsclock); - -+ return vmode; -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_prep_vmode); -+ -+static void hdmi_av_composer(struct dw_hdmi *hdmi, -+ const struct drm_display_info *display, -+ const struct drm_display_mode *mode) -+{ -+ u8 inv_val, bytes; -+ const struct drm_hdmi_info *hdmi_info = &display->hdmi; -+ struct hdmi_vmode *vmode = dw_hdmi_prep_vmode(hdmi, mode); -+ int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len; -+ unsigned int vdisplay, hdisplay; -+ - /* Set up HDMI_FC_INVIDCONF */ - inv_val = (hdmi->hdmi_data.hdcp_enable || - (dw_hdmi_support_scdc(hdmi, display) && --- -2.44.1 - - -From d26a864cd352b0fa251f5ef4298da27190e32b4c Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Tue, 30 Apr 2024 23:51:06 +0300 -Subject: [PATCH 43/54] drm/bridge: dw-hdmi: Commonize hdmi_data_info setup - -In preparation to support DW HDMI QP variant and minimize code -duplication, split dw_hdmi_setup() into a common dw_hdmi_prep_data() -function to be shared by the two drivers. - -Signed-off-by: Cristian Ciocaltea ---- - .../gpu/drm/bridge/synopsys/dw-hdmi-common.h | 2 ++ - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 22 +++++++++++++------ - 2 files changed, 17 insertions(+), 7 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -index b594be2c6337..b4ad71639ffa 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -@@ -156,6 +156,8 @@ void dw_hdmi_prep_avi_infoframe(struct hdmi_avi_infoframe *frame, - const struct drm_display_mode *mode); - struct hdmi_vmode *dw_hdmi_prep_vmode(struct dw_hdmi *hdmi, - const struct drm_display_mode *mode); -+void dw_hdmi_prep_data(struct dw_hdmi *hdmi, -+ const struct drm_display_mode *mode); - - enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector *connector, - bool force); -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 5cf929f68ae9..a9053b0d5f54 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -2133,14 +2133,9 @@ static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) - HDMI_IH_MUTE_FC_STAT2); - } - --static int dw_hdmi_setup(struct dw_hdmi *hdmi, -- const struct drm_connector *connector, -- const struct drm_display_mode *mode) -+void dw_hdmi_prep_data(struct dw_hdmi *hdmi, -+ const struct drm_display_mode *mode) - { -- int ret; -- -- hdmi_disable_overflow_interrupts(hdmi); -- - hdmi->vic = drm_match_cea_mode(mode); - - if (!hdmi->vic) { -@@ -2180,6 +2175,19 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, - hdmi->hdmi_data.pix_repet_factor = 0; - hdmi->hdmi_data.hdcp_enable = 0; - hdmi->hdmi_data.video_mode.mdataenablepolarity = true; -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_prep_data); -+ -+ -+static int dw_hdmi_setup(struct dw_hdmi *hdmi, -+ const struct drm_connector *connector, -+ const struct drm_display_mode *mode) -+{ -+ int ret; -+ -+ hdmi_disable_overflow_interrupts(hdmi); -+ -+ dw_hdmi_prep_data(hdmi, mode); - - /* HDMI Initialization Step B.1 */ - hdmi_av_composer(hdmi, &connector->display_info, mode); --- -2.44.1 - - -From b41dc7e05fe0f33cffe74ffda9b1f980afa2849c Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Wed, 1 May 2024 01:46:51 +0300 -Subject: [PATCH 44/54] drm/bridge: dw-hdmi: Commonize - dw_hdmi_connector_create() - -In preparation to support DW HDMI QP variant, add a new parameter to -dw_hdmi_connector_create() which allows using a different -drm_connector_funcs structure and move the function to the common -header. - -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h | 2 ++ - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 +++++--- - 2 files changed, 7 insertions(+), 3 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -index b4ad71639ffa..44e27ebdd238 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-common.h -@@ -161,6 +161,8 @@ void dw_hdmi_prep_data(struct dw_hdmi *hdmi, - - enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector *connector, - bool force); -+int dw_hdmi_connector_create(struct dw_hdmi *hdmi, -+ const struct drm_connector_funcs *funcs); - - int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index a9053b0d5f54..39be3949c149 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -2470,7 +2470,8 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = - .atomic_check = dw_hdmi_connector_atomic_check, - }; - --static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) -+int dw_hdmi_connector_create(struct dw_hdmi *hdmi, -+ const struct drm_connector_funcs *funcs) - { - struct drm_connector *connector = &hdmi->connector; - struct cec_connector_info conn_info; -@@ -2488,7 +2489,7 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) - drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs); - - drm_connector_init_with_ddc(hdmi->bridge.dev, connector, -- &dw_hdmi_connector_funcs, -+ funcs ? funcs : &dw_hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA, - hdmi->ddc); - -@@ -2517,6 +2518,7 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) - - return 0; - } -+EXPORT_SYMBOL_GPL(dw_hdmi_connector_create); - - /* ----------------------------------------------------------------------------- - * DRM Bridge Operations -@@ -2805,7 +2807,7 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge, - return drm_bridge_attach(bridge->encoder, hdmi->next_bridge, - bridge, flags); - -- return dw_hdmi_connector_create(hdmi); -+ return dw_hdmi_connector_create(hdmi, NULL); - } - - void dw_hdmi_bridge_detach(struct drm_bridge *bridge) --- -2.44.1 - - -From f3b76b1900c8f8433dcdbeb4e11448c965b4fbe0 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Fri, 24 May 2024 23:46:26 +0300 -Subject: [PATCH 45/54] drm/rockchip: dw_hdmi: Use modern drm_device based - logging - -Prefer drm_{err|info|dbg}() over deprecated DRM_DEV_{ERROR|INFO|DEBUG}() -logging macros. - -Conversion done with the help of the following semantic patch, followed -by a few minor indentation adjustments: - -@@ -identifier T; -@@ - -( --DRM_DEV_ERROR(T->dev, -+drm_err(T, -...) -| --DRM_DEV_INFO(T->dev, -+drm_info(T, -...) -| --DRM_DEV_DEBUG(T->dev, -+drm_dbg(T, -...) -) - -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 24 ++++++++++----------- - 1 file changed, 11 insertions(+), 13 deletions(-) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index fe33092abbe7..2509ce19313f 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -212,7 +212,7 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) - - hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); - if (IS_ERR(hdmi->regmap)) { -- DRM_DEV_ERROR(hdmi->dev, "Unable to get rockchip,grf\n"); -+ drm_err(hdmi, "Unable to get rockchip,grf\n"); - return PTR_ERR(hdmi->regmap); - } - -@@ -223,7 +223,7 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) - if (PTR_ERR(hdmi->ref_clk) == -EPROBE_DEFER) { - return -EPROBE_DEFER; - } else if (IS_ERR(hdmi->ref_clk)) { -- DRM_DEV_ERROR(hdmi->dev, "failed to get reference clock\n"); -+ drm_err(hdmi, "failed to get reference clock\n"); - return PTR_ERR(hdmi->ref_clk); - } - -@@ -233,7 +233,7 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) - } else if (PTR_ERR(hdmi->grf_clk) == -EPROBE_DEFER) { - return -EPROBE_DEFER; - } else if (IS_ERR(hdmi->grf_clk)) { -- DRM_DEV_ERROR(hdmi->dev, "failed to get grf clock\n"); -+ drm_err(hdmi, "failed to get grf clock\n"); - return PTR_ERR(hdmi->grf_clk); - } - -@@ -322,17 +322,16 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) - - ret = clk_prepare_enable(hdmi->grf_clk); - if (ret < 0) { -- DRM_DEV_ERROR(hdmi->dev, "failed to enable grfclk %d\n", ret); -+ drm_err(hdmi, "failed to enable grfclk %d\n", ret); - return; - } - - ret = regmap_write(hdmi->regmap, hdmi->chip_data->lcdsel_grf_reg, val); - if (ret != 0) -- DRM_DEV_ERROR(hdmi->dev, "Could not write to GRF: %d\n", ret); -+ drm_err(hdmi, "Could not write to GRF: %d\n", ret); - - clk_disable_unprepare(hdmi->grf_clk); -- DRM_DEV_DEBUG(hdmi->dev, "vop %s output to hdmi\n", -- ret ? "LIT" : "BIG"); -+ drm_dbg(hdmi, "vop %s output to hdmi\n", ret ? "LIT" : "BIG"); - } - - static int -@@ -592,7 +591,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - ret = rockchip_hdmi_parse_dt(hdmi); - if (ret) { - if (ret != -EPROBE_DEFER) -- DRM_DEV_ERROR(hdmi->dev, "Unable to parse OF data\n"); -+ drm_err(hdmi, "Unable to parse OF data\n"); - return ret; - } - -@@ -600,26 +599,25 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - if (IS_ERR(hdmi->phy)) { - ret = PTR_ERR(hdmi->phy); - if (ret != -EPROBE_DEFER) -- DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n"); -+ drm_err(hdmi, "failed to get phy\n"); - return ret; - } - - ret = regulator_enable(hdmi->avdd_0v9); - if (ret) { -- DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd0v9: %d\n", ret); -+ drm_err(hdmi, "failed to enable avdd0v9: %d\n", ret); - goto err_avdd_0v9; - } - - ret = regulator_enable(hdmi->avdd_1v8); - if (ret) { -- DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd1v8: %d\n", ret); -+ drm_err(hdmi, "failed to enable avdd1v8: %d\n", ret); - goto err_avdd_1v8; - } - - ret = clk_prepare_enable(hdmi->ref_clk); - if (ret) { -- DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n", -- ret); -+ drm_err(hdmi, "Failed to enable HDMI reference clock: %d\n", ret); - goto err_clk; - } - --- -2.44.1 - - -From 14a35060796b9c44c63e0155cc777a59601e8fa1 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Tue, 7 May 2024 19:16:01 +0300 -Subject: [PATCH 46/54] drm/rockchip: dw_hdmi: Simplify clock handling - -Make use of devm_clk_get_optional_enabled() to replace devm_clk_get() -and clk_prepare_enable() for ref_clk and drop the now unnecessary calls -to clk_disable_unprepare(). - -Additionally, use devm_clk_get_optional() helper for grf_clk to replace -the open coding call to devm_clk_get() followed by the -ENOENT test. - -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 38 ++++++++------------- - 1 file changed, 14 insertions(+), 24 deletions(-) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index 2509ce19313f..7d07039ef096 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -209,6 +209,7 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = { - static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) - { - struct device_node *np = hdmi->dev->of_node; -+ int ret; - - hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); - if (IS_ERR(hdmi->regmap)) { -@@ -216,25 +217,23 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) - return PTR_ERR(hdmi->regmap); - } - -- hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "ref"); -+ hdmi->ref_clk = devm_clk_get_optional_enabled(hdmi->dev, "ref"); - if (!hdmi->ref_clk) -- hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "vpll"); -+ hdmi->ref_clk = devm_clk_get_optional_enabled(hdmi->dev, "vpll"); - -- if (PTR_ERR(hdmi->ref_clk) == -EPROBE_DEFER) { -- return -EPROBE_DEFER; -- } else if (IS_ERR(hdmi->ref_clk)) { -- drm_err(hdmi, "failed to get reference clock\n"); -- return PTR_ERR(hdmi->ref_clk); -+ if (IS_ERR(hdmi->ref_clk)) { -+ ret = PTR_ERR(hdmi->ref_clk); -+ if (ret != -EPROBE_DEFER) -+ drm_err(hdmi, "failed to get reference clock\n"); -+ return ret; - } - -- hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf"); -- if (PTR_ERR(hdmi->grf_clk) == -ENOENT) { -- hdmi->grf_clk = NULL; -- } else if (PTR_ERR(hdmi->grf_clk) == -EPROBE_DEFER) { -- return -EPROBE_DEFER; -- } else if (IS_ERR(hdmi->grf_clk)) { -- drm_err(hdmi, "failed to get grf clock\n"); -- return PTR_ERR(hdmi->grf_clk); -+ hdmi->grf_clk = devm_clk_get_optional(hdmi->dev, "grf"); -+ if (IS_ERR(hdmi->grf_clk)) { -+ ret = PTR_ERR(hdmi->grf_clk); -+ if (ret != -EPROBE_DEFER) -+ drm_err(hdmi, "failed to get grf clock\n"); -+ return ret; - } - - hdmi->avdd_0v9 = devm_regulator_get(hdmi->dev, "avdd-0v9"); -@@ -615,12 +614,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - goto err_avdd_1v8; - } - -- ret = clk_prepare_enable(hdmi->ref_clk); -- if (ret) { -- drm_err(hdmi, "Failed to enable HDMI reference clock: %d\n", ret); -- goto err_clk; -- } -- - if (hdmi->chip_data == &rk3568_chip_data) { - regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1, - HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK | -@@ -649,8 +642,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - - err_bind: - drm_encoder_cleanup(encoder); -- clk_disable_unprepare(hdmi->ref_clk); --err_clk: - regulator_disable(hdmi->avdd_1v8); - err_avdd_1v8: - regulator_disable(hdmi->avdd_0v9); -@@ -665,7 +656,6 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, - - dw_hdmi_unbind(hdmi->hdmi); - drm_encoder_cleanup(&hdmi->encoder.encoder); -- clk_disable_unprepare(hdmi->ref_clk); - - regulator_disable(hdmi->avdd_1v8); - regulator_disable(hdmi->avdd_0v9); --- -2.44.1 - - -From 6ba21ebba361b107956768931a60367dab071fdd Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Wed, 15 May 2024 02:24:03 +0300 -Subject: [PATCH 47/54] drm/rockchip: dw_hdmi: Use devm_regulator_get_enable() - -The regulators are only enabled at bind() and disabled at unbind(), -hence replace the boilerplate code by making use of -devm_regulator_get_enable() helper. - -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 34 ++++----------------- - 1 file changed, 6 insertions(+), 28 deletions(-) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index 7d07039ef096..edfd877c98fc 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -77,8 +77,6 @@ struct rockchip_hdmi { - struct clk *ref_clk; - struct clk *grf_clk; - struct dw_hdmi *hdmi; -- struct regulator *avdd_0v9; -- struct regulator *avdd_1v8; - struct phy *phy; - }; - -@@ -236,15 +234,13 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) - return ret; - } - -- hdmi->avdd_0v9 = devm_regulator_get(hdmi->dev, "avdd-0v9"); -- if (IS_ERR(hdmi->avdd_0v9)) -- return PTR_ERR(hdmi->avdd_0v9); -+ ret = devm_regulator_get_enable(hdmi->dev, "avdd-0v9"); -+ if (ret) -+ return ret; - -- hdmi->avdd_1v8 = devm_regulator_get(hdmi->dev, "avdd-1v8"); -- if (IS_ERR(hdmi->avdd_1v8)) -- return PTR_ERR(hdmi->avdd_1v8); -+ ret = devm_regulator_get_enable(hdmi->dev, "avdd-1v8"); - -- return 0; -+ return ret; - } - - static enum drm_mode_status -@@ -602,18 +598,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - return ret; - } - -- ret = regulator_enable(hdmi->avdd_0v9); -- if (ret) { -- drm_err(hdmi, "failed to enable avdd0v9: %d\n", ret); -- goto err_avdd_0v9; -- } -- -- ret = regulator_enable(hdmi->avdd_1v8); -- if (ret) { -- drm_err(hdmi, "failed to enable avdd1v8: %d\n", ret); -- goto err_avdd_1v8; -- } -- - if (hdmi->chip_data == &rk3568_chip_data) { - regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1, - HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK | -@@ -642,10 +626,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - - err_bind: - drm_encoder_cleanup(encoder); -- regulator_disable(hdmi->avdd_1v8); --err_avdd_1v8: -- regulator_disable(hdmi->avdd_0v9); --err_avdd_0v9: -+ - return ret; - } - -@@ -656,9 +637,6 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, - - dw_hdmi_unbind(hdmi->hdmi); - drm_encoder_cleanup(&hdmi->encoder.encoder); -- -- regulator_disable(hdmi->avdd_1v8); -- regulator_disable(hdmi->avdd_0v9); - } - - static const struct component_ops dw_hdmi_rockchip_ops = { --- -2.44.1 - - -From 0de628fab9d6fa101e6b973599a89fdc84504f73 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Mon, 27 May 2024 22:38:38 +0300 -Subject: [PATCH 48/54] drm/rockchip: dw_hdmi: Drop useless assignments of - mpll_cfg, cur_ctr, phy_config - -The mpll_cfg, cur_ctr and phy_config members in struct dw_hdmi_plat_data -are only used to configure the Synopsys PHYs supported internally by DW -HDMI transmitter driver (gpu/drm/bridge/synopsys/dw-hdmi.c), via -hdmi_phy_configure_dwc_hdmi_3d_tx(), which is further invoked from -dw_hdmi_phy_init(). This is part of the internal -dw_hdmi_synopsys_phy_ops struct, setup in dw_hdmi_detect_phy(). - -To handle vendor PHYs, the DW HDMI driver doesn't use the internal PHY -ops, but expects the glue layers to provide the phy_ops and phy_name -members of struct dw_hdmi_plat_data. - -Drop the unnecessary assignments of DW internal PHY related members from -structs rk3228_hdmi_drv_data and rk3328_hdmi_drv_data, since both set -the phy_force_vendor flag and provide the expected vendor PHY data. - -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index edfd877c98fc..ca6728a43159 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -444,9 +444,6 @@ static struct rockchip_hdmi_chip_data rk3228_chip_data = { - - static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { - .mode_valid = dw_hdmi_rockchip_mode_valid, -- .mpll_cfg = rockchip_mpll_cfg, -- .cur_ctr = rockchip_cur_ctr, -- .phy_config = rockchip_phy_config, - .phy_data = &rk3228_chip_data, - .phy_ops = &rk3228_hdmi_phy_ops, - .phy_name = "inno_dw_hdmi_phy2", -@@ -481,9 +478,6 @@ static struct rockchip_hdmi_chip_data rk3328_chip_data = { - - static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { - .mode_valid = dw_hdmi_rockchip_mode_valid, -- .mpll_cfg = rockchip_mpll_cfg, -- .cur_ctr = rockchip_cur_ctr, -- .phy_config = rockchip_phy_config, - .phy_data = &rk3328_chip_data, - .phy_ops = &rk3328_hdmi_phy_ops, - .phy_name = "inno_dw_hdmi_phy2", --- -2.44.1 - - -From 73bf7e4a35984bca8b89f4acb277f45c0786f7b9 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Thu, 28 Mar 2024 00:47:03 +0200 -Subject: [PATCH 49/54] dt-bindings: display: rockchip,dw-hdmi: Add compatible - for RK3588 - -Document the DW HDMI TX Controller found on Rockchip RK3588 SoC. - -Since RK3588 uses different clocks than previous Rockchip SoCs and also -requires a couple of reset lines and some additional properties, provide -the required changes in the binding to be able to handle all variants. - -Signed-off-by: Cristian Ciocaltea ---- - .../display/rockchip/rockchip,dw-hdmi.yaml | 124 +++++++++++++----- - 1 file changed, 89 insertions(+), 35 deletions(-) - -diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml -index 2aac62219ff6..651189de7af5 100644 ---- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml -+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml -@@ -12,10 +12,8 @@ maintainers: - description: | - The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP - with a companion PHY IP. -- --allOf: -- - $ref: ../bridge/synopsys,dw-hdmi.yaml# -- - $ref: /schemas/sound/dai-common.yaml# -+ RK3588 SoC updated the TX controller IP to DW HDMI 2.1 Quad-Pixel (QP), -+ while making use of a HDMI/eDP TX Combo PHY based on a Samsung IP block. - - properties: - compatible: -@@ -25,6 +23,7 @@ properties: - - rockchip,rk3328-dw-hdmi - - rockchip,rk3399-dw-hdmi - - rockchip,rk3568-dw-hdmi -+ - rockchip,rk3588-dw-hdmi - - reg-io-width: - const: 4 -@@ -40,36 +39,6 @@ properties: - A 1.8V supply that powers up the SoC internal circuitry. The pin name on the - SoC usually is HDMI_TX_AVDD_1V8. - -- clocks: -- minItems: 2 -- items: -- - {} -- - {} -- # The next three clocks are all optional, but shall be specified in this -- # order when present. -- - description: The HDMI CEC controller main clock -- - description: Power for GRF IO -- - description: External clock for some HDMI PHY (old clock name, deprecated) -- - description: External clock for some HDMI PHY (new name) -- -- clock-names: -- minItems: 2 -- items: -- - {} -- - {} -- - enum: -- - cec -- - grf -- - vpll -- - ref -- - enum: -- - grf -- - vpll -- - ref -- - enum: -- - vpll -- - ref -- - ddc-i2c-bus: - $ref: /schemas/types.yaml#/definitions/phandle - description: -@@ -131,13 +100,98 @@ properties: - required: - - compatible - - reg -- - reg-io-width - - clocks - - clock-names - - interrupts - - ports - - rockchip,grf - -+allOf: -+ - $ref: /schemas/sound/dai-common.yaml# -+ - if: -+ properties: -+ compatible: -+ contains: -+ enum: -+ - rockchip,rk3588-dw-hdmi -+ then: -+ properties: -+ reg: -+ maxItems: 1 -+ -+ clocks: -+ minItems: 1 -+ items: -+ - description: APB system interface clock -+ # The next clocks are optional, but shall be specified in this -+ # order when present. -+ - description: TMDS/FRL link clock -+ - description: EARC RX biphase clock -+ - description: Reference clock -+ - description: Audio interface clock -+ - description: Video datapath clock -+ -+ clock-names: -+ minItems: 1 -+ items: -+ - const: pclk -+ - enum: [hdp, earc, ref, aud, hclk_vo1] -+ - enum: [earc, ref, aud, hclk_vo1] -+ - enum: [ref, aud, hclk_vo1] -+ - enum: [aud, hclk_vo1] -+ - const: hclk_vo1 -+ -+ resets: -+ minItems: 2 -+ maxItems: 2 -+ -+ reset-names: -+ items: -+ - const: ref -+ - const: hdp -+ -+ interrupts: -+ minItems: 1 -+ maxItems: 5 -+ -+ rockchip,vo1_grf: -+ $ref: /schemas/types.yaml#/definitions/phandle -+ description: -+ phandle to the VO1 GRF -+ -+ required: -+ - resets -+ - reset-names -+ - rockchip,vo1_grf -+ -+ else: -+ $ref: ../bridge/synopsys,dw-hdmi.yaml# -+ -+ properties: -+ clocks: -+ minItems: 2 -+ items: -+ - {} -+ - {} -+ # The next three clocks are all optional, but shall be specified in this -+ # order when present. -+ - description: The HDMI CEC controller main clock -+ - description: Power for GRF IO -+ - description: External clock for some HDMI PHY (old clock name, deprecated) -+ - description: External clock for some HDMI PHY (new name) -+ -+ clock-names: -+ minItems: 2 -+ items: -+ - {} -+ - {} -+ - enum: [cec, grf, vpll, ref] -+ - enum: [grf, vpll, ref] -+ - enum: [vpll, ref] -+ -+ required: -+ - reg-io-width -+ - unevaluatedProperties: false - - examples: --- -2.44.1 - - -From 3c174706f556aa659210015116982f06b34b8dda Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Mon, 20 May 2024 14:49:50 +0300 -Subject: [PATCH 50/54] drm/bridge: synopsys: Add DW HDMI QP TX controller - driver - -The Synopsys DesignWare HDMI 2.1 Quad-Pixel (QP) TX controller supports -the following features, among others: - -* Fixed Rate Link (FRL) -* 4K@120Hz and 8K@60Hz video modes -* Variable Refresh Rate (VRR) including Quick Media Switching (QMS), aka - Cinema VRR -* Fast Vactive (FVA), aka Quick Frame Transport (QFT) -* SCDC I2C DDC access -* TMDS Scrambler enabling 2160p@60Hz with RGB/YCbCr4:4:4 -* YCbCr4:2:0 enabling 2160p@60Hz at lower HDMI link speeds -* Multi-stream audio -* Enhanced Audio Return Channel (EARC) - -Add driver to enable basic support, i.e. RGB output up to 4K@60Hz, -without audio, CEC or any of the HDMI 2.1 specific features. - -Co-developed-by: Algea Cao -Signed-off-by: Algea Cao -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/bridge/synopsys/Makefile | 2 +- - drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 796 ++++++++++++++++++ - drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h | 831 +++++++++++++++++++ - include/drm/bridge/dw_hdmi.h | 8 + - 4 files changed, 1636 insertions(+), 1 deletion(-) - create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c - create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h - -diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile b/drivers/gpu/drm/bridge/synopsys/Makefile -index ce715562e9e5..8354e4879f70 100644 ---- a/drivers/gpu/drm/bridge/synopsys/Makefile -+++ b/drivers/gpu/drm/bridge/synopsys/Makefile -@@ -1,5 +1,5 @@ - # SPDX-License-Identifier: GPL-2.0-only --obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o -+obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o dw-hdmi-qp.o - obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o - obj-$(CONFIG_DRM_DW_HDMI_GP_AUDIO) += dw-hdmi-gp-audio.o - obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c -new file mode 100644 -index 000000000000..09a4bf7246d6 ---- /dev/null -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c -@@ -0,0 +1,796 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. -+ * Copyright (c) 2024 Collabora Ltd. -+ * -+ * Author: Algea Cao -+ * Author: Cristian Ciocaltea -+ */ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "dw-hdmi-common.h" -+#include "dw-hdmi-qp.h" -+ -+static void dw_hdmi_qp_write(struct dw_hdmi *hdmi, unsigned int val, int offset) -+{ -+ regmap_write(hdmi->regm, offset, val); -+} -+ -+static unsigned int dw_hdmi_qp_read(struct dw_hdmi *hdmi, int offset) -+{ -+ unsigned int val = 0; -+ -+ regmap_read(hdmi->regm, offset, &val); -+ -+ return val; -+} -+ -+static void dw_hdmi_qp_mod(struct dw_hdmi *hdmi, unsigned int data, -+ unsigned int mask, unsigned int reg) -+{ -+ regmap_update_bits(hdmi->regm, reg, mask, data); -+} -+ -+static void dw_hdmi_qp_i2c_init(struct dw_hdmi *hdmi) -+{ -+ /* Software reset */ -+ dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); -+ -+ dw_hdmi_qp_write(hdmi, 0x085c085c, I2CM_FM_SCL_CONFIG0); -+ -+ dw_hdmi_qp_mod(hdmi, 0, I2CM_FM_EN, I2CM_INTERFACE_CONTROL0); -+ -+ /* Clear DONE and ERROR interrupts */ -+ dw_hdmi_qp_write(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR, -+ MAINUNIT_1_INT_CLEAR); -+} -+ -+static int dw_hdmi_qp_i2c_read(struct dw_hdmi *hdmi, -+ unsigned char *buf, unsigned int length) -+{ -+ struct dw_hdmi_i2c *i2c = hdmi->i2c; -+ int stat; -+ -+ if (!i2c->is_regaddr) { -+ dev_dbg(hdmi->dev, "set read register address to 0\n"); -+ i2c->slave_reg = 0x00; -+ i2c->is_regaddr = true; -+ } -+ -+ while (length--) { -+ reinit_completion(&i2c->cmp); -+ -+ dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, -+ I2CM_INTERFACE_CONTROL0); -+ -+ dw_hdmi_qp_mod(hdmi, I2CM_FM_READ, I2CM_WR_MASK, -+ I2CM_INTERFACE_CONTROL0); -+ -+ stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); -+ if (!stat) { -+ dev_err(hdmi->dev, "i2c read timed out\n"); -+ dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); -+ return -EAGAIN; -+ } -+ -+ /* Check for error condition on the bus */ -+ if (i2c->stat & I2CM_NACK_RCVD_IRQ) { -+ dev_err(hdmi->dev, "i2c read error\n"); -+ dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); -+ return -EIO; -+ } -+ -+ *buf++ = dw_hdmi_qp_read(hdmi, I2CM_INTERFACE_RDDATA_0_3) & 0xff; -+ dw_hdmi_qp_mod(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0); -+ } -+ -+ i2c->is_segment = false; -+ -+ return 0; -+} -+ -+static int dw_hdmi_qp_i2c_write(struct dw_hdmi *hdmi, -+ unsigned char *buf, unsigned int length) -+{ -+ struct dw_hdmi_i2c *i2c = hdmi->i2c; -+ int stat; -+ -+ if (!i2c->is_regaddr) { -+ /* Use the first write byte as register address */ -+ i2c->slave_reg = buf[0]; -+ length--; -+ buf++; -+ i2c->is_regaddr = true; -+ } -+ -+ while (length--) { -+ reinit_completion(&i2c->cmp); -+ -+ dw_hdmi_qp_write(hdmi, *buf++, I2CM_INTERFACE_WRDATA_0_3); -+ dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, -+ I2CM_INTERFACE_CONTROL0); -+ dw_hdmi_qp_mod(hdmi, I2CM_FM_WRITE, I2CM_WR_MASK, -+ I2CM_INTERFACE_CONTROL0); -+ -+ stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); -+ if (!stat) { -+ dev_err(hdmi->dev, "i2c write time out!\n"); -+ dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); -+ return -EAGAIN; -+ } -+ -+ /* Check for error condition on the bus */ -+ if (i2c->stat & I2CM_NACK_RCVD_IRQ) { -+ dev_err(hdmi->dev, "i2c write nack!\n"); -+ dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); -+ return -EIO; -+ } -+ -+ dw_hdmi_qp_mod(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0); -+ } -+ -+ return 0; -+} -+ -+static int dw_hdmi_qp_i2c_xfer(struct i2c_adapter *adap, -+ struct i2c_msg *msgs, int num) -+{ -+ struct dw_hdmi *hdmi = i2c_get_adapdata(adap); -+ struct dw_hdmi_i2c *i2c = hdmi->i2c; -+ u8 addr = msgs[0].addr; -+ int i, ret = 0; -+ -+ if (addr == DDC_CI_ADDR) -+ /* -+ * The internal I2C controller does not support the multi-byte -+ * read and write operations needed for DDC/CI. -+ * TOFIX: Blacklist the DDC/CI address until we filter out -+ * unsupported I2C operations. -+ */ -+ return -EOPNOTSUPP; -+ -+ for (i = 0; i < num; i++) { -+ if (msgs[i].len == 0) { -+ dev_err(hdmi->dev, -+ "unsupported transfer %d/%d, no data\n", -+ i + 1, num); -+ return -EOPNOTSUPP; -+ } -+ } -+ -+ mutex_lock(&i2c->lock); -+ -+ /* Unmute DONE and ERROR interrupts */ -+ dw_hdmi_qp_mod(hdmi, I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N, -+ I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N, -+ MAINUNIT_1_INT_MASK_N); -+ -+ /* Set slave device address taken from the first I2C message */ -+ if (addr == DDC_SEGMENT_ADDR && msgs[0].len == 1) -+ addr = DDC_ADDR; -+ -+ dw_hdmi_qp_mod(hdmi, addr << 5, I2CM_SLVADDR, I2CM_INTERFACE_CONTROL0); -+ -+ /* Set slave device register address on transfer */ -+ i2c->is_regaddr = false; -+ -+ /* Set segment pointer for I2C extended read mode operation */ -+ i2c->is_segment = false; -+ -+ for (i = 0; i < num; i++) { -+ if (msgs[i].addr == DDC_SEGMENT_ADDR && msgs[i].len == 1) { -+ i2c->is_segment = true; -+ dw_hdmi_qp_mod(hdmi, DDC_SEGMENT_ADDR, I2CM_SEG_ADDR, -+ I2CM_INTERFACE_CONTROL1); -+ dw_hdmi_qp_mod(hdmi, *msgs[i].buf, I2CM_SEG_PTR, -+ I2CM_INTERFACE_CONTROL1); -+ } else { -+ if (msgs[i].flags & I2C_M_RD) -+ ret = dw_hdmi_qp_i2c_read(hdmi, msgs[i].buf, -+ msgs[i].len); -+ else -+ ret = dw_hdmi_qp_i2c_write(hdmi, msgs[i].buf, -+ msgs[i].len); -+ } -+ if (ret < 0) -+ break; -+ } -+ -+ if (!ret) -+ ret = num; -+ -+ /* Mute DONE and ERROR interrupts */ -+ dw_hdmi_qp_mod(hdmi, 0, I2CM_OP_DONE_MASK_N | I2CM_NACK_RCVD_MASK_N, -+ MAINUNIT_1_INT_MASK_N); -+ -+ mutex_unlock(&i2c->lock); -+ -+ return ret; -+} -+ -+static u32 dw_hdmi_qp_i2c_func(struct i2c_adapter *adapter) -+{ -+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -+} -+ -+static const struct i2c_algorithm dw_hdmi_algorithm = { -+ .master_xfer = dw_hdmi_qp_i2c_xfer, -+ .functionality = dw_hdmi_qp_i2c_func, -+}; -+ -+/* ----------------------------------------------------------------------------- -+ * HDMI TX Setup -+ */ -+ -+static void hdmi_infoframe_set_checksum(u8 *ptr, int size) -+{ -+ u8 csum = 0; -+ int i; -+ -+ ptr[3] = 0; -+ /* compute checksum */ -+ for (i = 0; i < size; i++) -+ csum += ptr[i]; -+ -+ ptr[3] = 256 - csum; -+} -+ -+static void hdmi_config_AVI(struct dw_hdmi *hdmi, -+ const struct drm_connector *connector, -+ const struct drm_display_mode *mode) -+{ -+ struct hdmi_avi_infoframe frame; -+ u32 val, i, j; -+ u8 buf[17]; -+ -+ dw_hdmi_prep_avi_infoframe(&frame, hdmi, connector, mode); -+ -+ frame.scan_mode = HDMI_SCAN_MODE_NONE; -+ frame.video_code = hdmi->vic; -+ -+ hdmi_avi_infoframe_pack_only(&frame, buf, 17); -+ -+ /* mode which vic >= 128 must use avi version 3 */ -+ if (hdmi->vic >= 128) { -+ frame.version = 3; -+ buf[1] = frame.version; -+ buf[4] &= 0x1f; -+ buf[4] |= ((frame.colorspace & 0x7) << 5); -+ buf[7] = frame.video_code; -+ hdmi_infoframe_set_checksum(buf, 17); -+ } -+ -+ /* -+ * The Designware IP uses a different byte format from standard -+ * AVI info frames, though generally the bits are in the correct -+ * bytes. -+ */ -+ -+ val = (frame.version << 8) | (frame.length << 16); -+ dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS0); -+ -+ for (i = 0; i < 4; i++) { -+ for (j = 0; j < 4; j++) { -+ if (i * 4 + j >= 14) -+ break; -+ if (!j) -+ val = buf[i * 4 + j + 3]; -+ val |= buf[i * 4 + j + 3] << (8 * j); -+ } -+ -+ dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS1 + i * 4); -+ } -+ -+ dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_FIELDRATE, PKTSCHED_PKT_CONFIG1); -+ -+ dw_hdmi_qp_mod(hdmi, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, -+ PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN); -+} -+ -+static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi, -+ const struct drm_connector *connector) -+{ -+ const struct drm_connector_state *conn_state = connector->state; -+ struct hdr_output_metadata *hdr_metadata; -+ struct hdmi_drm_infoframe frame; -+ u8 buffer[30]; -+ ssize_t err; -+ int i; -+ u32 val; -+ -+ if (!hdmi->plat_data->use_drm_infoframe) -+ return; -+ -+ dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); -+ -+ if (!hdmi->connector.hdr_sink_metadata.hdmi_type1.eotf) { -+ dev_dbg(hdmi->dev, "No need to set HDR metadata in infoframe\n"); -+ return; -+ } -+ -+ if (!conn_state->hdr_output_metadata) { -+ dev_dbg(hdmi->dev, "source metadata not set yet\n"); -+ return; -+ } -+ -+ hdr_metadata = (struct hdr_output_metadata *) -+ conn_state->hdr_output_metadata->data; -+ -+ if (!(hdmi->connector.hdr_sink_metadata.hdmi_type1.eotf & -+ BIT(hdr_metadata->hdmi_metadata_type1.eotf))) { -+ dev_err(hdmi->dev, "EOTF %d not supported\n", -+ hdr_metadata->hdmi_metadata_type1.eotf); -+ return; -+ } -+ -+ err = drm_hdmi_infoframe_set_hdr_metadata(&frame, conn_state); -+ if (err < 0) -+ return; -+ -+ err = hdmi_drm_infoframe_pack(&frame, buffer, sizeof(buffer)); -+ if (err < 0) { -+ dev_err(hdmi->dev, "Failed to pack drm infoframe: %zd\n", err); -+ return; -+ } -+ -+ val = (frame.version << 8) | (frame.length << 16); -+ dw_hdmi_qp_write(hdmi, val, PKT_DRMI_CONTENTS0); -+ -+ for (i = 0; i <= frame.length; i++) { -+ if (i % 4 == 0) -+ val = buffer[3 + i]; -+ val |= buffer[3 + i] << ((i % 4) * 8); -+ -+ if (i % 4 == 3 || (i == (frame.length))) -+ dw_hdmi_qp_write(hdmi, val, -+ PKT_DRMI_CONTENTS1 + ((i / 4) * 4)); -+ } -+ -+ dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_FIELDRATE, PKTSCHED_PKT_CONFIG1); -+ dw_hdmi_qp_mod(hdmi, PKTSCHED_DRMI_TX_EN, PKTSCHED_DRMI_TX_EN, -+ PKTSCHED_PKT_EN); -+} -+ -+static int dw_hdmi_qp_setup(struct dw_hdmi *hdmi, -+ struct drm_connector *connector, -+ struct drm_display_mode *mode) -+{ -+ u8 bytes = 0; -+ int ret; -+ -+ dw_hdmi_prep_data(hdmi, mode); -+ -+ if (mode->flags & DRM_MODE_FLAG_DBLCLK) { -+ hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1; -+ hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 1; -+ } -+ -+ /* -+ * According to the dw-hdmi specification 6.4.2 -+ * vp_pr_cd[3:0]: -+ * 0000b: No pixel repetition (pixel sent only once) -+ * 0001b: Pixel sent two times (pixel repeated once) -+ */ -+ if (mode->flags & DRM_MODE_FLAG_DBLCLK) -+ hdmi->hdmi_data.pix_repet_factor = 1; -+ -+ /* HDMI Initialization Step B.1 */ -+ dw_hdmi_prep_vmode(hdmi, mode); -+ -+ /* HDMI Initialization Step B.2 */ -+ ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, -+ &connector->display_info, -+ &hdmi->previous_mode); -+ if (ret) -+ return ret; -+ hdmi->phy.enabled = true; -+ -+ /* not for DVI mode */ -+ if (hdmi->sink_is_hdmi) { -+ dev_dbg(hdmi->dev, "%s HDMI mode\n", __func__); -+ -+ dw_hdmi_qp_mod(hdmi, 0, OPMODE_DVI, LINK_CONFIG0); -+ dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0); -+ -+ if (hdmi->hdmi_data.video_mode.mtmdsclock > HDMI14_MAX_TMDSCLK) { -+ if (dw_hdmi_support_scdc(hdmi, &connector->display_info)) { -+ drm_scdc_readb(hdmi->ddc, SCDC_SINK_VERSION, &bytes); -+ drm_scdc_writeb(hdmi->ddc, SCDC_SOURCE_VERSION, -+ min_t(u8, bytes, SCDC_MIN_SOURCE_VERSION)); -+ drm_scdc_set_high_tmds_clock_ratio(connector, 1); -+ drm_scdc_set_scrambling(connector, 1); -+ } -+ dw_hdmi_qp_write(hdmi, 1, SCRAMB_CONFIG0); -+ } else { -+ if (dw_hdmi_support_scdc(hdmi, &connector->display_info)) { -+ drm_scdc_set_high_tmds_clock_ratio(connector, 0); -+ drm_scdc_set_scrambling(connector, 0); -+ } -+ dw_hdmi_qp_write(hdmi, 0, SCRAMB_CONFIG0); -+ } -+ -+ /* HDMI Initialization Step F */ -+ hdmi_config_AVI(hdmi, connector, mode); -+ hdmi_config_drm_infoframe(hdmi, connector); -+ } else { -+ dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); -+ -+ dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0); -+ dw_hdmi_qp_mod(hdmi, OPMODE_DVI, OPMODE_DVI, LINK_CONFIG0); -+ } -+ -+ return 0; -+} -+ -+static void dw_hdmi_qp_update_power(struct dw_hdmi *hdmi) -+{ -+ int force = hdmi->force; -+ -+ if (hdmi->disabled) { -+ force = DRM_FORCE_OFF; -+ } else if (force == DRM_FORCE_UNSPECIFIED) { -+ if (hdmi->rxsense) -+ force = DRM_FORCE_ON; -+ else -+ force = DRM_FORCE_OFF; -+ } -+ -+ if (force == DRM_FORCE_OFF) { -+ if (hdmi->bridge_is_on) { -+ if (hdmi->phy.enabled) { -+ hdmi->phy.ops->disable(hdmi, hdmi->phy.data); -+ hdmi->phy.enabled = false; -+ } -+ -+ hdmi->bridge_is_on = false; -+ } -+ } else { -+ if (!hdmi->bridge_is_on) { -+ hdmi->bridge_is_on = true; -+ -+ /* -+ * The curr_conn field is guaranteed to be valid here, as this function -+ * is only be called when !hdmi->disabled. -+ */ -+ dw_hdmi_qp_setup(hdmi, hdmi->curr_conn, &hdmi->previous_mode); -+ } -+ } -+} -+ -+static void dw_hdmi_qp_connector_force(struct drm_connector *connector) -+{ -+ struct dw_hdmi *hdmi = -+ container_of(connector, struct dw_hdmi, connector); -+ -+ mutex_lock(&hdmi->mutex); -+ hdmi->force = connector->force; -+ dw_hdmi_qp_update_power(hdmi); -+ mutex_unlock(&hdmi->mutex); -+} -+ -+static const struct drm_connector_funcs dw_hdmi_qp_connector_funcs = { -+ .fill_modes = drm_helper_probe_single_connector_modes, -+ .detect = dw_hdmi_connector_detect, -+ .destroy = drm_connector_cleanup, -+ .force = dw_hdmi_qp_connector_force, -+ .reset = drm_atomic_helper_connector_reset, -+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, -+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -+}; -+ -+static int dw_hdmi_qp_bridge_attach(struct drm_bridge *bridge, -+ enum drm_bridge_attach_flags flags) -+{ -+ struct dw_hdmi *hdmi = bridge->driver_private; -+ -+ if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) -+ return drm_bridge_attach(bridge->encoder, hdmi->next_bridge, -+ bridge, flags); -+ -+ return dw_hdmi_connector_create(hdmi, &dw_hdmi_qp_connector_funcs); -+} -+ -+static enum drm_mode_status -+dw_hdmi_qp_bridge_mode_valid(struct drm_bridge *bridge, -+ const struct drm_display_info *info, -+ const struct drm_display_mode *mode) -+{ -+ struct dw_hdmi *hdmi = bridge->driver_private; -+ const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; -+ enum drm_mode_status mode_status = MODE_OK; -+ -+ if (pdata->mode_valid) -+ mode_status = pdata->mode_valid(hdmi, pdata->priv_data, info, -+ mode); -+ -+ return mode_status; -+} -+ -+static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge, -+ struct drm_bridge_state *old_state) -+{ -+ struct dw_hdmi *hdmi = bridge->driver_private; -+ -+ mutex_lock(&hdmi->mutex); -+ hdmi->disabled = true; -+ hdmi->curr_conn = NULL; -+ dw_hdmi_qp_update_power(hdmi); -+ dw_handle_plugged_change(hdmi, false); -+ mutex_unlock(&hdmi->mutex); -+} -+ -+static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge, -+ struct drm_bridge_state *old_state) -+{ -+ struct dw_hdmi *hdmi = bridge->driver_private; -+ struct drm_atomic_state *state = old_state->base.state; -+ struct drm_connector *connector; -+ -+ connector = drm_atomic_get_new_connector_for_encoder(state, -+ bridge->encoder); -+ -+ mutex_lock(&hdmi->mutex); -+ hdmi->disabled = false; -+ hdmi->curr_conn = connector; -+ dw_hdmi_qp_update_power(hdmi); -+ dw_handle_plugged_change(hdmi, true); -+ mutex_unlock(&hdmi->mutex); -+} -+ -+static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = { -+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, -+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, -+ .atomic_reset = drm_atomic_helper_bridge_reset, -+ .attach = dw_hdmi_qp_bridge_attach, -+ .detach = dw_hdmi_bridge_detach, -+ .atomic_check = dw_hdmi_bridge_atomic_check, -+ .atomic_enable = dw_hdmi_qp_bridge_atomic_enable, -+ .atomic_disable = dw_hdmi_qp_bridge_atomic_disable, -+ .mode_set = dw_hdmi_bridge_mode_set, -+ .mode_valid = dw_hdmi_qp_bridge_mode_valid, -+ .detect = dw_hdmi_bridge_detect, -+ .edid_read = dw_hdmi_bridge_edid_read, -+}; -+ -+static irqreturn_t dw_hdmi_qp_main_hardirq(int irq, void *dev_id) -+{ -+ struct dw_hdmi *hdmi = dev_id; -+ struct dw_hdmi_i2c *i2c = hdmi->i2c; -+ u32 stat; -+ -+ stat = dw_hdmi_qp_read(hdmi, MAINUNIT_1_INT_STATUS); -+ -+ i2c->stat = stat & (I2CM_OP_DONE_IRQ | I2CM_READ_REQUEST_IRQ | -+ I2CM_NACK_RCVD_IRQ); -+ -+ if (i2c->stat) { -+ dw_hdmi_qp_write(hdmi, i2c->stat, MAINUNIT_1_INT_CLEAR); -+ complete(&i2c->cmp); -+ } -+ -+ if (stat) -+ return IRQ_HANDLED; -+ -+ return IRQ_NONE; -+} -+ -+static int dw_hdmi_qp_detect_phy(struct dw_hdmi *hdmi) -+{ -+ if (!hdmi->plat_data->phy_force_vendor) { -+ dev_err(hdmi->dev, "Internal HDMI PHY not supported\n"); -+ return -ENODEV; -+ } -+ -+ /* Vendor PHYs require support from the glue layer. */ -+ if (!hdmi->plat_data->phy_ops || !hdmi->plat_data->phy_name) { -+ dev_err(hdmi->dev, -+ "Vendor HDMI PHY not supported by glue layer\n"); -+ return -ENODEV; -+ } -+ -+ hdmi->phy.ops = hdmi->plat_data->phy_ops; -+ hdmi->phy.data = hdmi->plat_data->phy_data; -+ hdmi->phy.name = hdmi->plat_data->phy_name; -+ -+ return 0; -+} -+ -+static const struct regmap_config dw_hdmi_qp_regmap_config = { -+ .reg_bits = 32, -+ .val_bits = 32, -+ .reg_stride = 4, -+ .max_register = EARCRX_1_INT_FORCE, -+}; -+ -+static void dw_hdmi_qp_init_hw(struct dw_hdmi *hdmi) -+{ -+ dw_hdmi_qp_write(hdmi, 0, MAINUNIT_0_INT_MASK_N); -+ dw_hdmi_qp_write(hdmi, 0, MAINUNIT_1_INT_MASK_N); -+ dw_hdmi_qp_write(hdmi, 428571429, TIMER_BASE_CONFIG0); -+ -+ dw_hdmi_qp_i2c_init(hdmi); -+ -+ if (hdmi->phy.ops->setup_hpd) -+ hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); -+} -+ -+static struct dw_hdmi * -+dw_hdmi_qp_probe(struct platform_device *pdev, -+ const struct dw_hdmi_plat_data *plat_data) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct device_node *ddc_node; -+ struct dw_hdmi *hdmi; -+ struct resource *iores = NULL; -+ int irq, ret; -+ -+ hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); -+ if (!hdmi) -+ return ERR_PTR(-ENOMEM); -+ -+ hdmi->plat_data = plat_data; -+ hdmi->dev = dev; -+ hdmi->disabled = true; -+ hdmi->rxsense = true; -+ hdmi->last_connector_result = connector_status_disconnected; -+ -+ mutex_init(&hdmi->mutex); -+ mutex_init(&hdmi->audio_mutex); -+ mutex_init(&hdmi->cec_notifier_mutex); -+ spin_lock_init(&hdmi->audio_lock); -+ -+ ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); -+ if (ddc_node) { -+ hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node); -+ of_node_put(ddc_node); -+ if (!hdmi->ddc) { -+ dev_dbg(hdmi->dev, "failed to read ddc node\n"); -+ return ERR_PTR(-EPROBE_DEFER); -+ } -+ -+ } else { -+ dev_dbg(hdmi->dev, "no ddc property found\n"); -+ } -+ -+ if (!plat_data->regm) { -+ const struct regmap_config *reg_config; -+ -+ reg_config = &dw_hdmi_qp_regmap_config; -+ -+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ hdmi->regs = devm_ioremap_resource(dev, iores); -+ if (IS_ERR(hdmi->regs)) { -+ ret = PTR_ERR(hdmi->regs); -+ goto err_res; -+ } -+ -+ hdmi->regm = devm_regmap_init_mmio(dev, hdmi->regs, reg_config); -+ if (IS_ERR(hdmi->regm)) { -+ dev_err(dev, "Failed to configure regmap\n"); -+ ret = PTR_ERR(hdmi->regm); -+ goto err_res; -+ } -+ } else { -+ hdmi->regm = plat_data->regm; -+ } -+ -+ /* Allow SCDC advertising in dw_hdmi_support_scdc() */ -+ hdmi->version = 0x200a; -+ -+ ret = dw_hdmi_qp_detect_phy(hdmi); -+ if (ret < 0) -+ goto err_res; -+ -+ dw_hdmi_qp_init_hw(hdmi); -+ -+ if ((dw_hdmi_qp_read(hdmi, CMU_STATUS) & DISPLAY_CLK_MONITOR) == -+ DISPLAY_CLK_LOCKED) -+ hdmi->disabled = false; -+ -+ /* Not handled for now: IRQ0 (AVP), IRQ1 (CEC), IRQ2 (EARC) */ -+ irq = platform_get_irq(pdev, 3); -+ if (irq < 0) { -+ ret = irq; -+ goto err_res; -+ } -+ -+ ret = devm_request_threaded_irq(dev, irq, -+ dw_hdmi_qp_main_hardirq, NULL, -+ IRQF_SHARED, dev_name(dev), hdmi); -+ if (ret) -+ goto err_res; -+ -+ /* If DDC bus is not specified, try to register HDMI I2C bus */ -+ if (!hdmi->ddc) { -+ hdmi->ddc = dw_hdmi_i2c_adapter(hdmi, &dw_hdmi_algorithm); -+ if (IS_ERR(hdmi->ddc)) -+ hdmi->ddc = NULL; -+ } -+ -+ hdmi->bridge.driver_private = hdmi; -+ hdmi->bridge.funcs = &dw_hdmi_qp_bridge_funcs; -+ hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID -+ | DRM_BRIDGE_OP_HPD; -+ hdmi->bridge.ddc = hdmi->ddc; -+ hdmi->bridge.of_node = pdev->dev.of_node; -+ hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; -+ -+ drm_bridge_add(&hdmi->bridge); -+ -+ return hdmi; -+ -+err_res: -+ i2c_put_adapter(hdmi->ddc); -+ -+ return ERR_PTR(ret); -+} -+ -+static void dw_hdmi_qp_remove(struct dw_hdmi *hdmi) -+{ -+ drm_bridge_remove(&hdmi->bridge); -+ -+ if (hdmi->audio && !IS_ERR(hdmi->audio)) -+ platform_device_unregister(hdmi->audio); -+ if (!IS_ERR(hdmi->cec)) -+ platform_device_unregister(hdmi->cec); -+ -+ if (hdmi->i2c) -+ i2c_del_adapter(&hdmi->i2c->adap); -+ else -+ i2c_put_adapter(hdmi->ddc); -+} -+ -+struct dw_hdmi *dw_hdmi_qp_bind(struct platform_device *pdev, -+ struct drm_encoder *encoder, -+ struct dw_hdmi_plat_data *plat_data) -+{ -+ struct dw_hdmi *hdmi; -+ int ret; -+ -+ hdmi = dw_hdmi_qp_probe(pdev, plat_data); -+ if (IS_ERR(hdmi)) -+ return hdmi; -+ -+ ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, 0); -+ if (ret) { -+ dw_hdmi_qp_remove(hdmi); -+ return ERR_PTR(ret); -+ } -+ -+ return hdmi; -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind); -+ -+void dw_hdmi_qp_unbind(struct dw_hdmi *hdmi) -+{ -+ dw_hdmi_qp_remove(hdmi); -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_unbind); -+ -+void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi *hdmi) -+{ -+ dw_hdmi_qp_init_hw(hdmi); -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_resume); -+ -+MODULE_AUTHOR("Algea Cao "); -+MODULE_AUTHOR("Cristian Ciocaltea "); -+MODULE_DESCRIPTION("DW HDMI QP transmitter driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:dw-hdmi-qp"); -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h -new file mode 100644 -index 000000000000..4cac70f2d11d ---- /dev/null -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h -@@ -0,0 +1,831 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) Rockchip Electronics Co.Ltd -+ * Author: -+ * Algea Cao -+ */ -+#ifndef __DW_HDMI_QP_H__ -+#define __DW_HDMI_QP_H__ -+/* Main Unit Registers */ -+#define CORE_ID 0x0 -+#define VER_NUMBER 0x4 -+#define VER_TYPE 0x8 -+#define CONFIG_REG 0xc -+#define CONFIG_CEC BIT(28) -+#define CONFIG_AUD_UD BIT(23) -+#define CORE_TIMESTAMP_HHMM 0x14 -+#define CORE_TIMESTAMP_MMDD 0x18 -+#define CORE_TIMESTAMP_YYYY 0x1c -+/* Reset Manager Registers */ -+#define GLOBAL_SWRESET_REQUEST 0x40 -+#define EARCRX_CMDC_SWINIT_P BIT(27) -+#define AVP_DATAPATH_PACKET_AUDIO_SWINIT_P BIT(10) -+#define GLOBAL_SWDISABLE 0x44 -+#define CEC_SWDISABLE BIT(17) -+#define AVP_DATAPATH_PACKET_AUDIO_SWDISABLE BIT(10) -+#define AVP_DATAPATH_VIDEO_SWDISABLE BIT(6) -+#define RESET_MANAGER_CONFIG0 0x48 -+#define RESET_MANAGER_STATUS0 0x50 -+#define RESET_MANAGER_STATUS1 0x54 -+#define RESET_MANAGER_STATUS2 0x58 -+/* Timer Base Registers */ -+#define TIMER_BASE_CONFIG0 0x80 -+#define TIMER_BASE_STATUS0 0x84 -+/* CMU Registers */ -+#define CMU_CONFIG0 0xa0 -+#define CMU_CONFIG1 0xa4 -+#define CMU_CONFIG2 0xa8 -+#define CMU_CONFIG3 0xac -+#define CMU_STATUS 0xb0 -+#define DISPLAY_CLK_MONITOR 0x3f -+#define DISPLAY_CLK_LOCKED 0X15 -+#define EARC_BPCLK_OFF BIT(9) -+#define AUDCLK_OFF BIT(7) -+#define LINKQPCLK_OFF BIT(5) -+#define VIDQPCLK_OFF BIT(3) -+#define IPI_CLK_OFF BIT(1) -+#define CMU_IPI_CLK_FREQ 0xb4 -+#define CMU_VIDQPCLK_FREQ 0xb8 -+#define CMU_LINKQPCLK_FREQ 0xbc -+#define CMU_AUDQPCLK_FREQ 0xc0 -+#define CMU_EARC_BPCLK_FREQ 0xc4 -+/* I2CM Registers */ -+#define I2CM_SM_SCL_CONFIG0 0xe0 -+#define I2CM_FM_SCL_CONFIG0 0xe4 -+#define I2CM_CONFIG0 0xe8 -+#define I2CM_CONTROL0 0xec -+#define I2CM_STATUS0 0xf0 -+#define I2CM_INTERFACE_CONTROL0 0xf4 -+#define I2CM_ADDR 0xff000 -+#define I2CM_SLVADDR 0xfe0 -+#define I2CM_WR_MASK 0x1e -+#define I2CM_EXT_READ BIT(4) -+#define I2CM_SHORT_READ BIT(3) -+#define I2CM_FM_READ BIT(2) -+#define I2CM_FM_WRITE BIT(1) -+#define I2CM_FM_EN BIT(0) -+#define I2CM_INTERFACE_CONTROL1 0xf8 -+#define I2CM_SEG_PTR 0x7f80 -+#define I2CM_SEG_ADDR 0x7f -+#define I2CM_INTERFACE_WRDATA_0_3 0xfc -+#define I2CM_INTERFACE_WRDATA_4_7 0x100 -+#define I2CM_INTERFACE_WRDATA_8_11 0x104 -+#define I2CM_INTERFACE_WRDATA_12_15 0x108 -+#define I2CM_INTERFACE_RDDATA_0_3 0x10c -+#define I2CM_INTERFACE_RDDATA_4_7 0x110 -+#define I2CM_INTERFACE_RDDATA_8_11 0x114 -+#define I2CM_INTERFACE_RDDATA_12_15 0x118 -+/* SCDC Registers */ -+#define SCDC_CONFIG0 0x140 -+#define SCDC_I2C_FM_EN BIT(12) -+#define SCDC_UPD_FLAGS_AUTO_CLR BIT(6) -+#define SCDC_UPD_FLAGS_POLL_EN BIT(4) -+#define SCDC_CONTROL0 0x148 -+#define SCDC_STATUS0 0x150 -+#define STATUS_UPDATE BIT(0) -+#define FRL_START BIT(4) -+#define FLT_UPDATE BIT(5) -+/* FLT Registers */ -+#define FLT_CONFIG0 0x160 -+#define FLT_CONFIG1 0x164 -+#define FLT_CONFIG2 0x168 -+#define FLT_CONTROL0 0x170 -+/* Main Unit 2 Registers */ -+#define MAINUNIT_STATUS0 0x180 -+/* Video Interface Registers */ -+#define VIDEO_INTERFACE_CONFIG0 0x800 -+#define VIDEO_INTERFACE_CONFIG1 0x804 -+#define VIDEO_INTERFACE_CONFIG2 0x808 -+#define VIDEO_INTERFACE_CONTROL0 0x80c -+#define VIDEO_INTERFACE_STATUS0 0x814 -+/* Video Packing Registers */ -+#define VIDEO_PACKING_CONFIG0 0x81c -+/* Audio Interface Registers */ -+#define AUDIO_INTERFACE_CONFIG0 0x820 -+#define AUD_IF_SEL_MSK 0x3 -+#define AUD_IF_SPDIF 0x2 -+#define AUD_IF_I2S 0x1 -+#define AUD_IF_PAI 0x0 -+#define AUD_FIFO_INIT_ON_OVF_MSK BIT(2) -+#define AUD_FIFO_INIT_ON_OVF_EN BIT(2) -+#define I2S_LINES_EN_MSK GENMASK(7, 4) -+#define I2S_LINES_EN(x) BIT(x + 4) -+#define I2S_BPCUV_RCV_MSK BIT(12) -+#define I2S_BPCUV_RCV_EN BIT(12) -+#define I2S_BPCUV_RCV_DIS 0 -+#define SPDIF_LINES_EN GENMASK(19, 16) -+#define AUD_FORMAT_MSK GENMASK(26, 24) -+#define AUD_3DOBA (0x7 << 24) -+#define AUD_3DASP (0x6 << 24) -+#define AUD_MSOBA (0x5 << 24) -+#define AUD_MSASP (0x4 << 24) -+#define AUD_HBR (0x3 << 24) -+#define AUD_DST (0x2 << 24) -+#define AUD_OBA (0x1 << 24) -+#define AUD_ASP (0x0 << 24) -+#define AUDIO_INTERFACE_CONFIG1 0x824 -+#define AUDIO_INTERFACE_CONTROL0 0x82c -+#define AUDIO_FIFO_CLR_P BIT(0) -+#define AUDIO_INTERFACE_STATUS0 0x834 -+/* Frame Composer Registers */ -+#define FRAME_COMPOSER_CONFIG0 0x840 -+#define FRAME_COMPOSER_CONFIG1 0x844 -+#define FRAME_COMPOSER_CONFIG2 0x848 -+#define FRAME_COMPOSER_CONFIG3 0x84c -+#define FRAME_COMPOSER_CONFIG4 0x850 -+#define FRAME_COMPOSER_CONFIG5 0x854 -+#define FRAME_COMPOSER_CONFIG6 0x858 -+#define FRAME_COMPOSER_CONFIG7 0x85c -+#define FRAME_COMPOSER_CONFIG8 0x860 -+#define FRAME_COMPOSER_CONFIG9 0x864 -+#define FRAME_COMPOSER_CONTROL0 0x86c -+/* Video Monitor Registers */ -+#define VIDEO_MONITOR_CONFIG0 0x880 -+#define VIDEO_MONITOR_STATUS0 0x884 -+#define VIDEO_MONITOR_STATUS1 0x888 -+#define VIDEO_MONITOR_STATUS2 0x88c -+#define VIDEO_MONITOR_STATUS3 0x890 -+#define VIDEO_MONITOR_STATUS4 0x894 -+#define VIDEO_MONITOR_STATUS5 0x898 -+#define VIDEO_MONITOR_STATUS6 0x89c -+/* HDCP2 Logic Registers */ -+#define HDCP2LOGIC_CONFIG0 0x8e0 -+#define HDCP2_BYPASS BIT(0) -+#define HDCP2LOGIC_ESM_GPIO_IN 0x8e4 -+#define HDCP2LOGIC_ESM_GPIO_OUT 0x8e8 -+/* HDCP14 Registers */ -+#define HDCP14_CONFIG0 0x900 -+#define HDCP14_CONFIG1 0x904 -+#define HDCP14_CONFIG2 0x908 -+#define HDCP14_CONFIG3 0x90c -+#define HDCP14_KEY_SEED 0x914 -+#define HDCP14_KEY_H 0x918 -+#define HDCP14_KEY_L 0x91c -+#define HDCP14_KEY_STATUS 0x920 -+#define HDCP14_AKSV_H 0x924 -+#define HDCP14_AKSV_L 0x928 -+#define HDCP14_AN_H 0x92c -+#define HDCP14_AN_L 0x930 -+#define HDCP14_STATUS0 0x934 -+#define HDCP14_STATUS1 0x938 -+/* Scrambler Registers */ -+#define SCRAMB_CONFIG0 0x960 -+/* Video Configuration Registers */ -+#define LINK_CONFIG0 0x968 -+#define OPMODE_FRL_4LANES BIT(8) -+#define OPMODE_DVI BIT(4) -+#define OPMODE_FRL BIT(0) -+/* TMDS FIFO Registers */ -+#define TMDS_FIFO_CONFIG0 0x970 -+#define TMDS_FIFO_CONTROL0 0x974 -+/* FRL RSFEC Registers */ -+#define FRL_RSFEC_CONFIG0 0xa20 -+#define FRL_RSFEC_STATUS0 0xa30 -+/* FRL Packetizer Registers */ -+#define FRL_PKTZ_CONFIG0 0xa40 -+#define FRL_PKTZ_CONTROL0 0xa44 -+#define FRL_PKTZ_CONTROL1 0xa50 -+#define FRL_PKTZ_STATUS1 0xa54 -+/* Packet Scheduler Registers */ -+#define PKTSCHED_CONFIG0 0xa80 -+#define PKTSCHED_PRQUEUE0_CONFIG0 0xa84 -+#define PKTSCHED_PRQUEUE1_CONFIG0 0xa88 -+#define PKTSCHED_PRQUEUE2_CONFIG0 0xa8c -+#define PKTSCHED_PRQUEUE2_CONFIG1 0xa90 -+#define PKTSCHED_PRQUEUE2_CONFIG2 0xa94 -+#define PKTSCHED_PKT_CONFIG0 0xa98 -+#define PKTSCHED_PKT_CONFIG1 0xa9c -+#define PKTSCHED_DRMI_FIELDRATE BIT(13) -+#define PKTSCHED_AVI_FIELDRATE BIT(12) -+#define PKTSCHED_PKT_CONFIG2 0xaa0 -+#define PKTSCHED_PKT_CONFIG3 0xaa4 -+#define PKTSCHED_PKT_EN 0xaa8 -+#define PKTSCHED_DRMI_TX_EN BIT(17) -+#define PKTSCHED_AUDI_TX_EN BIT(15) -+#define PKTSCHED_AVI_TX_EN BIT(13) -+#define PKTSCHED_EMP_CVTEM_TX_EN BIT(10) -+#define PKTSCHED_AMD_TX_EN BIT(8) -+#define PKTSCHED_GCP_TX_EN BIT(3) -+#define PKTSCHED_AUDS_TX_EN BIT(2) -+#define PKTSCHED_ACR_TX_EN BIT(1) -+#define PKTSCHED_NULL_TX_EN BIT(0) -+#define PKTSCHED_PKT_CONTROL0 0xaac -+#define PKTSCHED_PKT_SEND 0xab0 -+#define PKTSCHED_PKT_STATUS0 0xab4 -+#define PKTSCHED_PKT_STATUS1 0xab8 -+#define PKT_NULL_CONTENTS0 0xb00 -+#define PKT_NULL_CONTENTS1 0xb04 -+#define PKT_NULL_CONTENTS2 0xb08 -+#define PKT_NULL_CONTENTS3 0xb0c -+#define PKT_NULL_CONTENTS4 0xb10 -+#define PKT_NULL_CONTENTS5 0xb14 -+#define PKT_NULL_CONTENTS6 0xb18 -+#define PKT_NULL_CONTENTS7 0xb1c -+#define PKT_ACP_CONTENTS0 0xb20 -+#define PKT_ACP_CONTENTS1 0xb24 -+#define PKT_ACP_CONTENTS2 0xb28 -+#define PKT_ACP_CONTENTS3 0xb2c -+#define PKT_ACP_CONTENTS4 0xb30 -+#define PKT_ACP_CONTENTS5 0xb34 -+#define PKT_ACP_CONTENTS6 0xb38 -+#define PKT_ACP_CONTENTS7 0xb3c -+#define PKT_ISRC1_CONTENTS0 0xb40 -+#define PKT_ISRC1_CONTENTS1 0xb44 -+#define PKT_ISRC1_CONTENTS2 0xb48 -+#define PKT_ISRC1_CONTENTS3 0xb4c -+#define PKT_ISRC1_CONTENTS4 0xb50 -+#define PKT_ISRC1_CONTENTS5 0xb54 -+#define PKT_ISRC1_CONTENTS6 0xb58 -+#define PKT_ISRC1_CONTENTS7 0xb5c -+#define PKT_ISRC2_CONTENTS0 0xb60 -+#define PKT_ISRC2_CONTENTS1 0xb64 -+#define PKT_ISRC2_CONTENTS2 0xb68 -+#define PKT_ISRC2_CONTENTS3 0xb6c -+#define PKT_ISRC2_CONTENTS4 0xb70 -+#define PKT_ISRC2_CONTENTS5 0xb74 -+#define PKT_ISRC2_CONTENTS6 0xb78 -+#define PKT_ISRC2_CONTENTS7 0xb7c -+#define PKT_GMD_CONTENTS0 0xb80 -+#define PKT_GMD_CONTENTS1 0xb84 -+#define PKT_GMD_CONTENTS2 0xb88 -+#define PKT_GMD_CONTENTS3 0xb8c -+#define PKT_GMD_CONTENTS4 0xb90 -+#define PKT_GMD_CONTENTS5 0xb94 -+#define PKT_GMD_CONTENTS6 0xb98 -+#define PKT_GMD_CONTENTS7 0xb9c -+#define PKT_AMD_CONTENTS0 0xba0 -+#define PKT_AMD_CONTENTS1 0xba4 -+#define PKT_AMD_CONTENTS2 0xba8 -+#define PKT_AMD_CONTENTS3 0xbac -+#define PKT_AMD_CONTENTS4 0xbb0 -+#define PKT_AMD_CONTENTS5 0xbb4 -+#define PKT_AMD_CONTENTS6 0xbb8 -+#define PKT_AMD_CONTENTS7 0xbbc -+#define PKT_VSI_CONTENTS0 0xbc0 -+#define PKT_VSI_CONTENTS1 0xbc4 -+#define PKT_VSI_CONTENTS2 0xbc8 -+#define PKT_VSI_CONTENTS3 0xbcc -+#define PKT_VSI_CONTENTS4 0xbd0 -+#define PKT_VSI_CONTENTS5 0xbd4 -+#define PKT_VSI_CONTENTS6 0xbd8 -+#define PKT_VSI_CONTENTS7 0xbdc -+#define PKT_AVI_CONTENTS0 0xbe0 -+#define HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT BIT(4) -+#define HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR 0x04 -+#define HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR 0x08 -+#define HDMI_FC_AVICONF2_IT_CONTENT_VALID 0x80 -+#define PKT_AVI_CONTENTS1 0xbe4 -+#define PKT_AVI_CONTENTS2 0xbe8 -+#define PKT_AVI_CONTENTS3 0xbec -+#define PKT_AVI_CONTENTS4 0xbf0 -+#define PKT_AVI_CONTENTS5 0xbf4 -+#define PKT_AVI_CONTENTS6 0xbf8 -+#define PKT_AVI_CONTENTS7 0xbfc -+#define PKT_SPDI_CONTENTS0 0xc00 -+#define PKT_SPDI_CONTENTS1 0xc04 -+#define PKT_SPDI_CONTENTS2 0xc08 -+#define PKT_SPDI_CONTENTS3 0xc0c -+#define PKT_SPDI_CONTENTS4 0xc10 -+#define PKT_SPDI_CONTENTS5 0xc14 -+#define PKT_SPDI_CONTENTS6 0xc18 -+#define PKT_SPDI_CONTENTS7 0xc1c -+#define PKT_AUDI_CONTENTS0 0xc20 -+#define PKT_AUDI_CONTENTS1 0xc24 -+#define PKT_AUDI_CONTENTS2 0xc28 -+#define PKT_AUDI_CONTENTS3 0xc2c -+#define PKT_AUDI_CONTENTS4 0xc30 -+#define PKT_AUDI_CONTENTS5 0xc34 -+#define PKT_AUDI_CONTENTS6 0xc38 -+#define PKT_AUDI_CONTENTS7 0xc3c -+#define PKT_NVI_CONTENTS0 0xc40 -+#define PKT_NVI_CONTENTS1 0xc44 -+#define PKT_NVI_CONTENTS2 0xc48 -+#define PKT_NVI_CONTENTS3 0xc4c -+#define PKT_NVI_CONTENTS4 0xc50 -+#define PKT_NVI_CONTENTS5 0xc54 -+#define PKT_NVI_CONTENTS6 0xc58 -+#define PKT_NVI_CONTENTS7 0xc5c -+#define PKT_DRMI_CONTENTS0 0xc60 -+#define PKT_DRMI_CONTENTS1 0xc64 -+#define PKT_DRMI_CONTENTS2 0xc68 -+#define PKT_DRMI_CONTENTS3 0xc6c -+#define PKT_DRMI_CONTENTS4 0xc70 -+#define PKT_DRMI_CONTENTS5 0xc74 -+#define PKT_DRMI_CONTENTS6 0xc78 -+#define PKT_DRMI_CONTENTS7 0xc7c -+#define PKT_GHDMI1_CONTENTS0 0xc80 -+#define PKT_GHDMI1_CONTENTS1 0xc84 -+#define PKT_GHDMI1_CONTENTS2 0xc88 -+#define PKT_GHDMI1_CONTENTS3 0xc8c -+#define PKT_GHDMI1_CONTENTS4 0xc90 -+#define PKT_GHDMI1_CONTENTS5 0xc94 -+#define PKT_GHDMI1_CONTENTS6 0xc98 -+#define PKT_GHDMI1_CONTENTS7 0xc9c -+#define PKT_GHDMI2_CONTENTS0 0xca0 -+#define PKT_GHDMI2_CONTENTS1 0xca4 -+#define PKT_GHDMI2_CONTENTS2 0xca8 -+#define PKT_GHDMI2_CONTENTS3 0xcac -+#define PKT_GHDMI2_CONTENTS4 0xcb0 -+#define PKT_GHDMI2_CONTENTS5 0xcb4 -+#define PKT_GHDMI2_CONTENTS6 0xcb8 -+#define PKT_GHDMI2_CONTENTS7 0xcbc -+/* EMP Packetizer Registers */ -+#define PKT_EMP_CONFIG0 0xce0 -+#define PKT_EMP_CONTROL0 0xcec -+#define PKT_EMP_CONTROL1 0xcf0 -+#define PKT_EMP_CONTROL2 0xcf4 -+#define PKT_EMP_VTEM_CONTENTS0 0xd00 -+#define PKT_EMP_VTEM_CONTENTS1 0xd04 -+#define PKT_EMP_VTEM_CONTENTS2 0xd08 -+#define PKT_EMP_VTEM_CONTENTS3 0xd0c -+#define PKT_EMP_VTEM_CONTENTS4 0xd10 -+#define PKT_EMP_VTEM_CONTENTS5 0xd14 -+#define PKT_EMP_VTEM_CONTENTS6 0xd18 -+#define PKT_EMP_VTEM_CONTENTS7 0xd1c -+#define PKT0_EMP_CVTEM_CONTENTS0 0xd20 -+#define PKT0_EMP_CVTEM_CONTENTS1 0xd24 -+#define PKT0_EMP_CVTEM_CONTENTS2 0xd28 -+#define PKT0_EMP_CVTEM_CONTENTS3 0xd2c -+#define PKT0_EMP_CVTEM_CONTENTS4 0xd30 -+#define PKT0_EMP_CVTEM_CONTENTS5 0xd34 -+#define PKT0_EMP_CVTEM_CONTENTS6 0xd38 -+#define PKT0_EMP_CVTEM_CONTENTS7 0xd3c -+#define PKT1_EMP_CVTEM_CONTENTS0 0xd40 -+#define PKT1_EMP_CVTEM_CONTENTS1 0xd44 -+#define PKT1_EMP_CVTEM_CONTENTS2 0xd48 -+#define PKT1_EMP_CVTEM_CONTENTS3 0xd4c -+#define PKT1_EMP_CVTEM_CONTENTS4 0xd50 -+#define PKT1_EMP_CVTEM_CONTENTS5 0xd54 -+#define PKT1_EMP_CVTEM_CONTENTS6 0xd58 -+#define PKT1_EMP_CVTEM_CONTENTS7 0xd5c -+#define PKT2_EMP_CVTEM_CONTENTS0 0xd60 -+#define PKT2_EMP_CVTEM_CONTENTS1 0xd64 -+#define PKT2_EMP_CVTEM_CONTENTS2 0xd68 -+#define PKT2_EMP_CVTEM_CONTENTS3 0xd6c -+#define PKT2_EMP_CVTEM_CONTENTS4 0xd70 -+#define PKT2_EMP_CVTEM_CONTENTS5 0xd74 -+#define PKT2_EMP_CVTEM_CONTENTS6 0xd78 -+#define PKT2_EMP_CVTEM_CONTENTS7 0xd7c -+#define PKT3_EMP_CVTEM_CONTENTS0 0xd80 -+#define PKT3_EMP_CVTEM_CONTENTS1 0xd84 -+#define PKT3_EMP_CVTEM_CONTENTS2 0xd88 -+#define PKT3_EMP_CVTEM_CONTENTS3 0xd8c -+#define PKT3_EMP_CVTEM_CONTENTS4 0xd90 -+#define PKT3_EMP_CVTEM_CONTENTS5 0xd94 -+#define PKT3_EMP_CVTEM_CONTENTS6 0xd98 -+#define PKT3_EMP_CVTEM_CONTENTS7 0xd9c -+#define PKT4_EMP_CVTEM_CONTENTS0 0xda0 -+#define PKT4_EMP_CVTEM_CONTENTS1 0xda4 -+#define PKT4_EMP_CVTEM_CONTENTS2 0xda8 -+#define PKT4_EMP_CVTEM_CONTENTS3 0xdac -+#define PKT4_EMP_CVTEM_CONTENTS4 0xdb0 -+#define PKT4_EMP_CVTEM_CONTENTS5 0xdb4 -+#define PKT4_EMP_CVTEM_CONTENTS6 0xdb8 -+#define PKT4_EMP_CVTEM_CONTENTS7 0xdbc -+#define PKT5_EMP_CVTEM_CONTENTS0 0xdc0 -+#define PKT5_EMP_CVTEM_CONTENTS1 0xdc4 -+#define PKT5_EMP_CVTEM_CONTENTS2 0xdc8 -+#define PKT5_EMP_CVTEM_CONTENTS3 0xdcc -+#define PKT5_EMP_CVTEM_CONTENTS4 0xdd0 -+#define PKT5_EMP_CVTEM_CONTENTS5 0xdd4 -+#define PKT5_EMP_CVTEM_CONTENTS6 0xdd8 -+#define PKT5_EMP_CVTEM_CONTENTS7 0xddc -+/* Audio Packetizer Registers */ -+#define AUDPKT_CONTROL0 0xe20 -+#define AUDPKT_PBIT_FORCE_EN_MASK BIT(12) -+#define AUDPKT_PBIT_FORCE_EN BIT(12) -+#define AUDPKT_CHSTATUS_OVR_EN_MASK BIT(0) -+#define AUDPKT_CHSTATUS_OVR_EN BIT(0) -+#define AUDPKT_CONTROL1 0xe24 -+#define AUDPKT_ACR_CONTROL0 0xe40 -+#define AUDPKT_ACR_N_VALUE 0xfffff -+#define AUDPKT_ACR_CONTROL1 0xe44 -+#define AUDPKT_ACR_CTS_OVR_VAL_MSK GENMASK(23, 4) -+#define AUDPKT_ACR_CTS_OVR_VAL(x) ((x) << 4) -+#define AUDPKT_ACR_CTS_OVR_EN_MSK BIT(1) -+#define AUDPKT_ACR_CTS_OVR_EN BIT(1) -+#define AUDPKT_ACR_STATUS0 0xe4c -+#define AUDPKT_CHSTATUS_OVR0 0xe60 -+#define AUDPKT_CHSTATUS_OVR1 0xe64 -+/* IEC60958 Byte 3: Sampleing frenuency Bits 24 to 27 */ -+#define AUDPKT_CHSTATUS_SR_MASK GENMASK(3, 0) -+#define AUDPKT_CHSTATUS_SR_22050 0x4 -+#define AUDPKT_CHSTATUS_SR_24000 0x6 -+#define AUDPKT_CHSTATUS_SR_32000 0x3 -+#define AUDPKT_CHSTATUS_SR_44100 0x0 -+#define AUDPKT_CHSTATUS_SR_48000 0x2 -+#define AUDPKT_CHSTATUS_SR_88200 0x8 -+#define AUDPKT_CHSTATUS_SR_96000 0xa -+#define AUDPKT_CHSTATUS_SR_176400 0xc -+#define AUDPKT_CHSTATUS_SR_192000 0xe -+#define AUDPKT_CHSTATUS_SR_768000 0x9 -+#define AUDPKT_CHSTATUS_SR_NOT_INDICATED 0x1 -+/* IEC60958 Byte 4: Original Sampleing frenuency Bits 36 to 39 */ -+#define AUDPKT_CHSTATUS_0SR_MASK GENMASK(15, 12) -+#define AUDPKT_CHSTATUS_OSR_8000 0x6 -+#define AUDPKT_CHSTATUS_OSR_11025 0xa -+#define AUDPKT_CHSTATUS_OSR_12000 0x2 -+#define AUDPKT_CHSTATUS_OSR_16000 0x8 -+#define AUDPKT_CHSTATUS_OSR_22050 0xb -+#define AUDPKT_CHSTATUS_OSR_24000 0x9 -+#define AUDPKT_CHSTATUS_OSR_32000 0xc -+#define AUDPKT_CHSTATUS_OSR_44100 0xf -+#define AUDPKT_CHSTATUS_OSR_48000 0xd -+#define AUDPKT_CHSTATUS_OSR_88200 0x7 -+#define AUDPKT_CHSTATUS_OSR_96000 0x5 -+#define AUDPKT_CHSTATUS_OSR_176400 0x3 -+#define AUDPKT_CHSTATUS_OSR_192000 0x1 -+#define AUDPKT_CHSTATUS_OSR_NOT_INDICATED 0x0 -+#define AUDPKT_CHSTATUS_OVR2 0xe68 -+#define AUDPKT_CHSTATUS_OVR3 0xe6c -+#define AUDPKT_CHSTATUS_OVR4 0xe70 -+#define AUDPKT_CHSTATUS_OVR5 0xe74 -+#define AUDPKT_CHSTATUS_OVR6 0xe78 -+#define AUDPKT_CHSTATUS_OVR7 0xe7c -+#define AUDPKT_CHSTATUS_OVR8 0xe80 -+#define AUDPKT_CHSTATUS_OVR9 0xe84 -+#define AUDPKT_CHSTATUS_OVR10 0xe88 -+#define AUDPKT_CHSTATUS_OVR11 0xe8c -+#define AUDPKT_CHSTATUS_OVR12 0xe90 -+#define AUDPKT_CHSTATUS_OVR13 0xe94 -+#define AUDPKT_CHSTATUS_OVR14 0xe98 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC0 0xea0 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC1 0xea4 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC2 0xea8 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC3 0xeac -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC4 0xeb0 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC5 0xeb4 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC6 0xeb8 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC7 0xebc -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC8 0xec0 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC9 0xec4 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC10 0xec8 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC11 0xecc -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC12 0xed0 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC13 0xed4 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC14 0xed8 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC15 0xedc -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC16 0xee0 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC17 0xee4 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC18 0xee8 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC19 0xeec -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC20 0xef0 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC21 0xef4 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC22 0xef8 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC23 0xefc -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC24 0xf00 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC25 0xf04 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC26 0xf08 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC27 0xf0c -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC28 0xf10 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC29 0xf14 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC30 0xf18 -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC31 0xf1c -+#define AUDPKT_USRDATA_OVR_MSG_GENERIC32 0xf20 -+#define AUDPKT_VBIT_OVR0 0xf24 -+/* CEC Registers */ -+#define CEC_TX_CONTROL 0x1000 -+#define CEC_STATUS 0x1004 -+#define CEC_CONFIG 0x1008 -+#define CEC_ADDR 0x100c -+#define CEC_TX_COUNT 0x1020 -+#define CEC_TX_DATA3_0 0x1024 -+#define CEC_TX_DATA7_4 0x1028 -+#define CEC_TX_DATA11_8 0x102c -+#define CEC_TX_DATA15_12 0x1030 -+#define CEC_RX_COUNT_STATUS 0x1040 -+#define CEC_RX_DATA3_0 0x1044 -+#define CEC_RX_DATA7_4 0x1048 -+#define CEC_RX_DATA11_8 0x104c -+#define CEC_RX_DATA15_12 0x1050 -+#define CEC_LOCK_CONTROL 0x1054 -+#define CEC_RXQUAL_BITTIME_CONFIG 0x1060 -+#define CEC_RX_BITTIME_CONFIG 0x1064 -+#define CEC_TX_BITTIME_CONFIG 0x1068 -+/* eARC RX CMDC Registers */ -+#define EARCRX_CMDC_CONFIG0 0x1800 -+#define EARCRX_XACTREAD_STOP_CFG BIT(26) -+#define EARCRX_XACTREAD_RETRY_CFG BIT(25) -+#define EARCRX_CMDC_DSCVR_EARCVALID0_TO_DISC1 BIT(24) -+#define EARCRX_CMDC_XACT_RESTART_EN BIT(18) -+#define EARCRX_CMDC_CONFIG1 0x1804 -+#define EARCRX_CMDC_CONTROL 0x1808 -+#define EARCRX_CMDC_HEARTBEAT_LOSS_EN BIT(4) -+#define EARCRX_CMDC_DISCOVERY_EN BIT(3) -+#define EARCRX_CONNECTOR_HPD BIT(1) -+#define EARCRX_CMDC_WHITELIST0_CONFIG 0x180c -+#define EARCRX_CMDC_WHITELIST1_CONFIG 0x1810 -+#define EARCRX_CMDC_WHITELIST2_CONFIG 0x1814 -+#define EARCRX_CMDC_WHITELIST3_CONFIG 0x1818 -+#define EARCRX_CMDC_STATUS 0x181c -+#define EARCRX_CMDC_XACT_INFO 0x1820 -+#define EARCRX_CMDC_XACT_ACTION 0x1824 -+#define EARCRX_CMDC_HEARTBEAT_RXSTAT_SE 0x1828 -+#define EARCRX_CMDC_HEARTBEAT_STATUS 0x182c -+#define EARCRX_CMDC_XACT_WR0 0x1840 -+#define EARCRX_CMDC_XACT_WR1 0x1844 -+#define EARCRX_CMDC_XACT_WR2 0x1848 -+#define EARCRX_CMDC_XACT_WR3 0x184c -+#define EARCRX_CMDC_XACT_WR4 0x1850 -+#define EARCRX_CMDC_XACT_WR5 0x1854 -+#define EARCRX_CMDC_XACT_WR6 0x1858 -+#define EARCRX_CMDC_XACT_WR7 0x185c -+#define EARCRX_CMDC_XACT_WR8 0x1860 -+#define EARCRX_CMDC_XACT_WR9 0x1864 -+#define EARCRX_CMDC_XACT_WR10 0x1868 -+#define EARCRX_CMDC_XACT_WR11 0x186c -+#define EARCRX_CMDC_XACT_WR12 0x1870 -+#define EARCRX_CMDC_XACT_WR13 0x1874 -+#define EARCRX_CMDC_XACT_WR14 0x1878 -+#define EARCRX_CMDC_XACT_WR15 0x187c -+#define EARCRX_CMDC_XACT_WR16 0x1880 -+#define EARCRX_CMDC_XACT_WR17 0x1884 -+#define EARCRX_CMDC_XACT_WR18 0x1888 -+#define EARCRX_CMDC_XACT_WR19 0x188c -+#define EARCRX_CMDC_XACT_WR20 0x1890 -+#define EARCRX_CMDC_XACT_WR21 0x1894 -+#define EARCRX_CMDC_XACT_WR22 0x1898 -+#define EARCRX_CMDC_XACT_WR23 0x189c -+#define EARCRX_CMDC_XACT_WR24 0x18a0 -+#define EARCRX_CMDC_XACT_WR25 0x18a4 -+#define EARCRX_CMDC_XACT_WR26 0x18a8 -+#define EARCRX_CMDC_XACT_WR27 0x18ac -+#define EARCRX_CMDC_XACT_WR28 0x18b0 -+#define EARCRX_CMDC_XACT_WR29 0x18b4 -+#define EARCRX_CMDC_XACT_WR30 0x18b8 -+#define EARCRX_CMDC_XACT_WR31 0x18bc -+#define EARCRX_CMDC_XACT_WR32 0x18c0 -+#define EARCRX_CMDC_XACT_WR33 0x18c4 -+#define EARCRX_CMDC_XACT_WR34 0x18c8 -+#define EARCRX_CMDC_XACT_WR35 0x18cc -+#define EARCRX_CMDC_XACT_WR36 0x18d0 -+#define EARCRX_CMDC_XACT_WR37 0x18d4 -+#define EARCRX_CMDC_XACT_WR38 0x18d8 -+#define EARCRX_CMDC_XACT_WR39 0x18dc -+#define EARCRX_CMDC_XACT_WR40 0x18e0 -+#define EARCRX_CMDC_XACT_WR41 0x18e4 -+#define EARCRX_CMDC_XACT_WR42 0x18e8 -+#define EARCRX_CMDC_XACT_WR43 0x18ec -+#define EARCRX_CMDC_XACT_WR44 0x18f0 -+#define EARCRX_CMDC_XACT_WR45 0x18f4 -+#define EARCRX_CMDC_XACT_WR46 0x18f8 -+#define EARCRX_CMDC_XACT_WR47 0x18fc -+#define EARCRX_CMDC_XACT_WR48 0x1900 -+#define EARCRX_CMDC_XACT_WR49 0x1904 -+#define EARCRX_CMDC_XACT_WR50 0x1908 -+#define EARCRX_CMDC_XACT_WR51 0x190c -+#define EARCRX_CMDC_XACT_WR52 0x1910 -+#define EARCRX_CMDC_XACT_WR53 0x1914 -+#define EARCRX_CMDC_XACT_WR54 0x1918 -+#define EARCRX_CMDC_XACT_WR55 0x191c -+#define EARCRX_CMDC_XACT_WR56 0x1920 -+#define EARCRX_CMDC_XACT_WR57 0x1924 -+#define EARCRX_CMDC_XACT_WR58 0x1928 -+#define EARCRX_CMDC_XACT_WR59 0x192c -+#define EARCRX_CMDC_XACT_WR60 0x1930 -+#define EARCRX_CMDC_XACT_WR61 0x1934 -+#define EARCRX_CMDC_XACT_WR62 0x1938 -+#define EARCRX_CMDC_XACT_WR63 0x193c -+#define EARCRX_CMDC_XACT_WR64 0x1940 -+#define EARCRX_CMDC_XACT_RD0 0x1960 -+#define EARCRX_CMDC_XACT_RD1 0x1964 -+#define EARCRX_CMDC_XACT_RD2 0x1968 -+#define EARCRX_CMDC_XACT_RD3 0x196c -+#define EARCRX_CMDC_XACT_RD4 0x1970 -+#define EARCRX_CMDC_XACT_RD5 0x1974 -+#define EARCRX_CMDC_XACT_RD6 0x1978 -+#define EARCRX_CMDC_XACT_RD7 0x197c -+#define EARCRX_CMDC_XACT_RD8 0x1980 -+#define EARCRX_CMDC_XACT_RD9 0x1984 -+#define EARCRX_CMDC_XACT_RD10 0x1988 -+#define EARCRX_CMDC_XACT_RD11 0x198c -+#define EARCRX_CMDC_XACT_RD12 0x1990 -+#define EARCRX_CMDC_XACT_RD13 0x1994 -+#define EARCRX_CMDC_XACT_RD14 0x1998 -+#define EARCRX_CMDC_XACT_RD15 0x199c -+#define EARCRX_CMDC_XACT_RD16 0x19a0 -+#define EARCRX_CMDC_XACT_RD17 0x19a4 -+#define EARCRX_CMDC_XACT_RD18 0x19a8 -+#define EARCRX_CMDC_XACT_RD19 0x19ac -+#define EARCRX_CMDC_XACT_RD20 0x19b0 -+#define EARCRX_CMDC_XACT_RD21 0x19b4 -+#define EARCRX_CMDC_XACT_RD22 0x19b8 -+#define EARCRX_CMDC_XACT_RD23 0x19bc -+#define EARCRX_CMDC_XACT_RD24 0x19c0 -+#define EARCRX_CMDC_XACT_RD25 0x19c4 -+#define EARCRX_CMDC_XACT_RD26 0x19c8 -+#define EARCRX_CMDC_XACT_RD27 0x19cc -+#define EARCRX_CMDC_XACT_RD28 0x19d0 -+#define EARCRX_CMDC_XACT_RD29 0x19d4 -+#define EARCRX_CMDC_XACT_RD30 0x19d8 -+#define EARCRX_CMDC_XACT_RD31 0x19dc -+#define EARCRX_CMDC_XACT_RD32 0x19e0 -+#define EARCRX_CMDC_XACT_RD33 0x19e4 -+#define EARCRX_CMDC_XACT_RD34 0x19e8 -+#define EARCRX_CMDC_XACT_RD35 0x19ec -+#define EARCRX_CMDC_XACT_RD36 0x19f0 -+#define EARCRX_CMDC_XACT_RD37 0x19f4 -+#define EARCRX_CMDC_XACT_RD38 0x19f8 -+#define EARCRX_CMDC_XACT_RD39 0x19fc -+#define EARCRX_CMDC_XACT_RD40 0x1a00 -+#define EARCRX_CMDC_XACT_RD41 0x1a04 -+#define EARCRX_CMDC_XACT_RD42 0x1a08 -+#define EARCRX_CMDC_XACT_RD43 0x1a0c -+#define EARCRX_CMDC_XACT_RD44 0x1a10 -+#define EARCRX_CMDC_XACT_RD45 0x1a14 -+#define EARCRX_CMDC_XACT_RD46 0x1a18 -+#define EARCRX_CMDC_XACT_RD47 0x1a1c -+#define EARCRX_CMDC_XACT_RD48 0x1a20 -+#define EARCRX_CMDC_XACT_RD49 0x1a24 -+#define EARCRX_CMDC_XACT_RD50 0x1a28 -+#define EARCRX_CMDC_XACT_RD51 0x1a2c -+#define EARCRX_CMDC_XACT_RD52 0x1a30 -+#define EARCRX_CMDC_XACT_RD53 0x1a34 -+#define EARCRX_CMDC_XACT_RD54 0x1a38 -+#define EARCRX_CMDC_XACT_RD55 0x1a3c -+#define EARCRX_CMDC_XACT_RD56 0x1a40 -+#define EARCRX_CMDC_XACT_RD57 0x1a44 -+#define EARCRX_CMDC_XACT_RD58 0x1a48 -+#define EARCRX_CMDC_XACT_RD59 0x1a4c -+#define EARCRX_CMDC_XACT_RD60 0x1a50 -+#define EARCRX_CMDC_XACT_RD61 0x1a54 -+#define EARCRX_CMDC_XACT_RD62 0x1a58 -+#define EARCRX_CMDC_XACT_RD63 0x1a5c -+#define EARCRX_CMDC_XACT_RD64 0x1a60 -+#define EARCRX_CMDC_SYNC_CONFIG 0x1b00 -+/* eARC RX DMAC Registers */ -+#define EARCRX_DMAC_PHY_CONTROL 0x1c00 -+#define EARCRX_DMAC_CONFIG 0x1c08 -+#define EARCRX_DMAC_CONTROL0 0x1c0c -+#define EARCRX_DMAC_AUDIO_EN BIT(1) -+#define EARCRX_DMAC_EN BIT(0) -+#define EARCRX_DMAC_CONTROL1 0x1c10 -+#define EARCRX_DMAC_STATUS 0x1c14 -+#define EARCRX_DMAC_CHSTATUS0 0x1c18 -+#define EARCRX_DMAC_CHSTATUS1 0x1c1c -+#define EARCRX_DMAC_CHSTATUS2 0x1c20 -+#define EARCRX_DMAC_CHSTATUS3 0x1c24 -+#define EARCRX_DMAC_CHSTATUS4 0x1c28 -+#define EARCRX_DMAC_CHSTATUS5 0x1c2c -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC0 0x1c30 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC1 0x1c34 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC2 0x1c38 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC3 0x1c3c -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC4 0x1c40 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC5 0x1c44 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC6 0x1c48 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC7 0x1c4c -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC8 0x1c50 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC9 0x1c54 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC10 0x1c58 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC11 0x1c5c -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT0 0x1c60 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT1 0x1c64 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT2 0x1c68 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT3 0x1c6c -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT4 0x1c70 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT5 0x1c74 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT6 0x1c78 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT7 0x1c7c -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT8 0x1c80 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT9 0x1c84 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT10 0x1c88 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT11 0x1c8c -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT0 0x1c90 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT1 0x1c94 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT2 0x1c98 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT3 0x1c9c -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT4 0x1ca0 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT5 0x1ca4 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT6 0x1ca8 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT7 0x1cac -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT8 0x1cb0 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT9 0x1cb4 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT10 0x1cb8 -+#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT11 0x1cbc -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC0 0x1cc0 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC1 0x1cc4 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC2 0x1cc8 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC3 0x1ccc -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC4 0x1cd0 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC5 0x1cd4 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC6 0x1cd8 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC7 0x1cdc -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC8 0x1ce0 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC9 0x1ce4 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC10 0x1ce8 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC11 0x1cec -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC12 0x1cf0 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC13 0x1cf4 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC14 0x1cf8 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC15 0x1cfc -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC16 0x1d00 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC17 0x1d04 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC18 0x1d08 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC19 0x1d0c -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC20 0x1d10 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC21 0x1d14 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC22 0x1d18 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC23 0x1d1c -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC24 0x1d20 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC25 0x1d24 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC26 0x1d28 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC27 0x1d2c -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC28 0x1d30 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC29 0x1d34 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC30 0x1d38 -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC31 0x1d3c -+#define EARCRX_DMAC_USRDATA_MSG_GENERIC32 0x1d40 -+#define EARCRX_DMAC_CHSTATUS_STREAMER0 0x1d44 -+#define EARCRX_DMAC_CHSTATUS_STREAMER1 0x1d48 -+#define EARCRX_DMAC_CHSTATUS_STREAMER2 0x1d4c -+#define EARCRX_DMAC_CHSTATUS_STREAMER3 0x1d50 -+#define EARCRX_DMAC_CHSTATUS_STREAMER4 0x1d54 -+#define EARCRX_DMAC_CHSTATUS_STREAMER5 0x1d58 -+#define EARCRX_DMAC_CHSTATUS_STREAMER6 0x1d5c -+#define EARCRX_DMAC_CHSTATUS_STREAMER7 0x1d60 -+#define EARCRX_DMAC_CHSTATUS_STREAMER8 0x1d64 -+#define EARCRX_DMAC_CHSTATUS_STREAMER9 0x1d68 -+#define EARCRX_DMAC_CHSTATUS_STREAMER10 0x1d6c -+#define EARCRX_DMAC_CHSTATUS_STREAMER11 0x1d70 -+#define EARCRX_DMAC_CHSTATUS_STREAMER12 0x1d74 -+#define EARCRX_DMAC_CHSTATUS_STREAMER13 0x1d78 -+#define EARCRX_DMAC_CHSTATUS_STREAMER14 0x1d7c -+#define EARCRX_DMAC_USRDATA_STREAMER0 0x1d80 -+/* Main Unit Interrupt Registers */ -+#define MAIN_INTVEC_INDEX 0x3000 -+#define MAINUNIT_0_INT_STATUS 0x3010 -+#define MAINUNIT_0_INT_MASK_N 0x3014 -+#define MAINUNIT_0_INT_CLEAR 0x3018 -+#define MAINUNIT_0_INT_FORCE 0x301c -+#define MAINUNIT_1_INT_STATUS 0x3020 -+#define FLT_EXIT_TO_LTSL_IRQ BIT(22) -+#define FLT_EXIT_TO_LTS4_IRQ BIT(21) -+#define FLT_EXIT_TO_LTSP_IRQ BIT(20) -+#define SCDC_NACK_RCVD_IRQ BIT(12) -+#define SCDC_RR_REPLY_STOP_IRQ BIT(11) -+#define SCDC_UPD_FLAGS_CLR_IRQ BIT(10) -+#define SCDC_UPD_FLAGS_CHG_IRQ BIT(9) -+#define SCDC_UPD_FLAGS_RD_IRQ BIT(8) -+#define I2CM_NACK_RCVD_IRQ BIT(2) -+#define I2CM_READ_REQUEST_IRQ BIT(1) -+#define I2CM_OP_DONE_IRQ BIT(0) -+#define MAINUNIT_1_INT_MASK_N 0x3024 -+#define I2CM_NACK_RCVD_MASK_N BIT(2) -+#define I2CM_READ_REQUEST_MASK_N BIT(1) -+#define I2CM_OP_DONE_MASK_N BIT(0) -+#define MAINUNIT_1_INT_CLEAR 0x3028 -+#define I2CM_NACK_RCVD_CLEAR BIT(2) -+#define I2CM_READ_REQUEST_CLEAR BIT(1) -+#define I2CM_OP_DONE_CLEAR BIT(0) -+#define MAINUNIT_1_INT_FORCE 0x302c -+/* AVPUNIT Interrupt Registers */ -+#define AVP_INTVEC_INDEX 0x3800 -+#define AVP_0_INT_STATUS 0x3810 -+#define AVP_0_INT_MASK_N 0x3814 -+#define AVP_0_INT_CLEAR 0x3818 -+#define AVP_0_INT_FORCE 0x381c -+#define AVP_1_INT_STATUS 0x3820 -+#define AVP_1_INT_MASK_N 0x3824 -+#define HDCP14_AUTH_CHG_MASK_N BIT(6) -+#define AVP_1_INT_CLEAR 0x3828 -+#define AVP_1_INT_FORCE 0x382c -+#define AVP_2_INT_STATUS 0x3830 -+#define AVP_2_INT_MASK_N 0x3834 -+#define AVP_2_INT_CLEAR 0x3838 -+#define AVP_2_INT_FORCE 0x383c -+#define AVP_3_INT_STATUS 0x3840 -+#define AVP_3_INT_MASK_N 0x3844 -+#define AVP_3_INT_CLEAR 0x3848 -+#define AVP_3_INT_FORCE 0x384c -+#define AVP_4_INT_STATUS 0x3850 -+#define AVP_4_INT_MASK_N 0x3854 -+#define AVP_4_INT_CLEAR 0x3858 -+#define AVP_4_INT_FORCE 0x385c -+#define AVP_5_INT_STATUS 0x3860 -+#define AVP_5_INT_MASK_N 0x3864 -+#define AVP_5_INT_CLEAR 0x3868 -+#define AVP_5_INT_FORCE 0x386c -+#define AVP_6_INT_STATUS 0x3870 -+#define AVP_6_INT_MASK_N 0x3874 -+#define AVP_6_INT_CLEAR 0x3878 -+#define AVP_6_INT_FORCE 0x387c -+/* CEC Interrupt Registers */ -+#define CEC_INT_STATUS 0x4000 -+#define CEC_INT_MASK_N 0x4004 -+#define CEC_INT_CLEAR 0x4008 -+#define CEC_INT_FORCE 0x400c -+/* eARC RX Interrupt Registers */ -+#define EARCRX_INTVEC_INDEX 0x4800 -+#define EARCRX_0_INT_STATUS 0x4810 -+#define EARCRX_CMDC_DISCOVERY_TIMEOUT_IRQ BIT(9) -+#define EARCRX_CMDC_DISCOVERY_DONE_IRQ BIT(8) -+#define EARCRX_0_INT_MASK_N 0x4814 -+#define EARCRX_0_INT_CLEAR 0x4818 -+#define EARCRX_0_INT_FORCE 0x481c -+#define EARCRX_1_INT_STATUS 0x4820 -+#define EARCRX_1_INT_MASK_N 0x4824 -+#define EARCRX_1_INT_CLEAR 0x4828 -+#define EARCRX_1_INT_FORCE 0x482c -+ -+#endif /* __DW_HDMI_QP_H__ */ -diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h -index 6a46baa0737c..a9cc4604222a 100644 ---- a/include/drm/bridge/dw_hdmi.h -+++ b/include/drm/bridge/dw_hdmi.h -@@ -131,6 +131,7 @@ struct dw_hdmi_plat_data { - unsigned long input_bus_encoding; - bool use_drm_infoframe; - bool ycbcr_420_allowed; -+ bool is_hdmi_qp; - - /* - * Private data passed to all the .mode_valid() and .configure_phy() -@@ -162,6 +163,7 @@ struct dw_hdmi_plat_data { - unsigned long mpixelclock); - - unsigned int disable_cec : 1; -+ - }; - - struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, -@@ -206,6 +208,12 @@ void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data, - bool force, bool disabled, bool rxsense); - void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data); - -+void dw_hdmi_qp_unbind(struct dw_hdmi *hdmi); -+struct dw_hdmi *dw_hdmi_qp_bind(struct platform_device *pdev, -+ struct drm_encoder *encoder, -+ struct dw_hdmi_plat_data *plat_data); -+void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi *hdmi); -+ - bool dw_hdmi_bus_fmt_is_420(struct dw_hdmi *hdmi); - - #endif /* __IMX_HDMI_H__ */ --- -2.44.1 - - -From aad4f4cecc70fa0170fcad63933585f71c975164 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Mon, 20 May 2024 15:07:08 +0300 -Subject: [PATCH 51/54] drm/rockchip: dw_hdmi: Add basic RK3588 support - -RK3588 SoC updated the Synopsis DesignWare HDMI transmitter used in the -older SoCs to Quad-Pixel (QP) variant, which is HDMI 2.1 compliant, -while making use of a HDMI/eDP TX Combo PHY based on a Samsung IP block. - -Add just the basic support for now, i.e. RGB output up to 4K@30Hz, -without audio, CEC or any of the HDMI 2.1 specific features. - -Co-developed-by: Algea Cao -Signed-off-by: Algea Cao -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 261 +++++++++++++++++++- - 1 file changed, 253 insertions(+), 8 deletions(-) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index ca6728a43159..70f7006bde08 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -29,8 +29,8 @@ - - #define RK3288_GRF_SOC_CON6 0x025C - #define RK3288_HDMI_LCDC_SEL BIT(4) --#define RK3328_GRF_SOC_CON2 0x0408 - -+#define RK3328_GRF_SOC_CON2 0x0408 - #define RK3328_HDMI_SDAIN_MSK BIT(11) - #define RK3328_HDMI_SCLIN_MSK BIT(10) - #define RK3328_HDMI_HPD_IOE BIT(2) -@@ -54,6 +54,21 @@ - #define RK3568_HDMI_SDAIN_MSK BIT(15) - #define RK3568_HDMI_SCLIN_MSK BIT(14) - -+#define RK3588_GRF_SOC_CON2 0x0308 -+#define RK3588_HDMI0_HPD_INT_MSK BIT(13) -+#define RK3588_HDMI0_HPD_INT_CLR BIT(12) -+#define RK3588_GRF_SOC_CON7 0x031c -+#define RK3588_SET_HPD_PATH_MASK (0x3 << 12) -+#define RK3588_GRF_SOC_STATUS1 0x0384 -+#define RK3588_HDMI0_LEVEL_INT BIT(16) -+#define RK3588_GRF_VO1_CON3 0x000c -+#define RK3588_SCLIN_MASK BIT(9) -+#define RK3588_SDAIN_MASK BIT(10) -+#define RK3588_MODE_MASK BIT(11) -+#define RK3588_I2S_SEL_MASK BIT(13) -+#define RK3588_GRF_VO1_CON9 0x0024 -+#define RK3588_HDMI0_GRANT_SEL BIT(10) -+ - #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) - - /** -@@ -71,6 +86,7 @@ struct rockchip_hdmi_chip_data { - struct rockchip_hdmi { - struct device *dev; - struct regmap *regmap; -+ struct regmap *vo1_regmap; - struct rockchip_encoder encoder; - const struct rockchip_hdmi_chip_data *chip_data; - const struct dw_hdmi_plat_data *plat_data; -@@ -78,6 +94,10 @@ struct rockchip_hdmi { - struct clk *grf_clk; - struct dw_hdmi *hdmi; - struct phy *phy; -+ -+ bool is_hdmi_qp; -+ struct gpio_desc *qp_enable_gpio; -+ struct delayed_work qp_hpd_work; - }; - - static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder) -@@ -206,8 +226,12 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = { - - static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) - { -+ static const char * const qp_clk_names[] = { -+ "pclk", "hdp", "earc", "aud", "hclk_vo1", -+ }; - struct device_node *np = hdmi->dev->of_node; -- int ret; -+ struct clk *qp_clk; -+ int ret, i; - - hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); - if (IS_ERR(hdmi->regmap)) { -@@ -234,6 +258,34 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) - return ret; - } - -+ if (hdmi->is_hdmi_qp) { -+ hdmi->vo1_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,vo1_grf"); -+ if (IS_ERR(hdmi->vo1_regmap)) { -+ drm_err(hdmi, "Unable to get rockchip,vo1_grf\n"); -+ return PTR_ERR(hdmi->vo1_regmap); -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(qp_clk_names); i++) { -+ qp_clk = devm_clk_get_optional_enabled(hdmi->dev, qp_clk_names[i]); -+ -+ if (IS_ERR(qp_clk)) { -+ ret = PTR_ERR(qp_clk); -+ if (ret != -EPROBE_DEFER) -+ drm_err(hdmi, "failed to get %s clock: %d\n", -+ qp_clk_names[i], ret); -+ return ret; -+ } -+ } -+ -+ hdmi->qp_enable_gpio = devm_gpiod_get_optional(hdmi->dev, "enable", -+ GPIOD_OUT_HIGH); -+ if (IS_ERR(hdmi->qp_enable_gpio)) { -+ ret = PTR_ERR(hdmi->qp_enable_gpio); -+ drm_err(hdmi, "failed to request enable GPIO: %d\n", ret); -+ return ret; -+ } -+ } -+ - ret = devm_regulator_get_enable(hdmi->dev, "avdd-0v9"); - if (ret) - return ret; -@@ -303,8 +355,32 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, - static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) - { - struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); -+ struct drm_crtc *crtc = encoder->crtc; - u32 val; -- int ret; -+ int ret, rate; -+ -+ if (hdmi->is_hdmi_qp) { -+ /* Unconditionally switch to TMDS as FRL is not yet supported */ -+ gpiod_set_value(hdmi->qp_enable_gpio, 1); -+ -+ if (crtc && crtc->state) { -+ clk_set_rate(hdmi->ref_clk, -+ crtc->state->adjusted_mode.crtc_clock * 1000); -+ /* -+ * FIXME: Temporary workaround to pass pixel clock rate -+ * to the PHY driver until phy_configure_opts_hdmi -+ * becomes available in the PHY API. See also the related -+ * comment in rk_hdptx_phy_power_on() from -+ * drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c -+ */ -+ if (hdmi->phy) { -+ rate = crtc->state->mode.clock * 10; -+ phy_set_bus_width(hdmi->phy, rate); -+ drm_dbg(hdmi, "%s set bus_width=%u\n", -+ __func__, rate); -+ } -+ } -+ } - - if (hdmi->chip_data->lcdsel_grf_reg < 0) - return; -@@ -356,6 +432,9 @@ static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, - { - struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; - -+ if (hdmi->is_hdmi_qp) -+ dw_hdmi_set_high_tmds_clock_ratio(dw_hdmi, display); -+ - return phy_power_on(hdmi->phy); - } - -@@ -430,6 +509,29 @@ static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data) - RK3328_HDMI_HPD_IOE)); - } - -+static enum drm_connector_status -+dw_hdmi_rk3588_read_hpd(struct dw_hdmi *dw_hdmi, void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ u32 val; -+ -+ regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &val); -+ -+ return val & RK3588_HDMI0_LEVEL_INT ? -+ connector_status_connected : connector_status_disconnected; -+} -+ -+static void dw_hdmi_rk3588_setup_hpd(struct dw_hdmi *dw_hdmi, void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ regmap_write(hdmi->regmap, -+ RK3588_GRF_SOC_CON2, -+ HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, -+ RK3588_HDMI0_HPD_INT_CLR | -+ RK3588_HDMI0_HPD_INT_MSK)); -+} -+ - static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = { - .init = dw_hdmi_rockchip_genphy_init, - .disable = dw_hdmi_rockchip_genphy_disable, -@@ -513,6 +615,82 @@ static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = { - .use_drm_infoframe = true, - }; - -+static const struct dw_hdmi_phy_ops rk3588_hdmi_phy_ops = { -+ .init = dw_hdmi_rockchip_genphy_init, -+ .disable = dw_hdmi_rockchip_genphy_disable, -+ .read_hpd = dw_hdmi_rk3588_read_hpd, -+ .setup_hpd = dw_hdmi_rk3588_setup_hpd, -+}; -+ -+struct rockchip_hdmi_chip_data rk3588_chip_data = { -+ .lcdsel_grf_reg = -1, -+}; -+ -+static const struct dw_hdmi_plat_data rk3588_hdmi_drv_data = { -+ .phy_data = &rk3588_chip_data, -+ .phy_ops = &rk3588_hdmi_phy_ops, -+ .phy_name = "samsung_hdptx_phy", -+ .phy_force_vendor = true, -+ .use_drm_infoframe = true, -+ .is_hdmi_qp = true, -+}; -+ -+static void dw_hdmi_rk3588_hpd_work(struct work_struct *p_work) -+{ -+ struct rockchip_hdmi *hdmi = container_of(p_work, struct rockchip_hdmi, -+ qp_hpd_work.work); -+ -+ struct drm_device *drm = hdmi->encoder.encoder.dev; -+ bool changed; -+ -+ if (drm) { -+ changed = drm_helper_hpd_irq_event(drm); -+ if (changed) -+ drm_dbg(hdmi, "connector status changed\n"); -+ } -+} -+ -+static irqreturn_t dw_hdmi_rk3588_hardirq(int irq, void *dev_id) -+{ -+ struct rockchip_hdmi *hdmi = dev_id; -+ u32 intr_stat, val; -+ -+ regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat); -+ -+ if (intr_stat) { -+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, -+ RK3588_HDMI0_HPD_INT_MSK); -+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); -+ return IRQ_WAKE_THREAD; -+ } -+ -+ return IRQ_NONE; -+} -+ -+static irqreturn_t dw_hdmi_rk3588_irq(int irq, void *dev_id) -+{ -+ struct rockchip_hdmi *hdmi = dev_id; -+ u32 intr_stat, val; -+ int debounce_ms; -+ -+ regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat); -+ if (!intr_stat) -+ return IRQ_NONE; -+ -+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, -+ RK3588_HDMI0_HPD_INT_CLR); -+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); -+ -+ debounce_ms = intr_stat & RK3588_HDMI0_LEVEL_INT ? 150 : 20; -+ mod_delayed_work(system_wq, &hdmi->qp_hpd_work, -+ msecs_to_jiffies(debounce_ms)); -+ -+ val |= HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK); -+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); -+ -+ return IRQ_HANDLED; -+} -+ - static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { - { .compatible = "rockchip,rk3228-dw-hdmi", - .data = &rk3228_hdmi_drv_data -@@ -529,6 +707,9 @@ static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { - { .compatible = "rockchip,rk3568-dw-hdmi", - .data = &rk3568_hdmi_drv_data - }, -+ { .compatible = "rockchip,rk3588-dw-hdmi", -+ .data = &rk3588_hdmi_drv_data -+ }, - {}, - }; - MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids); -@@ -542,7 +723,8 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - struct drm_device *drm = data; - struct drm_encoder *encoder; - struct rockchip_hdmi *hdmi; -- int ret; -+ int ret, irq; -+ u32 val; - - if (!pdev->dev.of_node) - return -ENODEV; -@@ -553,13 +735,14 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - - match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node); - plat_data = devm_kmemdup(&pdev->dev, match->data, -- sizeof(*plat_data), GFP_KERNEL); -+ sizeof(*plat_data), GFP_KERNEL); - if (!plat_data) - return -ENOMEM; - - hdmi->dev = &pdev->dev; - hdmi->plat_data = plat_data; - hdmi->chip_data = plat_data->phy_data; -+ hdmi->is_hdmi_qp = plat_data->is_hdmi_qp; - plat_data->phy_data = hdmi; - plat_data->priv_data = hdmi; - encoder = &hdmi->encoder.encoder; -@@ -598,6 +781,37 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - RK3568_HDMI_SCLIN_MSK, - RK3568_HDMI_SDAIN_MSK | - RK3568_HDMI_SCLIN_MSK)); -+ } else if (hdmi->is_hdmi_qp) { -+ val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) | -+ HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) | -+ HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) | -+ HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK); -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val); -+ -+ val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, -+ RK3588_SET_HPD_PATH_MASK); -+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val); -+ -+ val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL, -+ RK3588_HDMI0_GRANT_SEL); -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON9, val); -+ -+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK); -+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); -+ -+ INIT_DELAYED_WORK(&hdmi->qp_hpd_work, dw_hdmi_rk3588_hpd_work); -+ -+ irq = platform_get_irq(pdev, 4); -+ if (irq < 0) -+ return irq; -+ -+ ret = devm_request_threaded_irq(hdmi->dev, irq, -+ dw_hdmi_rk3588_hardirq, -+ dw_hdmi_rk3588_irq, -+ IRQF_SHARED, "dw-hdmi-qp-hpd", -+ hdmi); -+ if (ret) -+ return ret; - } - - drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); -@@ -605,7 +819,10 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - - platform_set_drvdata(pdev, hdmi); - -- hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data); -+ if (hdmi->is_hdmi_qp) -+ hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, plat_data); -+ else -+ hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data); - - /* - * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), -@@ -629,7 +846,13 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, - { - struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); - -- dw_hdmi_unbind(hdmi->hdmi); -+ if (hdmi->is_hdmi_qp) { -+ cancel_delayed_work_sync(&hdmi->qp_hpd_work); -+ dw_hdmi_qp_unbind(hdmi->hdmi); -+ } else { -+ dw_hdmi_unbind(hdmi->hdmi); -+ } -+ - drm_encoder_cleanup(&hdmi->encoder.encoder); - } - -@@ -651,8 +874,30 @@ static void dw_hdmi_rockchip_remove(struct platform_device *pdev) - static int __maybe_unused dw_hdmi_rockchip_resume(struct device *dev) - { - struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); -+ u32 val; -+ -+ if (hdmi->is_hdmi_qp) { -+ val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) | -+ HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) | -+ HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) | -+ HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK); -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val); - -- dw_hdmi_resume(hdmi->hdmi); -+ val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, -+ RK3588_SET_HPD_PATH_MASK); -+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val); -+ -+ val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL, -+ RK3588_HDMI0_GRANT_SEL); -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON9, val); -+ -+ dw_hdmi_qp_resume(dev, hdmi->hdmi); -+ -+ if (hdmi->encoder.encoder.dev) -+ drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev); -+ } else { -+ dw_hdmi_resume(hdmi->hdmi); -+ } - - return 0; - } --- -2.44.1 - - -From 4682a4746176a2d0dbeb71e6085a12391aa3c5dd Mon Sep 17 00:00:00 2001 -From: Detlev Casanova -Date: Fri, 3 May 2024 14:27:39 -0400 -Subject: [PATCH 52/54] vop2: Add clock resets support - -At the end of initialization, each VP clock needs to be reset before -they can be used. - -Failing to do so can put the VOP in an undefined state where the -generated HDMI signal is either lost or not matching the selected mode. - -Signed-off-by: Detlev Casanova ---- - drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 30 ++++++++++++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -index 86d2c15af39f..6f626f2f198a 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - #include - - #include -@@ -159,6 +160,7 @@ struct vop2_win { - struct vop2_video_port { - struct drm_crtc crtc; - struct vop2 *vop2; -+ struct reset_control *dclk_rst; - struct clk *dclk; - unsigned int id; - const struct vop2_video_port_data *data; -@@ -2064,6 +2066,26 @@ static struct vop2_clk *vop2_clk_get(struct vop2 *vop2, const char *name) - return NULL; - } - -+static int vop2_clk_reset(struct vop2_video_port *vp) -+{ -+ struct reset_control *rstc = vp->dclk_rst; -+ struct vop2 *vop2 = vp->vop2; -+ int ret; -+ -+ if (!rstc) -+ return 0; -+ -+ ret = reset_control_assert(rstc); -+ if (ret < 0) -+ drm_warn(vop2->drm, "failed to assert reset\n"); -+ udelay(10); -+ ret = reset_control_deassert(rstc); -+ if (ret < 0) -+ drm_warn(vop2->drm, "failed to deassert reset\n"); -+ -+ return ret; -+} -+ - static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - struct drm_atomic_state *state) - { -@@ -2233,6 +2255,8 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - - vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl); - -+ vop2_clk_reset(vp); -+ - drm_crtc_vblank_on(crtc); - - vop2_unlock(vop2); -@@ -2920,6 +2944,12 @@ static int vop2_create_crtcs(struct vop2 *vop2) - vp->data = vp_data; - - snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id); -+ vp->dclk_rst = devm_reset_control_get_optional(vop2->dev, dclk_name); -+ if (IS_ERR(vp->dclk_rst)) { -+ drm_err(vop2->drm, "failed to get %s reset\n", dclk_name); -+ return PTR_ERR(vp->dclk_rst); -+ } -+ - vp->dclk = devm_clk_get(vop2->dev, dclk_name); - if (IS_ERR(vp->dclk)) { - drm_err(vop2->drm, "failed to get %s\n", dclk_name); --- -2.44.1 - - -From ec32c5f52b353b97633cc166e5b1e8342d2ae78e Mon Sep 17 00:00:00 2001 -From: Detlev Casanova -Date: Fri, 3 May 2024 14:28:12 -0400 -Subject: [PATCH 53/54] arm64: dts: rockchip: Add VOP clock resets for rk3588s - -This adds the needed clock resets for all rk3588(s) based SOCs. - -Signed-off-by: Detlev Casanova ---- - arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -index eb1aa7d8e475..0fecbf46e127 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -@@ -1403,6 +1403,14 @@ vop: vop@fdd90000 { - "pclk_vop"; - iommus = <&vop_mmu>; - power-domains = <&power RK3588_PD_VOP>; -+ resets = <&cru SRST_D_VOP0>, -+ <&cru SRST_D_VOP1>, -+ <&cru SRST_D_VOP2>, -+ <&cru SRST_D_VOP3>; -+ reset-names = "dclk_vp0", -+ "dclk_vp1", -+ "dclk_vp2", -+ "dclk_vp3"; - rockchip,grf = <&sys_grf>; - rockchip,vop-grf = <&vop_grf>; - rockchip,vo1-grf = <&vo1_grf>; --- -2.44.1 - - -From dc492a647595f2866fb2e20ccf576bcaff42a109 Mon Sep 17 00:00:00 2001 -From: Detlev Casanova -Date: Mon, 6 May 2024 13:54:01 -0400 -Subject: [PATCH 54/54] dt-bindings: display: vop2: Add VP clock resets - -Add the documentation for VOP2 video ports reset clocks. -One reset can be set per video port. - -Signed-off-by: Detlev Casanova ---- - .../display/rockchip/rockchip-vop2.yaml | 27 +++++++++++++++++++ - 1 file changed, 27 insertions(+) - -diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml -index 2531726af306..941fd059498d 100644 ---- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml -+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml -@@ -65,6 +65,22 @@ properties: - - const: dclk_vp3 - - const: pclk_vop - -+ resets: -+ minItems: 3 -+ items: -+ - description: Pixel clock reset for video port 0. -+ - description: Pixel clock reset for video port 1. -+ - description: Pixel clock reset for video port 2. -+ - description: Pixel clock reset for video port 3. -+ -+ reset-names: -+ minItems: 3 -+ items: -+ - const: dclk_vp0 -+ - const: dclk_vp1 -+ - const: dclk_vp2 -+ - const: dclk_vp3 -+ - rockchip,grf: - $ref: /schemas/types.yaml#/definitions/phandle - description: -@@ -128,6 +144,11 @@ allOf: - clock-names: - minItems: 7 - -+ resets: -+ minItems: 4 -+ reset-names: -+ minItems: 4 -+ - ports: - required: - - port@0 -@@ -183,6 +204,12 @@ examples: - "dclk_vp0", - "dclk_vp1", - "dclk_vp2"; -+ resets = <&cru SRST_VOP0>, -+ <&cru SRST_VOP1>, -+ <&cru SRST_VOP2>; -+ reset-names = "dclk_vp0", -+ "dclk_vp1", -+ "dclk_vp2"; - power-domains = <&power RK3568_PD_VO>; - iommus = <&vop_mmu>; - vop_out: ports { --- -2.44.1 -