From 3c4ca982ecdfa8809b92cf3f6bdd05de397f8de2 Mon Sep 17 00:00:00 2001 From: chayleaf Date: Sat, 27 Jan 2024 03:57:21 +0700 Subject: [PATCH] update inputs --- flake.lock | 119 +- flake.nix | 9 +- home/modules/gui.nix | 2 +- overlays.nix | 7 +- pkgs/_sources/generated.json | 14 +- pkgs/_sources/generated.nix | 14 +- pkgs/default.nix | 67 +- pkgs/firefox-addons/generated.nix | 16 +- system/devices/radxa-rock5a-server.nix | 7 +- .../oneplus-enchilada/linux_6_7.patch | 16195 +++----------- system/hardware/oneplus-enchilada/pkgs.nix | 11 +- system/hardware/radxa-rock5a/default.nix | 14 +- system/hardware/radxa-rock5a/linux_6.7.patch | 17516 ---------------- system/hosts/router/metrics.nix | 2 +- system/hosts/server/files.nix | 4 +- system/hosts/server/home.nix | 14 +- system/hosts/server/maubot.nix | 3 - system/modules/ping-exporter.nix | 6 +- 18 files changed, 3297 insertions(+), 30723 deletions(-) delete mode 100644 system/hardware/radxa-rock5a/linux_6.7.patch diff --git a/flake.lock b/flake.lock index a50109a..2e0872c 100644 --- a/flake.lock +++ b/flake.lock @@ -92,22 +92,6 @@ } }, "flake-compat_3": { - "flake": false, - "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-compat_4": { "flake": false, "locked": { "lastModified": 1668681692, @@ -128,11 +112,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1698882062, - "narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=", + "lastModified": 1704982712, + "narHash": "sha256-2Ptt+9h8dczgle2Oo6z5ni5rt/uLMG47UFTR1ry/wgg=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "8c9fa2545007b49a5db5f650ae91f227672c3877", + "rev": "07f6395285469419cf9d078f59b5b49993198c00", "type": "github" }, "original": { @@ -166,11 +150,11 @@ ] }, "locked": { - "lastModified": 1700553346, - "narHash": "sha256-kW7uWsCv/lxuA824Ng6EYD9hlVYRyjuFn0xBbYltAeQ=", + "lastModified": 1706473109, + "narHash": "sha256-iyuAvpKTsq2u23Cr07RcV5XlfKExrG8gRpF75hf1uVc=", "owner": "nix-community", "repo": "home-manager", - "rev": "1aabb0a31b25ad83cfaa37c3fe29053417cd9a0f", + "rev": "d634c3abafa454551f2083b054cd95c3f287be61", "type": "github" }, "original": { @@ -181,11 +165,11 @@ }, "impermanence": { "locked": { - "lastModified": 1697303681, - "narHash": "sha256-caJ0rXeagaih+xTgRduYtYKL1rZ9ylh06CIrt1w5B4g=", + "lastModified": 1703656108, + "narHash": "sha256-hCSUqdFJKHHbER8Cenf5JRzjMlBjIdwdftGQsO0xoJs=", "owner": "nix-community", "repo": "impermanence", - "rev": "0f317c2e9e56550ce12323eb39302d251618f5b5", + "rev": "033643a45a4a920660ef91caa391fbffb14da466", "type": "github" }, "original": { @@ -194,27 +178,6 @@ "type": "github" } }, - "maubot": { - "inputs": { - "flake-compat": "flake-compat_3", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1700661503, - "narHash": "sha256-2GGbVFmAC8G1FLxIabCBYhfbUeUIZM/3p2VW9Eia60Q=", - "owner": "chayleaf", - "repo": "maubot.nix", - "rev": "71d397c5897233c592d35be6c4f28c295ce2e79d", - "type": "github" - }, - "original": { - "owner": "chayleaf", - "repo": "maubot.nix", - "type": "github" - } - }, "mobile-nixos": { "flake": false, "locked": { @@ -240,11 +203,11 @@ ] }, "locked": { - "lastModified": 1700616016, - "narHash": "sha256-GCD2U3jMWmBqJccDDXr8pf2Ia2NnFiIYqnm9wK1DxLk=", + "lastModified": 1706482802, + "narHash": "sha256-KXwKTfqFkoPpV8QqaVlpmO8w8rD/jHZL2315RL5QQ8w=", "owner": "fufexan", "repo": "nix-gaming", - "rev": "7d81bdbf62936d50906609097b1fd6e68e59daa7", + "rev": "8f354ef64cd18898b8980ecf7fe90118808b514b", "type": "github" }, "original": { @@ -260,11 +223,11 @@ ] }, "locked": { - "lastModified": 1700967448, - "narHash": "sha256-sWVi7Nm/fuTgwN8R7Tt3GM3vBP3r6M1/lhX0+LK3p7E=", + "lastModified": 1706411424, + "narHash": "sha256-BzziJYucEZvdCE985vjPoo3ztWcmUiSQ1wJ2CoT6jCc=", "owner": "nix-community", "repo": "nix-index-database", - "rev": "d189d05f9de237d3b554c91029f9cb78efec8ace", + "rev": "c782f2a4f6fc94311ab5ef31df2f1149a1856181", "type": "github" }, "original": { @@ -275,11 +238,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1700559156, - "narHash": "sha256-gL4epO/qf+wo30JjC3g+b5Bs8UrpxzkhNBBsUYxpw2g=", + "lastModified": 1706182238, + "narHash": "sha256-Ti7CerGydU7xyrP/ow85lHsOpf+XMx98kQnPoQCSi1g=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "c3abafb01cd7045dba522af29b625bd1e170c2fb", + "rev": "f84eaffc35d1a655e84749228cde19922fcf55f1", "type": "github" }, "original": { @@ -291,24 +254,24 @@ "nixos-mailserver": { "inputs": { "blobs": "blobs", - "flake-compat": "flake-compat_4", + "flake-compat": "flake-compat_3", "nixpkgs": [ "nixpkgs" ], - "nixpkgs-22_11": [ - "nixpkgs" - ], "nixpkgs-23_05": [ "nixpkgs" ], + "nixpkgs-23_11": [ + "nixpkgs" + ], "utils": "utils" }, "locked": { - "lastModified": 1700085753, - "narHash": "sha256-qtib7f3eRwfaUF+VziJXiBcZFqpHCAXS4HlrFsnzzl4=", + "lastModified": 1706219574, + "narHash": "sha256-qO+8UErk+bXCq2ybHU4GzXG4Ejk4Tk0rnnTPNyypW4g=", "owner": "simple-nixos-mailserver", "repo": "nixos-mailserver", - "rev": "008d78cc21959e33d0d31f375b88353a7d7121ae", + "rev": "e47f3719f1db3e0961a4358d4cb234a0acaa7baf", "type": "gitlab" }, "original": { @@ -324,11 +287,11 @@ ] }, "locked": { - "lastModified": 1701027558, - "narHash": "sha256-rINl9hvpQLfQtrXUy+R8bAtkKnU/1yOajVLfpFh0qWg=", + "lastModified": 1706386221, + "narHash": "sha256-fMBhmJqm6yihdweMmi+NPV4SFj2WXOQSpAwfKoLGyRE=", "owner": "chayleaf", "repo": "nixos-router", - "rev": "c69ede702d9e8d367cc45cc8869f549eccc90ea1", + "rev": "af7d975e755702b649a386c57b44665d56c80d7a", "type": "github" }, "original": { @@ -339,15 +302,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1701951621, - "narHash": "sha256-97wdVG/CHlHkWqd8Y+1PvLrNBp91tf0esBURFVT8KSA=", + "lastModified": 1706397479, + "narHash": "sha256-f5aOlL5eKiOkQy89sOvN653Yue1r/aXWTCL/Kz1iRMc=", "owner": "chayleaf", "repo": "nixpkgs", - "rev": "b4ba55d440f4eb00379307b7c2f0279b5d24b68b", + "rev": "74ece655ded61dc9cb4a718cb574a73bb34a68bf", "type": "github" }, "original": { "owner": "chayleaf", + "ref": "ci", "repo": "nixpkgs", "type": "github" } @@ -355,11 +319,11 @@ "nixpkgs-lib": { "locked": { "dir": "lib", - "lastModified": 1698611440, - "narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=", + "lastModified": 1703961334, + "narHash": "sha256-M1mV/Cq+pgjk0rt6VxoyyD+O8cOUiai8t9Q6Yyq4noY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735", + "rev": "b0d36bd0a420ecee3bc916c91886caca87c894e9", "type": "github" }, "original": { @@ -412,11 +376,11 @@ }, "nur": { "locked": { - "lastModified": 1700660661, - "narHash": "sha256-1+//5oLdqYo8ptS/ZpaGEzgnQ6FWJOjLPyTuiD6mPjY=", + "lastModified": 1706607970, + "narHash": "sha256-q5W32qx3HhozhAT75AerVqOnhgvNrSyFrjAlu4qNYCU=", "owner": "nix-community", "repo": "NUR", - "rev": "0707dd061f4fb82393f3c96c6ed10c60396d7f9c", + "rev": "d7e286c21530da5d6da54424d64e15de14f7c07a", "type": "github" }, "original": { @@ -431,7 +395,6 @@ "flake-compat": "flake-compat_2", "home-manager": "home-manager", "impermanence": "impermanence", - "maubot": "maubot", "mobile-nixos": "mobile-nixos", "nix-gaming": "nix-gaming", "nix-index-database": "nix-index-database", @@ -453,11 +416,11 @@ ] }, "locked": { - "lastModified": 1700619457, - "narHash": "sha256-zjmlh8xo4UsNdw7nMyiHgQg1xXNcJnpdMLvyunnnitQ=", + "lastModified": 1706580650, + "narHash": "sha256-e6q4Pn1dp3NoQJdMYdyNdDHU5IRBW9i3bHSJ3jThEL0=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "7c94410d52d4e8bd72803fc1fe6c51fe179edaf5", + "rev": "39e20b3c02caa91c9970beef325a04975d83d77f", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 5878f84..abe1a46 100644 --- a/flake.nix +++ b/flake.nix @@ -4,7 +4,7 @@ inputs = { #nixpkgs.url = "github:NixOS/nixpkgs/3dc2b4f8166f744c3b3e9ff8224e7c5d74a5424f"; # nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - nixpkgs.url = "github:chayleaf/nixpkgs"; + nixpkgs.url = "github:chayleaf/nixpkgs/ci"; nixos-hardware.url = "github:NixOS/nixos-hardware"; nix-index-database = { url = "github:nix-community/nix-index-database"; @@ -45,17 +45,13 @@ url = "github:chayleaf/nixos-router"; inputs.nixpkgs.follows = "nixpkgs"; }; - maubot = { - url = "github:chayleaf/maubot.nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; nixos-mailserver = { url = "gitlab:simple-nixos-mailserver/nixos-mailserver"; inputs.nixpkgs.follows = "nixpkgs"; # prevent extra input from being in flake.lock # (this doesn't affect any behavior) - inputs.nixpkgs-22_11.follows = "nixpkgs"; inputs.nixpkgs-23_05.follows = "nixpkgs"; + inputs.nixpkgs-23_11.follows = "nixpkgs"; }; flake-compat = { url = "github:edolstra/flake-compat"; @@ -69,7 +65,6 @@ # it takes the paths for modules from filesystem as opposed to flake inputs dev = { # coop-ofd = true; - # maubot = true; # mobile-nixos = true; # nixos-router = true; # notnft = true; diff --git a/home/modules/gui.nix b/home/modules/gui.nix index cdce9e3..9ee22df 100644 --- a/home/modules/gui.nix +++ b/home/modules/gui.nix @@ -187,7 +187,7 @@ # profiles = { }; package = pkgs.wrapMpv ((pkgs.mpv-unwrapped.override { # webp support - ffmpeg = pkgs.ffmpeg-custom; + ffmpeg = pkgs.ffmpeg-full; }).overrideAttrs (old: { patches = old.patches or [] ++ [ (pkgs.fetchpatch { diff --git a/overlays.nix b/overlays.nix index 0306c13..1c980c5 100644 --- a/overlays.nix +++ b/overlays.nix @@ -1,2 +1,5 @@ -# [ (import (builtins.fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz")) ] -[ (import ).overlays.default (import ) (import ).overlays.default ] +[ + (import ).overlays.default + (import ) + (import ).overlays.default +] diff --git a/pkgs/_sources/generated.json b/pkgs/_sources/generated.json index 68ccc66..d4e4180 100644 --- a/pkgs/_sources/generated.json +++ b/pkgs/_sources/generated.json @@ -22,24 +22,24 @@ "pinned": false, "src": { "name": null, - "sha256": "sha256-72jxUJdn4j0FV1qFH0r7UEVrAvSwrWgWsxCXyT1N/1A=", + "sha256": "sha256-5fEYhazqXcMENjp+37IcF5U81vZ9bPDkS0siUVi9mdg=", "type": "url", - "url": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton8-24/GE-Proton8-24.tar.gz" + "url": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton8-27/GE-Proton8-27.tar.gz" }, - "version": "GE-Proton8-24" + "version": "GE-Proton8-27" }, "searxng": { "cargoLocks": null, - "date": "2023-11-14", + "date": "2024-01-25", "extract": null, "name": "searxng", "passthru": null, "pinned": false, "src": { - "sha256": "sha256-vgDQ7cdWN79TFEbJGq0AdvC8p2YOmogk9iVViDkZDXw=", + "sha256": "sha256-QW1xC6RsHpn5P/QHjyc3O24tSmLvRCVIJwNqPyp1DV0=", "type": "tarball", - "url": "https://github.com/searxng/searxng/archive/b3d29cb86db4cc1a4e6320016529d1361451e1f1.tar.gz" + "url": "https://github.com/searxng/searxng/archive/8c73aa772b7d4446f77be82d8f9d9eef1e348deb.tar.gz" }, - "version": "b3d29cb86db4cc1a4e6320016529d1361451e1f1" + "version": "8c73aa772b7d4446f77be82d8f9d9eef1e348deb" } } \ No newline at end of file diff --git a/pkgs/_sources/generated.nix b/pkgs/_sources/generated.nix index bbc0dc7..4ae7758 100644 --- a/pkgs/_sources/generated.nix +++ b/pkgs/_sources/generated.nix @@ -12,19 +12,19 @@ }; proton-ge = { pname = "proton-ge"; - version = "GE-Proton8-24"; + version = "GE-Proton8-27"; src = fetchurl { - url = "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton8-24/GE-Proton8-24.tar.gz"; - sha256 = "sha256-72jxUJdn4j0FV1qFH0r7UEVrAvSwrWgWsxCXyT1N/1A="; + url = "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton8-27/GE-Proton8-27.tar.gz"; + sha256 = "sha256-5fEYhazqXcMENjp+37IcF5U81vZ9bPDkS0siUVi9mdg="; }; }; searxng = { pname = "searxng"; - version = "b3d29cb86db4cc1a4e6320016529d1361451e1f1"; + version = "8c73aa772b7d4446f77be82d8f9d9eef1e348deb"; src = fetchTarball { - url = "https://github.com/searxng/searxng/archive/b3d29cb86db4cc1a4e6320016529d1361451e1f1.tar.gz"; - sha256 = "sha256-vgDQ7cdWN79TFEbJGq0AdvC8p2YOmogk9iVViDkZDXw="; + url = "https://github.com/searxng/searxng/archive/8c73aa772b7d4446f77be82d8f9d9eef1e348deb.tar.gz"; + sha256 = "sha256-QW1xC6RsHpn5P/QHjyc3O24tSmLvRCVIJwNqPyp1DV0="; }; - date = "2023-11-14"; + date = "2024-01-25"; }; } diff --git a/pkgs/default.nix b/pkgs/default.nix index e8515b8..71703b1 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -22,12 +22,12 @@ in inherit (inputs.nix-gaming.packages.${pkgs.system}) faf-client osu-lazer-bin; inherit nixForNixPlugins; nix = nixForNixPlugins; - nixVersions = pkgs.nixVersions.extend (self: super: { + nixVersions = pkgs.nixVersions // { stable = nixForNixPlugins; unstable = nixForNixPlugins; - }); + }; # Various patches to change Nix version of existing packages so they don't error out because of nix-plugins in nix.conf - nix-plugins = (pkgs.nix-plugins.override { nix = nixForNixPlugins; }).overrideAttrs (old: { + /*nix-plugins = (pkgs.nix-plugins.override { nix = nixForNixPlugins; }).overrideAttrs (old: { version = "13.0.0"; patches = [ (pkgs.fetchpatch { @@ -36,37 +36,30 @@ in hash = "sha256-pOogMtjXYkSDtXW12TmBpGr/plnizJtud2nP3q2UldQ="; }) ]; + });*/ + harmonia = (pkgs.harmonia.override { nixVersions.nix_2_19 = nixForNixPlugins; }).overrideAttrs (old: rec { + version = "0.7.3"; + src = old.src.override { + rev = "refs/tags/${old.pname}-v${version}"; + hash = "sha256-XtnK54HvZMKZGSCrVD0FO5PQLMo3Vkj8ezUlsfqStq0="; + }; + cargoDeps = pkgs.rustPlatform.importCargoLock { lockFile = "${src}/Cargo.lock"; }; }); - harmonia = (pkgs.harmonia.override { nix = nixForNixPlugins; }); /*.overrideAttrs { - patches = [ - (pkgs.fetchpatch { - url = "https://github.com/nix-community/harmonia/pull/145/commits/394c939a45fa9c590347e149400876c318610b1e.patch"; - hash = "sha256-DvyE7/0PW3XRtFgIrl4IQa7RIQLQZoKLddxCZvhpu3I="; - }) - ]; - };*/ nix-init = pkgs.nix-init.override { nix = nixForNixPlugins; }; nix-serve = pkgs.nix-serve.override { nix = nixForNixPlugins; }; nix-serve-ng = pkgs.nix-serve-ng.override { nix = nixForNixPlugins; }; hydra_unstable = (pkgs.hydra_unstable.override { - nix = nixForNixPlugins; /*.overrideAttrs (old: { - # TODO: remove when https://github.com/NixOS/nix/issues/8796 is fixed or hydra code stops needing a fix - configureFlags = builtins.filter (x: x != "--enable-lto") (old.configureFlags or []); - });*/ + nix = nixForNixPlugins; }).overrideAttrs (old: { - # who cares about failing tests amirite + version = "2023-12-01"; + # who cares about tests amirite doCheck = false; - patches = (old.patches or [ ]) ++ [ - (pkgs.fetchpatch { - url = "https://github.com/chayleaf/hydra/commit/e9da80fff6234fab2458173272ee0bedbe8935c3.patch"; - hash = "sha256-PS8rwe5lIzvaVlh/DogYmW5OccVfpKQ6JehTQibx2XQ="; - }) - ]; + src = old.src.override { + rev = "4d1c8505120961f10897b8fe9a070d4e193c9a13"; + hash = "sha256-vXTuE83GL15mgZHegbllVAsVdDFcWWSayPfZxTJN5ys="; + }; }); nurl = pkgs.nurl.override { nix = nixForNixPlugins; }; - /*nvfetcher = pkgs.nvfetcher.overrideAttrs (old: { - meta = builtins.removeAttrs old.meta [ "broken" ]; - });*/ buffyboard = pkgs.callPackage ./buffyboard { }; clang-tools_latest = pkgs.clang-tools_16; @@ -74,30 +67,6 @@ in /*ghidra = pkgs.ghidra.overrideAttrs (old: { patches = old.patches ++ [ ./ghidra-stdcall.patch ]; });*/ - ffmpeg-custom = (pkgs.callPackage (import /${pkgs.path}/pkgs/development/libraries/ffmpeg/generic.nix { - version = "6.1"; - sha256 = "sha256-NzhD2D16bCVCyCXo0TRwZYp3Ta5eFSfoQPa+iRkeNZg="; - }) { - ffmpegVariant = "full"; - withCuda = false; - withCudaLLVM = false; - withNvdec = false; - withNvenc = false; - inherit (pkgs'.darwin.apple_sdk.frameworks) - Cocoa CoreServices CoreAudio CoreMedia AVFoundation MediaToolbox - VideoDecodeAcceleration VideoToolbox; - }).overrideAttrs (old: { - postPatch = '' - ${old.postPatch or ""} - substituteInPlace libavutil/hwcontext_vulkan.c \ - --replace FF_VK_KHR_VIDEO_DECODE_QUEUE FF_VK_EXT_VIDEO_DECODE_QUEUE \ - --replace FF_VK_KHR_VIDEO_DECODE_H264 FF_VK_EXT_VIDEO_DECODE_H264 \ - --replace FF_VK_KHR_VIDEO_DECODE_H265 FF_VK_EXT_VIDEO_DECODE_H265 \ - --replace FF_VK_KHR_VIDEO_DECODE_AV1 FF_VK_EXT_VIDEO_DECODE_AV1 - ''; - buildInputs = old.buildInputs ++ [ pkgs.libaribcaption ]; - configureFlags = old.configureFlags ++ [ "--enable-libaribcaption" ]; - }); gimp = callPackage ./gimp { inherit (pkgs) gimp; }; home-daemon = callPackage ./home-daemon { }; # pin version diff --git a/pkgs/firefox-addons/generated.nix b/pkgs/firefox-addons/generated.nix index 347f232..f3dc626 100644 --- a/pkgs/firefox-addons/generated.nix +++ b/pkgs/firefox-addons/generated.nix @@ -37,23 +37,21 @@ }; "rikaitan" = buildFirefoxXpiAddon { pname = "rikaitan"; - version = "23.9.25.1"; + version = "24.1.22.0"; addonId = "tatsu@autistici.org"; - url = "https://addons.mozilla.org/firefox/downloads/file/4172402/rikaitan-23.9.25.1.xpi"; - sha256 = "d954f90939455dd52ce161729d7175fac63cf10daea386a1eab34529e03c8f29"; + url = "https://addons.mozilla.org/firefox/downloads/file/4224979/rikaitan-24.1.22.0.xpi"; + sha256 = "7df217a68077d45b9f41fe0170193c9224abc2a543c121429ebef4e7e857b0df"; meta = with lib; { homepage = "https://github.com/Ajatt-Tools/rikaitan"; - description = "Japanese dictionary with Anki integration. \n\nThis project is a community-driven fork of Yomichan, which is no longer maintained."; - license = licenses.lgpl3; + description = "Japanese dictionary with Anki integration and flashcard creation support."; + license = licenses.gpl3; mozPermissions = [ - "" "storage" "clipboardWrite" "unlimitedStorage" - "webRequest" - "webRequestBlocking" - "nativeMessaging" + "declarativeNetRequest" + "scripting" "http://*/*" "https://*/*" "file://*/*" diff --git a/system/devices/radxa-rock5a-server.nix b/system/devices/radxa-rock5a-server.nix index 1898edb..8ffcd4a 100644 --- a/system/devices/radxa-rock5a-server.nix +++ b/system/devices/radxa-rock5a-server.nix @@ -73,11 +73,14 @@ in }; }; };*/ + # eth0 on some kernels + # end0 on other kernels + # sometimes even version dependent preLVMCommands = lib.mkOrder 499 '' - ip link set eth0 address ${router-config.router-settings.serverInitrdMac} || true + ip link set end0 address ${router-config.router-settings.serverInitrdMac} || ip link set eth0 address ${router-config.router-settings.serverInitrdMac} || true ''; postMountCommands = '' - ip link set eth0 address ${router-config.router-settings.serverMac} || true + ip link set end0 address ${router-config.router-settings.serverMac} || ip link set eth0 address ${router-config.router-settings.serverInitrdMac} || true ''; network.enable = true; network.udhcpc.extraArgs = [ "-t6" ]; diff --git a/system/hardware/oneplus-enchilada/linux_6_7.patch b/system/hardware/oneplus-enchilada/linux_6_7.patch index 3d8df13..4531a28 100644 --- a/system/hardware/oneplus-enchilada/linux_6_7.patch +++ b/system/hardware/oneplus-enchilada/linux_6_7.patch @@ -1,19 +1,3 @@ -diff --git a/Documentation/arch/loongarch/introduction.rst b/Documentation/arch/loongarch/introduction.rst -index 8c568cfc210..5e6db78abea 100644 ---- a/Documentation/arch/loongarch/introduction.rst -+++ b/Documentation/arch/loongarch/introduction.rst -@@ -375,9 +375,9 @@ Developer web site of Loongson and LoongArch (Software and Documentation): - - Documentation of LoongArch ISA: - -- https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.02-CN.pdf (in Chinese) -+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.10-CN.pdf (in Chinese) - -- https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.02-EN.pdf (in English) -+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.10-EN.pdf (in English) - - Documentation of LoongArch ELF psABI: - diff --git a/Documentation/devicetree/bindings/display/panel/visionox,rm69299.yaml b/Documentation/devicetree/bindings/display/panel/visionox,rm69299.yaml index fa745a6f445..9d90cf72578 100644 --- a/Documentation/devicetree/bindings/display/panel/visionox,rm69299.yaml @@ -215,6 +199,119 @@ index a8736fd5a53..c389d1955bd 100644 - const: qcom,spmi-flash-led reg: +diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx519.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx519.yaml +new file mode 100644 +index 00000000000..4ba318581aa +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/i2c/sony,imx519.yaml +@@ -0,0 +1,107 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/i2c/sony,imx519.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Sony 1/2.5-Inch 16Mpixel CMOS Digital Image Sensor ++ ++maintainers: ++ - Lee Jackson ++ ++description: ++ The Sony IMX519 is a 1/2.5-inch CMOS active pixel digital image sensor ++ with an active array size of 4656H x 3496V. It is programmable through ++ I2C interface. The I2C address is fixed to 0x1A as per sensor data sheet. ++ Image data is sent through MIPI CSI-2, which is configured as either 2 or ++ 4 data lanes. ++ ++properties: ++ compatible: ++ const: sony,imx519 ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ vdig-supply: ++ description: ++ Digital I/O voltage supply, 1.05 volts ++ ++ vana-supply: ++ description: ++ Analog voltage supply, 2.8 volts ++ ++ vddl-supply: ++ description: ++ Digital core voltage supply, 1.8 volts ++ ++ reset-gpios: ++ description: ++ Reference to the GPIO connected to the xclr pin, if any. ++ Must be released (set high) after all supplies and INCK are applied. ++ ++ port: ++ $ref: /schemas/graph.yaml#/$defs/port-base ++ additionalProperties: false ++ ++ properties: ++ endpoint: ++ $ref: /schemas/media/video-interfaces.yaml# ++ unevaluatedProperties: false ++ ++ properties: ++ data-lanes: ++ anyOf: ++ - items: ++ - const: 1 ++ - const: 2 ++ - items: ++ - const: 1 ++ - const: 2 ++ - const: 3 ++ - const: 4 ++ ++ required: ++ - data-lanes ++ - link-frequencies ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - vana-supply ++ - vdig-supply ++ - vddl-supply ++ - port ++ ++additionalProperties: false ++ ++examples: ++ - | ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ sensor@1a { ++ compatible = "sony,imx519"; ++ reg = <0x1a>; ++ clocks = <&imx519_clk>; ++ vana-supply = <&imx519_vana>; /* 2.8v */ ++ vdig-supply = <&imx519_vdig>; /* 1.05v */ ++ vddl-supply = <&imx519_vddl>; /* 1.8v */ ++ ++ port { ++ imx519_ep: endpoint { ++ remote-endpoint = <&csi1_ep>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = /bits/ 64 <408000000>; ++ }; ++ }; ++ }; ++ }; ++ ++... diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml index 7758a55dd32..874ca4157fb 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml @@ -234,10 +331,10 @@ index 7758a55dd32..874ca4157fb 100644 $ref: /schemas/types.yaml#/definitions/uint32 diff --git a/Documentation/devicetree/bindings/power/supply/lenovo,yoga-c630-ec.yaml b/Documentation/devicetree/bindings/power/supply/lenovo,yoga-c630-ec.yaml new file mode 100644 -index 00000000000..2dceb57a56b +index 00000000000..37977344f15 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/lenovo,yoga-c630-ec.yaml -@@ -0,0 +1,88 @@ +@@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- @@ -271,9 +368,15 @@ index 00000000000..2dceb57a56b + maxItems: 1 + +patternProperties: -+ '^connector@\d$': ++ '^connector@[01]$': + $ref: /schemas/connector/usb-connector.yaml# + ++ properties: ++ reg: ++ maxItems: 1 ++ ++ unevaluatedProperties: false ++ +required: + - compatible + - reg @@ -285,45 +388,34 @@ index 00000000000..2dceb57a56b + - |+ + #include + i2c1 { -+ clock-frequency = <400000>; -+ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ embedded-controller@70 { -+ compatible = "lenovo,yoga-c630-ec"; -+ reg = <0x70>; -+ -+ interrupts-extended = <&tlmm 20 IRQ_TYPE_LEVEL_HIGH>; ++ clock-frequency = <400000>; + + #address-cells = <1>; + #size-cells = <0>; + -+ connector@0 { -+ compatible = "usb-c-connector"; -+ reg = <0>; -+ power-role = "source"; -+ data-role = "host"; -+ }; ++ embedded-controller@70 { ++ compatible = "lenovo,yoga-c630-ec"; ++ reg = <0x70>; + -+ connector@1 { -+ compatible = "usb-c-connector"; -+ reg = <1>; -+ power-role = "source"; -+ data-role = "host"; ++ interrupts-extended = <&tlmm 20 IRQ_TYPE_LEVEL_HIGH>; + -+ ports { + #address-cells = <1>; + #size-cells = <0>; -+ port@1 { -+ reg = <1>; -+ lenovo_ec_dp_in: endpoint { -+ remote-endpoint = <&mdss_dp_out>; -+ }; ++ ++ connector@0 { ++ compatible = "usb-c-connector"; ++ reg = <0>; ++ power-role = "source"; ++ data-role = "host"; ++ }; ++ ++ connector@1 { ++ compatible = "usb-c-connector"; ++ reg = <1>; ++ power-role = "source"; ++ data-role = "host"; + }; -+ }; + }; -+ }; + }; +... diff --git a/Documentation/devicetree/bindings/power/supply/qcom,fg.yaml b/Documentation/devicetree/bindings/power/supply/qcom,fg.yaml @@ -529,74 +621,6 @@ index 00000000000..690537738e6 + }; + }; + }; -diff --git a/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml b/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml -index ff3a1707ef5..6d4cfd943f5 100644 ---- a/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml -+++ b/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml -@@ -36,7 +36,11 @@ properties: - - vdd-supply: - description: -- VDD power supply to the hub -+ 3V3 power supply to the hub -+ -+ vdd2-supply: -+ description: -+ 1V2 power supply to the hub - - peer-hub: - $ref: /schemas/types.yaml#/definitions/phandle -@@ -62,6 +66,7 @@ allOf: - properties: - reset-gpios: false - vdd-supply: false -+ vdd2-supply: false - peer-hub: false - i2c-bus: false - else: -diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml -index e889158ca20..915c8205623 100644 ---- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml -+++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml -@@ -521,8 +521,8 @@ examples: - - interrupts = , - , -- , -- ; -+ , -+ ; - interrupt-names = "hs_phy_irq", "ss_phy_irq", - "dm_hs_phy_irq", "dp_hs_phy_irq"; - -diff --git a/Documentation/devicetree/bindings/usb/usb-hcd.yaml b/Documentation/devicetree/bindings/usb/usb-hcd.yaml -index 692dd60e3f7..45a19d4928a 100644 ---- a/Documentation/devicetree/bindings/usb/usb-hcd.yaml -+++ b/Documentation/devicetree/bindings/usb/usb-hcd.yaml -@@ -41,7 +41,7 @@ examples: - - | - usb { - phys = <&usb2_phy1>, <&usb3_phy1>; -- phy-names = "usb"; -+ phy-names = "usb2", "usb3"; - #address-cells = <1>; - #size-cells = <0>; - -diff --git a/Documentation/filesystems/erofs.rst b/Documentation/filesystems/erofs.rst -index 57c6ae23b3f..cc4626d6ee4 100644 ---- a/Documentation/filesystems/erofs.rst -+++ b/Documentation/filesystems/erofs.rst -@@ -91,6 +91,10 @@ compatibility checking tool (fsck.erofs), and a debugging tool (dump.erofs): - - - git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git - -+For more information, please also refer to the documentation site: -+ -+- https://erofs.docs.kernel.org -+ - Bugs and patches are welcome, please kindly help us and send to the following - linux-erofs mailing list: - diff --git a/Documentation/input/event-codes.rst b/Documentation/input/event-codes.rst index b4557462edd..d43336e64d6 100644 --- a/Documentation/input/event-codes.rst @@ -614,58 +638,11 @@ index b4557462edd..d43336e64d6 100644 * ABS_MT_: - Used to describe multitouch input events. Please see -diff --git a/Documentation/process/maintainer-netdev.rst b/Documentation/process/maintainer-netdev.rst -index 7feacc20835..84ee60fceef 100644 ---- a/Documentation/process/maintainer-netdev.rst -+++ b/Documentation/process/maintainer-netdev.rst -@@ -193,9 +193,23 @@ Review timelines - Generally speaking, the patches get triaged quickly (in less than - 48h). But be patient, if your patch is active in patchwork (i.e. it's - listed on the project's patch list) the chances it was missed are close to zero. --Asking the maintainer for status updates on your --patch is a good way to ensure your patch is ignored or pushed to the --bottom of the priority list. -+ -+The high volume of development on netdev makes reviewers move on -+from discussions relatively quickly. New comments and replies -+are very unlikely to arrive after a week of silence. If a patch -+is no longer active in patchwork and the thread went idle for more -+than a week - clarify the next steps and/or post the next version. -+ -+For RFC postings specifically, if nobody responded in a week - reviewers -+either missed the posting or have no strong opinions. If the code is ready, -+repost as a PATCH. -+ -+Emails saying just "ping" or "bump" are considered rude. If you can't figure -+out the status of the patch from patchwork or where the discussion has -+landed - describe your best guess and ask if it's correct. For example:: -+ -+ I don't understand what the next steps are. Person X seems to be unhappy -+ with A, should I do B and repost the patches? - - .. _Changes requested: - -diff --git a/Documentation/translations/zh_CN/arch/loongarch/introduction.rst b/Documentation/translations/zh_CN/arch/loongarch/introduction.rst -index 59d6bf33050..bf463c5a4c5 100644 ---- a/Documentation/translations/zh_CN/arch/loongarch/introduction.rst -+++ b/Documentation/translations/zh_CN/arch/loongarch/introduction.rst -@@ -338,9 +338,9 @@ Loongson与LoongArch的开发者网站(软件与文档资源): - - LoongArch指令集架构的文档: - -- https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.02-CN.pdf (中文版) -+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.10-CN.pdf (中文版) - -- https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.02-EN.pdf (英文版) -+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.10-EN.pdf (英文版) - - LoongArch的ELF psABI文档: - diff --git a/MAINTAINERS b/MAINTAINERS -index ea790149af7..00e3beabbdf 100644 +index a7c4cf8201e..5426ae32c1f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -6832,6 +6832,11 @@ S: Maintained +@@ -6811,6 +6811,11 @@ S: Maintained F: Documentation/devicetree/bindings/display/panel/samsung,s6d7aa0.yaml F: drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c @@ -677,118 +654,22 @@ index ea790149af7..00e3beabbdf 100644 DRM DRIVER FOR SITRONIX ST7586 PANELS M: David Lechner S: Maintained -@@ -7855,6 +7860,7 @@ R: Yue Hu - R: Jeffle Xu - L: linux-erofs@lists.ozlabs.org - S: Maintained -+W: https://erofs.docs.kernel.org - T: git git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git - F: Documentation/ABI/testing/sysfs-fs-erofs - F: Documentation/filesystems/erofs.rst -@@ -11024,7 +11030,6 @@ F: drivers/net/wireless/intel/iwlwifi/ - - INTEL WMI SLIM BOOTLOADER (SBL) FIRMWARE UPDATE DRIVER - M: Jithu Joseph --R: Maurice Ma - S: Maintained - W: https://slimbootloader.github.io/security/firmware-update.html - F: drivers/platform/x86/intel/wmi/sbl-fw-update.c -@@ -13778,7 +13783,6 @@ F: drivers/net/ethernet/mellanox/mlxfw/ - MELLANOX HARDWARE PLATFORM SUPPORT - M: Hans de Goede - M: Ilpo Järvinen --M: Mark Gross - M: Vadim Pasternak - L: platform-driver-x86@vger.kernel.org - S: Supported -@@ -14387,7 +14391,6 @@ F: drivers/platform/surface/surface_gpe.c - MICROSOFT SURFACE HARDWARE PLATFORM SUPPORT - M: Hans de Goede - M: Ilpo Järvinen --M: Mark Gross - M: Maximilian Luz - L: platform-driver-x86@vger.kernel.org - S: Maintained -@@ -14994,6 +14997,7 @@ M: Jakub Kicinski - M: Paolo Abeni - L: netdev@vger.kernel.org - S: Maintained -+P: Documentation/process/maintainer-netdev.rst - Q: https://patchwork.kernel.org/project/netdevbpf/list/ - T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git - T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git -@@ -15045,6 +15049,7 @@ M: Jakub Kicinski - M: Paolo Abeni - L: netdev@vger.kernel.org - S: Maintained -+P: Documentation/process/maintainer-netdev.rst - Q: https://patchwork.kernel.org/project/netdevbpf/list/ - B: mailto:netdev@vger.kernel.org - T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git -@@ -15055,6 +15060,7 @@ F: Documentation/networking/ - F: Documentation/process/maintainer-netdev.rst - F: Documentation/userspace-api/netlink/ - F: include/linux/in.h -+F: include/linux/indirect_call_wrapper.h - F: include/linux/net.h - F: include/linux/netdevice.h - F: include/net/ -@@ -22078,6 +22084,7 @@ F: drivers/watchdog/tqmx86_wdt.c - TRACING - M: Steven Rostedt - M: Masami Hiramatsu -+R: Mathieu Desnoyers - L: linux-kernel@vger.kernel.org - L: linux-trace-kernel@vger.kernel.org - S: Maintained -@@ -23664,7 +23671,6 @@ F: drivers/platform/x86/x86-android-tablets/ - X86 PLATFORM DRIVERS - M: Hans de Goede - M: Ilpo Järvinen --M: Mark Gross - L: platform-driver-x86@vger.kernel.org - S: Maintained - Q: https://patchwork.kernel.org/project/platform-driver-x86/list/ -diff --git a/Makefile b/Makefile -index 724c79bebe7..99db546fbb4 100644 ---- a/Makefile -+++ b/Makefile -@@ -2,7 +2,7 @@ - VERSION = 6 - PATCHLEVEL = 7 - SUBLEVEL = 0 --EXTRAVERSION = -rc2 -+EXTRAVERSION = -rc3 - NAME = Hurr durr I'ma ninja sloth - - # *DOCUMENTATION* -diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c -index 9afdc4c4a5d..a395b6c0aae 100644 ---- a/arch/arm/xen/enlighten.c -+++ b/arch/arm/xen/enlighten.c -@@ -484,7 +484,8 @@ static int __init xen_guest_init(void) - * for secondary CPUs as they are brought up. - * For uniformity we use VCPUOP_register_vcpu_info even on cpu0. - */ -- xen_vcpu_info = alloc_percpu(struct vcpu_info); -+ xen_vcpu_info = __alloc_percpu(sizeof(struct vcpu_info), -+ 1 << fls(sizeof(struct vcpu_info) - 1)); - if (xen_vcpu_info == NULL) - return -ENOMEM; - -diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile -index 4bd85cc0d32..9a2d3723cd0 100644 ---- a/arch/arm64/Makefile -+++ b/arch/arm64/Makefile -@@ -158,7 +158,7 @@ endif - - all: $(notdir $(KBUILD_IMAGE)) - -- -+vmlinuz.efi: Image - Image vmlinuz.efi: vmlinux - $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ +@@ -20170,6 +20175,15 @@ T: git git://linuxtv.org/media_tree.git + F: Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml + F: drivers/media/i2c/imx415.c ++SONY IMX519 SENSOR DRIVER ++M: Arducam Kernel Maintenance ++M: Lee Jackson ++L: linux-media@vger.kernel.org ++S: Maintained ++T: git git://linuxtv.org/media_tree.git ++F: Documentation/devicetree/bindings/media/i2c/sony,imx519.yaml ++F: drivers/media/i2c/imx519.c ++ + SONY MEMORYSTICK SUBSYSTEM + M: Maxim Levitsky + M: Alex Dubov diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index d6cb840b705..28f3a66dc2f 100644 --- a/arch/arm64/boot/dts/qcom/Makefile @@ -1577,7 +1458,7 @@ index d46e591e72b..2b952a5b752 100644 compatible = "qcom,qcm2290-mpss-pas", "qcom,sm6115-mpss-pas"; reg = <0x0 0x06080000 0x0 0x100>; diff --git a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts -index 94885b9c21c..b85339aeb51 100644 +index fd38a6278f2..6352b4976b9 100644 --- a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts +++ b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts @@ -23,6 +23,14 @@ chosen { @@ -1749,7 +1630,18 @@ index 94885b9c21c..b85339aeb51 100644 sd_det_in_on: sd-det-in-on-state { pins = "gpio88"; function = "gpio"; -@@ -427,6 +567,7 @@ &wifi { +@@ -409,6 +549,10 @@ &usb { + status = "okay"; + }; + ++&usb_dwc3 { ++ dr_mode = "host"; ++}; ++ + &usb_qmpphy { + vdda-phy-supply = <&pm2250_l12>; + vdda-pll-supply = <&pm2250_l13>; +@@ -431,6 +575,7 @@ &wifi { vdd-1.8-xo-supply = <&pm2250_l13>; vdd-1.3-rfa-supply = <&pm2250_l10>; vdd-3.3-ch0-supply = <&pm2250_l22>; @@ -1758,7 +1650,7 @@ index 94885b9c21c..b85339aeb51 100644 }; diff --git a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts -index a7278a9472e..0372551e3d8 100644 +index 9738c0dacd5..8b3e8200ea5 100644 --- a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +++ b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts @@ -280,6 +280,12 @@ &remoteproc_cdsp { @@ -1796,15 +1688,15 @@ index a7278a9472e..0372551e3d8 100644 }; vreg_l24a_2p96: l24 { -@@ -518,7 +524,6 @@ &usb { +@@ -518,6 +524,7 @@ &usb { &usb_dwc3 { maximum-speed = "super-speed"; -- dr_mode = "peripheral"; ++ dr_mode = "host"; }; &usb_hsphy { -@@ -536,6 +541,15 @@ &usb_qmpphy { +@@ -535,6 +542,15 @@ &usb_qmpphy { status = "okay"; }; @@ -2466,7 +2358,7 @@ index 00000000000..a22062a9fc8 + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi -index 11f353d416b..df7b86f437a 100644 +index c0365832c31..68ffd29f1a2 100644 --- a/arch/arm64/boot/dts/qcom/sc7180.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi @@ -1532,6 +1532,83 @@ mmss_noc: interconnect@1740000 { @@ -2554,7 +2446,7 @@ index 11f353d416b..df7b86f437a 100644 compatible = "qcom,sc7180-ipa"; diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts -index c7eba6c491b..c58b57e78c7 100644 +index 7e7bf3fb3be..d4f6284694a 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts @@ -194,6 +194,7 @@ pcie0_3p3v_dual: vldo-3v3-regulator { @@ -3958,7 +3850,7 @@ index e9427851eba..0ca1997f934 100644 + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi -index bf5e6eb9d31..b0f1d08a620 100644 +index 9648505644f..fca4e070f12 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -888,6 +888,11 @@ mdata_mem: mpss-metadata { @@ -4006,11 +3898,52 @@ index bf5e6eb9d31..b0f1d08a620 100644 }; fastrpc { +@@ -3353,8 +3384,8 @@ slpi_pas: remoteproc@5c00000 { + + qcom,qmp = <&aoss_qmp>; + +- power-domains = <&rpmhpd SDM845_CX>, +- <&rpmhpd SDM845_MX>; ++ power-domains = <&rpmhpd SDM845_LCX>, ++ <&rpmhpd SDM845_LMX>; + power-domain-names = "lcx", "lmx"; + + memory-region = <&slpi_mem>; +@@ -4053,10 +4084,10 @@ usb_1: usb@a6f8800 { + <&gcc GCC_USB30_PRIM_MASTER_CLK>; + assigned-clock-rates = <19200000>, <150000000>; + +- interrupts = , +- , +- , +- ; ++ interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc GIC_SPI 486 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc_intc 8 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc_intc 9 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", + "dm_hs_phy_irq", "dp_hs_phy_irq"; + +@@ -4104,10 +4135,10 @@ usb_2: usb@a8f8800 { + <&gcc GCC_USB30_SEC_MASTER_CLK>; + assigned-clock-rates = <19200000>, <150000000>; + +- interrupts = , +- , +- , +- ; ++ interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc GIC_SPI 487 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc_intc 10 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc_intc 11 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", + "dm_hs_phy_irq", "dp_hs_phy_irq"; + diff --git a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts -index 92a812b5f42..d3a29e246c9 100644 +index 92a812b5f42..c54e7d3612f 100644 --- a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts +++ b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts -@@ -370,6 +370,44 @@ zap-shader { +@@ -370,6 +370,33 @@ zap-shader { &i2c1 { status = "okay"; clock-frequency = <400000>; @@ -4030,53 +3963,33 @@ index 92a812b5f42..d3a29e246c9 100644 + connector@0 { + compatible = "usb-c-connector"; + reg = <0>; -+ power-role = "dual"; -+ data-role = "dual"; ++ power-role = "source"; ++ data-role = "host"; + }; + + connector@1 { + compatible = "usb-c-connector"; + reg = <1>; -+ power-role = "dual"; -+ data-role = "dual"; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ port@1 { -+ reg = <1>; -+ lenovo_ec_dp_in: endpoint { -+ remote-endpoint = <&mdss_dp_out>; -+ }; -+ }; -+ }; ++ power-role = "source"; ++ data-role = "host"; + }; + }; }; &i2c3 { -@@ -495,6 +533,20 @@ &mdss { - status = "okay"; +@@ -561,6 +588,11 @@ dai@2 { + }; }; -+&mdss_dp { ++&slpi_pas { ++ firmware-name = "qcom/sdm850/LENOVO/81JL/qcslpi850.mbn"; + status = "okay"; -+ data-lanes = <0 1>; -+ -+ ports { -+ port@1 { -+ reg = <1>; -+ mdss_dp_out: endpoint { -+ remote-endpoint = <&lenovo_ec_dp_in>; -+ }; -+ }; -+ }; +}; + - &mdss_dsi0 { - status = "okay"; - vdda-supply = <&vreg_l26a_1p2>; -@@ -688,6 +740,14 @@ mode_pin_active: mode-pin-state { + &sound { + compatible = "lenovo,yoga-c630-sndcard", "qcom,sdm845-sndcard"; + model = "Lenovo-YOGA-C630-13Q50"; +@@ -688,6 +720,14 @@ mode_pin_active: mode-pin-state { bias-disable; }; @@ -4531,10 +4444,10 @@ index 839c6035124..258eebfbaba 100644 ranges; diff --git a/arch/arm64/configs/sdm845.config b/arch/arm64/configs/sdm845.config new file mode 100644 -index 00000000000..91bb92c77a6 +index 00000000000..8306c125202 --- /dev/null +++ b/arch/arm64/configs/sdm845.config -@@ -0,0 +1,1014 @@ +@@ -0,0 +1,1022 @@ +# Qualcomm Snapdragon 845 (SDM845) config fragment +CONFIG_LOCALVERSION="-sdm845" + @@ -4573,10 +4486,12 @@ index 00000000000..91bb92c77a6 +CONFIG_DRM_PANEL_NOVATEK_NT35596S=y + +# C630 -+CONFIG_DRM_TI_SN65DSI86=m -+CONFIG_DRM_PANEL_EDP=m -+CONFIG_PHY_QCOM_EDP=m ++CONFIG_DRM_TI_SN65DSI86=y ++CONFIG_DRM_PANEL_EDP=y ++CONFIG_PHY_QCOM_EDP=y +CONFIG_I2C_HID_OF_ELAN=m ++CONFIG_BACKLIGHT_PWM=y ++CONFIG_LENOVO_YOGA_C630_EC=m + +# SOC +CONFIG_FORCE_NR_CPUS=y @@ -4598,12 +4513,12 @@ index 00000000000..91bb92c77a6 +CONFIG_PHY_QCOM_QMP_PCIE=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_INTERCONNECT_QCOM_OSM_L3=y -+ +# Notification LED +# Must be builtin as it won't be automatically modprobed +CONFIG_LEDS_TRIGGER_PATTERN=y +CONFIG_LEDS_CLASS_MULTICOLOR=m +CONFIG_LEDS_QCOM_LPG=m ++CONFIG_I2C_QCOM_GENI=y + +# Flash LED +CONFIG_LEDS_QCOM_FLASH=m @@ -4626,6 +4541,8 @@ index 00000000000..91bb92c77a6 +CONFIG_DRM=y +CONFIG_FB_SIMPLE=y +CONFIG_DRM_MSM=y ++# Virtual video test driver ++CONFIG_VIDEO_VIVID=m + +# Brightness Control +CONFIG_REGULATOR_QCOM_LABIBB=y @@ -4654,6 +4571,10 @@ index 00000000000..91bb92c77a6 +# Alpine can't seem to handle this +CONFIG_MODULE_DECOMPRESS=y + ++# Usage clamping (scale CPU for specific tasks) ++CONFIG_UCLAMP_TASK=y ++CONFIG_UCLAMP_TASK_GROUP=y ++ +# Needed for mounting userdata on android +CONFIG_QFMT_V2=y + @@ -5549,1976 +5470,113 @@ index 00000000000..91bb92c77a6 +CONFIG_SM_DISPCC_8550=n +CONFIG_SM_GCC_8550=n +CONFIG_SM_TCSRCC_8550=n -diff --git a/arch/arm64/include/asm/setup.h b/arch/arm64/include/asm/setup.h -index f4af547ef54..2e4d7da74fb 100644 ---- a/arch/arm64/include/asm/setup.h -+++ b/arch/arm64/include/asm/setup.h -@@ -21,9 +21,22 @@ static inline bool arch_parse_debug_rodata(char *arg) - extern bool rodata_enabled; - extern bool rodata_full; - -- if (arg && !strcmp(arg, "full")) { -+ if (!arg) -+ return false; -+ -+ if (!strcmp(arg, "full")) { -+ rodata_enabled = rodata_full = true; -+ return true; -+ } -+ -+ if (!strcmp(arg, "off")) { -+ rodata_enabled = rodata_full = false; -+ return true; -+ } -+ -+ if (!strcmp(arg, "on")) { - rodata_enabled = true; -- rodata_full = true; -+ rodata_full = false; - return true; - } - -diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c -index 8e2017ba5f1..924843f1f66 100644 ---- a/arch/arm64/mm/pageattr.c -+++ b/arch/arm64/mm/pageattr.c -@@ -29,8 +29,8 @@ bool can_set_direct_map(void) - * - * KFENCE pool requires page-granular mapping if initialized late. - */ -- return (rodata_enabled && rodata_full) || debug_pagealloc_enabled() || -- arm64_kfence_can_set_direct_map(); -+ return rodata_full || debug_pagealloc_enabled() || -+ arm64_kfence_can_set_direct_map(); - } - - static int change_page_range(pte_t *ptep, unsigned long addr, void *data) -@@ -105,8 +105,7 @@ static int change_memory_common(unsigned long addr, int numpages, - * If we are manipulating read-only permissions, apply the same - * change to the linear mapping of the pages that back this VM area. - */ -- if (rodata_enabled && -- rodata_full && (pgprot_val(set_mask) == PTE_RDONLY || -+ if (rodata_full && (pgprot_val(set_mask) == PTE_RDONLY || - pgprot_val(clear_mask) == PTE_RDONLY)) { - for (i = 0; i < area->nr_pages; i++) { - __change_memory_common((u64)page_address(area->pages[i]), -diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile -index 9eeb0c05f3f..204b94b2e6a 100644 ---- a/arch/loongarch/Makefile -+++ b/arch/loongarch/Makefile -@@ -68,6 +68,7 @@ LDFLAGS_vmlinux += -static -n -nostdlib - ifdef CONFIG_AS_HAS_EXPLICIT_RELOCS - cflags-y += $(call cc-option,-mexplicit-relocs) - KBUILD_CFLAGS_KERNEL += $(call cc-option,-mdirect-extern-access) -+KBUILD_CFLAGS_KERNEL += $(call cc-option,-fdirect-access-external-data) - KBUILD_AFLAGS_MODULE += $(call cc-option,-fno-direct-access-external-data) - KBUILD_CFLAGS_MODULE += $(call cc-option,-fno-direct-access-external-data) - KBUILD_AFLAGS_MODULE += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax) -@@ -142,6 +143,8 @@ vdso-install-y += arch/loongarch/vdso/vdso.so.dbg - - all: $(notdir $(KBUILD_IMAGE)) - -+vmlinuz.efi: vmlinux.efi -+ - vmlinux.elf vmlinux.efi vmlinuz.efi: vmlinux - $(Q)$(MAKE) $(build)=$(boot) $(bootvars-y) $(boot)/$@ - -diff --git a/arch/loongarch/include/asm/asmmacro.h b/arch/loongarch/include/asm/asmmacro.h -index c9544f358c3..655db7d7a42 100644 ---- a/arch/loongarch/include/asm/asmmacro.h -+++ b/arch/loongarch/include/asm/asmmacro.h -@@ -609,8 +609,7 @@ - lu32i.d \reg, 0 - lu52i.d \reg, \reg, 0 - .pushsection ".la_abs", "aw", %progbits -- 768: -- .dword 768b-766b -+ .dword 766b - .dword \sym - .popsection - #endif -diff --git a/arch/loongarch/include/asm/percpu.h b/arch/loongarch/include/asm/percpu.h -index ed5da02b1cf..9b36ac003f8 100644 ---- a/arch/loongarch/include/asm/percpu.h -+++ b/arch/loongarch/include/asm/percpu.h -@@ -40,13 +40,13 @@ static __always_inline unsigned long __percpu_##op(void *ptr, \ - switch (size) { \ - case 4: \ - __asm__ __volatile__( \ -- "am"#asm_op".w" " %[ret], %[val], %[ptr] \n" \ -+ "am"#asm_op".w" " %[ret], %[val], %[ptr] \n" \ - : [ret] "=&r" (ret), [ptr] "+ZB"(*(u32 *)ptr) \ - : [val] "r" (val)); \ - break; \ - case 8: \ - __asm__ __volatile__( \ -- "am"#asm_op".d" " %[ret], %[val], %[ptr] \n" \ -+ "am"#asm_op".d" " %[ret], %[val], %[ptr] \n" \ - : [ret] "=&r" (ret), [ptr] "+ZB"(*(u64 *)ptr) \ - : [val] "r" (val)); \ - break; \ -@@ -63,7 +63,7 @@ PERCPU_OP(and, and, &) - PERCPU_OP(or, or, |) - #undef PERCPU_OP - --static __always_inline unsigned long __percpu_read(void *ptr, int size) -+static __always_inline unsigned long __percpu_read(void __percpu *ptr, int size) - { - unsigned long ret; - -@@ -100,7 +100,7 @@ static __always_inline unsigned long __percpu_read(void *ptr, int size) - return ret; - } - --static __always_inline void __percpu_write(void *ptr, unsigned long val, int size) -+static __always_inline void __percpu_write(void __percpu *ptr, unsigned long val, int size) - { - switch (size) { - case 1: -@@ -132,8 +132,7 @@ static __always_inline void __percpu_write(void *ptr, unsigned long val, int siz - } - } - --static __always_inline unsigned long __percpu_xchg(void *ptr, unsigned long val, -- int size) -+static __always_inline unsigned long __percpu_xchg(void *ptr, unsigned long val, int size) - { - switch (size) { - case 1: -diff --git a/arch/loongarch/include/asm/setup.h b/arch/loongarch/include/asm/setup.h -index a0bc159ce8b..ee52fb1e996 100644 ---- a/arch/loongarch/include/asm/setup.h -+++ b/arch/loongarch/include/asm/setup.h -@@ -25,7 +25,7 @@ extern void set_merr_handler(unsigned long offset, void *addr, unsigned long len - #ifdef CONFIG_RELOCATABLE - - struct rela_la_abs { -- long offset; -+ long pc; - long symvalue; - }; - -diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c -index 6c3eff9af9f..1acfa704c8d 100644 ---- a/arch/loongarch/kernel/relocate.c -+++ b/arch/loongarch/kernel/relocate.c -@@ -52,7 +52,7 @@ static inline void __init relocate_absolute(long random_offset) - for (p = begin; (void *)p < end; p++) { - long v = p->symvalue; - uint32_t lu12iw, ori, lu32id, lu52id; -- union loongarch_instruction *insn = (void *)p - p->offset; -+ union loongarch_instruction *insn = (void *)p->pc; - - lu12iw = (v >> 12) & 0xfffff; - ori = v & 0xfff; -@@ -102,6 +102,14 @@ static inline __init unsigned long get_random_boot(void) - return hash; - } - -+static int __init nokaslr(char *p) -+{ -+ pr_info("KASLR is disabled.\n"); -+ -+ return 0; /* Print a notice and silence the boot warning */ -+} -+early_param("nokaslr", nokaslr); -+ - static inline __init bool kaslr_disabled(void) - { - char *str; -diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c -index 3064af94db9..e7015f7b70e 100644 ---- a/arch/loongarch/kernel/time.c -+++ b/arch/loongarch/kernel/time.c -@@ -58,14 +58,16 @@ static int constant_set_state_oneshot(struct clock_event_device *evt) - return 0; - } - --static int constant_set_state_oneshot_stopped(struct clock_event_device *evt) -+static int constant_set_state_periodic(struct clock_event_device *evt) - { -+ unsigned long period; - unsigned long timer_config; - - raw_spin_lock(&state_lock); - -- timer_config = csr_read64(LOONGARCH_CSR_TCFG); -- timer_config &= ~CSR_TCFG_EN; -+ period = const_clock_freq / HZ; -+ timer_config = period & CSR_TCFG_VAL; -+ timer_config |= (CSR_TCFG_PERIOD | CSR_TCFG_EN); - csr_write64(timer_config, LOONGARCH_CSR_TCFG); - - raw_spin_unlock(&state_lock); -@@ -73,16 +75,14 @@ static int constant_set_state_oneshot_stopped(struct clock_event_device *evt) - return 0; - } - --static int constant_set_state_periodic(struct clock_event_device *evt) -+static int constant_set_state_shutdown(struct clock_event_device *evt) - { -- unsigned long period; - unsigned long timer_config; - - raw_spin_lock(&state_lock); - -- period = const_clock_freq / HZ; -- timer_config = period & CSR_TCFG_VAL; -- timer_config |= (CSR_TCFG_PERIOD | CSR_TCFG_EN); -+ timer_config = csr_read64(LOONGARCH_CSR_TCFG); -+ timer_config &= ~CSR_TCFG_EN; - csr_write64(timer_config, LOONGARCH_CSR_TCFG); - - raw_spin_unlock(&state_lock); -@@ -90,11 +90,6 @@ static int constant_set_state_periodic(struct clock_event_device *evt) - return 0; - } - --static int constant_set_state_shutdown(struct clock_event_device *evt) --{ -- return 0; --} -- - static int constant_timer_next_event(unsigned long delta, struct clock_event_device *evt) - { - unsigned long timer_config; -@@ -161,7 +156,7 @@ int constant_clockevent_init(void) - cd->rating = 320; - cd->cpumask = cpumask_of(cpu); - cd->set_state_oneshot = constant_set_state_oneshot; -- cd->set_state_oneshot_stopped = constant_set_state_oneshot_stopped; -+ cd->set_state_oneshot_stopped = constant_set_state_shutdown; - cd->set_state_periodic = constant_set_state_periodic; - cd->set_state_shutdown = constant_set_state_shutdown; - cd->set_next_event = constant_timer_next_event; -diff --git a/arch/loongarch/mm/pgtable.c b/arch/loongarch/mm/pgtable.c -index 71d0539e2d0..2aae72e6387 100644 ---- a/arch/loongarch/mm/pgtable.c -+++ b/arch/loongarch/mm/pgtable.c -@@ -13,13 +13,13 @@ struct page *dmw_virt_to_page(unsigned long kaddr) - { - return pfn_to_page(virt_to_pfn(kaddr)); - } --EXPORT_SYMBOL_GPL(dmw_virt_to_page); -+EXPORT_SYMBOL(dmw_virt_to_page); - - struct page *tlb_virt_to_page(unsigned long kaddr) - { - return pfn_to_page(pte_pfn(*virt_to_kpte(kaddr))); - } --EXPORT_SYMBOL_GPL(tlb_virt_to_page); -+EXPORT_SYMBOL(tlb_virt_to_page); - - pgd_t *pgd_alloc(struct mm_struct *mm) - { -diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig -index a7c9c0e69e5..d14ccc948a2 100644 ---- a/arch/parisc/Kconfig -+++ b/arch/parisc/Kconfig -@@ -115,9 +115,12 @@ config ARCH_HAS_ILOG2_U64 - default n - - config GENERIC_BUG -- bool -- default y -+ def_bool y - depends on BUG -+ select GENERIC_BUG_RELATIVE_POINTERS if 64BIT -+ -+config GENERIC_BUG_RELATIVE_POINTERS -+ bool - - config GENERIC_HWEIGHT - bool -diff --git a/arch/parisc/include/asm/alternative.h b/arch/parisc/include/asm/alternative.h -index 1ed45fd085d..1eb488f25b8 100644 ---- a/arch/parisc/include/asm/alternative.h -+++ b/arch/parisc/include/asm/alternative.h -@@ -34,7 +34,8 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end, - - /* Alternative SMP implementation. */ - #define ALTERNATIVE(cond, replacement) "!0:" \ -- ".section .altinstructions, \"aw\" !" \ -+ ".section .altinstructions, \"a\" !" \ -+ ".align 4 !" \ - ".word (0b-4-.) !" \ - ".hword 1, " __stringify(cond) " !" \ - ".word " __stringify(replacement) " !" \ -@@ -44,7 +45,8 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end, - - /* to replace one single instructions by a new instruction */ - #define ALTERNATIVE(from, to, cond, replacement)\ -- .section .altinstructions, "aw" ! \ -+ .section .altinstructions, "a" ! \ -+ .align 4 ! \ - .word (from - .) ! \ - .hword (to - from)/4, cond ! \ - .word replacement ! \ -@@ -52,7 +54,8 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end, - - /* to replace multiple instructions by new code */ - #define ALTERNATIVE_CODE(from, num_instructions, cond, new_instr_ptr)\ -- .section .altinstructions, "aw" ! \ -+ .section .altinstructions, "a" ! \ -+ .align 4 ! \ - .word (from - .) ! \ - .hword -num_instructions, cond ! \ - .word (new_instr_ptr - .) ! \ -diff --git a/arch/parisc/include/asm/assembly.h b/arch/parisc/include/asm/assembly.h -index 75677b526b2..74d17d7e759 100644 ---- a/arch/parisc/include/asm/assembly.h -+++ b/arch/parisc/include/asm/assembly.h -@@ -574,6 +574,7 @@ - */ - #define ASM_EXCEPTIONTABLE_ENTRY(fault_addr, except_addr) \ - .section __ex_table,"aw" ! \ -+ .align 4 ! \ - .word (fault_addr - .), (except_addr - .) ! \ - .previous - -diff --git a/arch/parisc/include/asm/bug.h b/arch/parisc/include/asm/bug.h -index 4b6d60b9412..1641ff9a8b8 100644 ---- a/arch/parisc/include/asm/bug.h -+++ b/arch/parisc/include/asm/bug.h -@@ -17,24 +17,27 @@ - #define PARISC_BUG_BREAK_ASM "break 0x1f, 0x1fff" - #define PARISC_BUG_BREAK_INSN 0x03ffe01f /* PARISC_BUG_BREAK_ASM */ - --#if defined(CONFIG_64BIT) --#define ASM_WORD_INSN ".dword\t" -+#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS -+# define __BUG_REL(val) ".word " __stringify(val) " - ." - #else --#define ASM_WORD_INSN ".word\t" -+# define __BUG_REL(val) ".word " __stringify(val) - #endif - -+ - #ifdef CONFIG_DEBUG_BUGVERBOSE - #define BUG() \ - do { \ - asm volatile("\n" \ - "1:\t" PARISC_BUG_BREAK_ASM "\n" \ -- "\t.pushsection __bug_table,\"aw\"\n" \ -- "2:\t" ASM_WORD_INSN "1b, %c0\n" \ -- "\t.short %c1, %c2\n" \ -- "\t.org 2b+%c3\n" \ -+ "\t.pushsection __bug_table,\"a\"\n" \ -+ "\t.align 4\n" \ -+ "2:\t" __BUG_REL(1b) "\n" \ -+ "\t" __BUG_REL(%c0) "\n" \ -+ "\t.short %1, %2\n" \ -+ "\t.blockz %3-2*4-2*2\n" \ - "\t.popsection" \ - : : "i" (__FILE__), "i" (__LINE__), \ -- "i" (0), "i" (sizeof(struct bug_entry)) ); \ -+ "i" (0), "i" (sizeof(struct bug_entry)) ); \ - unreachable(); \ - } while(0) - -@@ -51,10 +54,12 @@ - do { \ - asm volatile("\n" \ - "1:\t" PARISC_BUG_BREAK_ASM "\n" \ -- "\t.pushsection __bug_table,\"aw\"\n" \ -- "2:\t" ASM_WORD_INSN "1b, %c0\n" \ -- "\t.short %c1, %c2\n" \ -- "\t.org 2b+%c3\n" \ -+ "\t.pushsection __bug_table,\"a\"\n" \ -+ "\t.align 4\n" \ -+ "2:\t" __BUG_REL(1b) "\n" \ -+ "\t" __BUG_REL(%c0) "\n" \ -+ "\t.short %1, %2\n" \ -+ "\t.blockz %3-2*4-2*2\n" \ - "\t.popsection" \ - : : "i" (__FILE__), "i" (__LINE__), \ - "i" (BUGFLAG_WARNING|(flags)), \ -@@ -65,10 +70,11 @@ - do { \ - asm volatile("\n" \ - "1:\t" PARISC_BUG_BREAK_ASM "\n" \ -- "\t.pushsection __bug_table,\"aw\"\n" \ -- "2:\t" ASM_WORD_INSN "1b\n" \ -- "\t.short %c0\n" \ -- "\t.org 2b+%c1\n" \ -+ "\t.pushsection __bug_table,\"a\"\n" \ -+ "\t.align %2\n" \ -+ "2:\t" __BUG_REL(1b) "\n" \ -+ "\t.short %0\n" \ -+ "\t.blockz %1-4-2\n" \ - "\t.popsection" \ - : : "i" (BUGFLAG_WARNING|(flags)), \ - "i" (sizeof(struct bug_entry)) ); \ -diff --git a/arch/parisc/include/asm/jump_label.h b/arch/parisc/include/asm/jump_label.h -index af2a598bc0f..94428798b6a 100644 ---- a/arch/parisc/include/asm/jump_label.h -+++ b/arch/parisc/include/asm/jump_label.h -@@ -15,10 +15,12 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran - asm_volatile_goto("1:\n\t" - "nop\n\t" - ".pushsection __jump_table, \"aw\"\n\t" -+ ".align %1\n\t" - ".word 1b - ., %l[l_yes] - .\n\t" - __stringify(ASM_ULONG_INSN) " %c0 - .\n\t" - ".popsection\n\t" -- : : "i" (&((char *)key)[branch]) : : l_yes); -+ : : "i" (&((char *)key)[branch]), "i" (sizeof(long)) -+ : : l_yes); - - return false; - l_yes: -@@ -30,10 +32,12 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, bool - asm_volatile_goto("1:\n\t" - "b,n %l[l_yes]\n\t" - ".pushsection __jump_table, \"aw\"\n\t" -+ ".align %1\n\t" - ".word 1b - ., %l[l_yes] - .\n\t" - __stringify(ASM_ULONG_INSN) " %c0 - .\n\t" - ".popsection\n\t" -- : : "i" (&((char *)key)[branch]) : : l_yes); -+ : : "i" (&((char *)key)[branch]), "i" (sizeof(long)) -+ : : l_yes); - - return false; - l_yes: -diff --git a/arch/parisc/include/asm/ldcw.h b/arch/parisc/include/asm/ldcw.h -index ee9e071859b..47ebc4c91ea 100644 ---- a/arch/parisc/include/asm/ldcw.h -+++ b/arch/parisc/include/asm/ldcw.h -@@ -55,7 +55,7 @@ - }) - - #ifdef CONFIG_SMP --# define __lock_aligned __section(".data..lock_aligned") -+# define __lock_aligned __section(".data..lock_aligned") __aligned(16) - #endif - - #endif /* __PARISC_LDCW_H */ -diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h -index 2bf660eabe4..4165079898d 100644 ---- a/arch/parisc/include/asm/uaccess.h -+++ b/arch/parisc/include/asm/uaccess.h -@@ -41,6 +41,7 @@ struct exception_table_entry { - - #define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\ - ".section __ex_table,\"aw\"\n" \ -+ ".align 4\n" \ - ".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \ - ".previous\n" - -diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h -index 87245c58478..8d94739d75c 100644 ---- a/arch/parisc/include/uapi/asm/errno.h -+++ b/arch/parisc/include/uapi/asm/errno.h -@@ -75,7 +75,6 @@ - - /* We now return you to your regularly scheduled HPUX. */ - --#define ENOSYM 215 /* symbol does not exist in executable */ - #define ENOTSOCK 216 /* Socket operation on non-socket */ - #define EDESTADDRREQ 217 /* Destination address required */ - #define EMSGSIZE 218 /* Message too long */ -@@ -101,7 +100,6 @@ - #define ETIMEDOUT 238 /* Connection timed out */ - #define ECONNREFUSED 239 /* Connection refused */ - #define EREFUSED ECONNREFUSED /* for HP's NFS apparently */ --#define EREMOTERELEASE 240 /* Remote peer released connection */ - #define EHOSTDOWN 241 /* Host is down */ - #define EHOSTUNREACH 242 /* No route to host */ - -diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S -index 58694d1989c..548051b0b4a 100644 ---- a/arch/parisc/kernel/vmlinux.lds.S -+++ b/arch/parisc/kernel/vmlinux.lds.S -@@ -130,6 +130,7 @@ SECTIONS - RO_DATA(8) - - /* unwind info */ -+ . = ALIGN(4); - .PARISC.unwind : { - __start___unwind = .; - *(.PARISC.unwind) -diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h -index dc17896a001..c15eadbb998 100644 ---- a/arch/s390/include/asm/processor.h -+++ b/arch/s390/include/asm/processor.h -@@ -228,7 +228,6 @@ typedef struct thread_struct thread_struct; - execve_tail(); \ - } while (0) - --/* Forward declaration, a strange C thing */ - struct task_struct; - struct mm_struct; - struct seq_file; -diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c -index cc364fce6aa..ba75f6bee77 100644 ---- a/arch/s390/kernel/ipl.c -+++ b/arch/s390/kernel/ipl.c -@@ -666,6 +666,7 @@ static int __init ipl_init(void) - &ipl_ccw_attr_group_lpar); - break; - case IPL_TYPE_ECKD: -+ case IPL_TYPE_ECKD_DUMP: - rc = sysfs_create_group(&ipl_kset->kobj, &ipl_eckd_attr_group); - break; - case IPL_TYPE_FCP: -diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c -index 77fd24e6cbb..39a91b00438 100644 ---- a/arch/s390/kernel/perf_pai_crypto.c -+++ b/arch/s390/kernel/perf_pai_crypto.c -@@ -279,12 +279,6 @@ static int paicrypt_event_init(struct perf_event *event) - if (IS_ERR(cpump)) - return PTR_ERR(cpump); - -- /* Event initialization sets last_tag to 0. When later on the events -- * are deleted and re-added, do not reset the event count value to zero. -- * Events are added, deleted and re-added when 2 or more events -- * are active at the same time. -- */ -- event->hw.last_tag = 0; - event->destroy = paicrypt_event_destroy; - - if (a->sample_period) { -@@ -318,6 +312,11 @@ static void paicrypt_start(struct perf_event *event, int flags) - { - u64 sum; - -+ /* Event initialization sets last_tag to 0. When later on the events -+ * are deleted and re-added, do not reset the event count value to zero. -+ * Events are added, deleted and re-added when 2 or more events -+ * are active at the same time. -+ */ - if (!event->hw.last_tag) { - event->hw.last_tag = 1; - sum = paicrypt_getall(event); /* Get current value */ -diff --git a/arch/s390/kernel/perf_pai_ext.c b/arch/s390/kernel/perf_pai_ext.c -index 8ba0f1a3a39..e7013a2e896 100644 ---- a/arch/s390/kernel/perf_pai_ext.c -+++ b/arch/s390/kernel/perf_pai_ext.c -@@ -260,7 +260,6 @@ static int paiext_event_init(struct perf_event *event) - rc = paiext_alloc(a, event); - if (rc) - return rc; -- event->hw.last_tag = 0; - event->destroy = paiext_event_destroy; - - if (a->sample_period) { -diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c -index a08f794a0e7..ce1c777227b 100644 ---- a/arch/x86/events/intel/core.c -+++ b/arch/x86/events/intel/core.c -@@ -4660,7 +4660,7 @@ static void intel_pmu_check_hybrid_pmus(struct x86_hybrid_pmu *pmu) - if (pmu->intel_cap.pebs_output_pt_available) - pmu->pmu.capabilities |= PERF_PMU_CAP_AUX_OUTPUT; - else -- pmu->pmu.capabilities |= ~PERF_PMU_CAP_AUX_OUTPUT; -+ pmu->pmu.capabilities &= ~PERF_PMU_CAP_AUX_OUTPUT; - - intel_pmu_check_event_constraints(pmu->event_constraints, - pmu->num_counters, -diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c -index 21556ad87f4..8f3a4d16bb7 100644 ---- a/arch/x86/hyperv/hv_init.c -+++ b/arch/x86/hyperv/hv_init.c -@@ -15,6 +15,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -286,15 +287,31 @@ static int hv_cpu_die(unsigned int cpu) - - static int __init hv_pci_init(void) - { -- int gen2vm = efi_enabled(EFI_BOOT); -+ bool gen2vm = efi_enabled(EFI_BOOT); - - /* -- * For Generation-2 VM, we exit from pci_arch_init() by returning 0. -- * The purpose is to suppress the harmless warning: -+ * A Generation-2 VM doesn't support legacy PCI/PCIe, so both -+ * raw_pci_ops and raw_pci_ext_ops are NULL, and pci_subsys_init() -> -+ * pcibios_init() doesn't call pcibios_resource_survey() -> -+ * e820__reserve_resources_late(); as a result, any emulated persistent -+ * memory of E820_TYPE_PRAM (12) via the kernel parameter -+ * memmap=nn[KMG]!ss is not added into iomem_resource and hence can't be -+ * detected by register_e820_pmem(). Fix this by directly calling -+ * e820__reserve_resources_late() here: e820__reserve_resources_late() -+ * depends on e820__reserve_resources(), which has been called earlier -+ * from setup_arch(). Note: e820__reserve_resources_late() also adds -+ * any memory of E820_TYPE_PMEM (7) into iomem_resource, and -+ * acpi_nfit_register_region() -> acpi_nfit_insert_resource() -> -+ * region_intersects() returns REGION_INTERSECTS, so the memory of -+ * E820_TYPE_PMEM won't get added twice. -+ * -+ * We return 0 here so that pci_arch_init() won't print the warning: - * "PCI: Fatal: No config space access function found" - */ -- if (gen2vm) -+ if (gen2vm) { -+ e820__reserve_resources_late(); - return 0; -+ } - - /* For Generation-1 VM, we'll proceed in pci_arch_init(). */ - return 1; -diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c -index 9373ec01c5a..13b45b9c806 100644 ---- a/arch/x86/kernel/cpu/microcode/amd.c -+++ b/arch/x86/kernel/cpu/microcode/amd.c -@@ -104,8 +104,6 @@ struct cont_desc { - size_t size; - }; - --static u32 ucode_new_rev; -- - /* - * Microcode patch container file is prepended to the initrd in cpio - * format. See Documentation/arch/x86/microcode.rst -@@ -442,12 +440,11 @@ static int __apply_microcode_amd(struct microcode_amd *mc) - * - * Returns true if container found (sets @desc), false otherwise. - */ --static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size) -+static bool early_apply_microcode(u32 cpuid_1_eax, u32 old_rev, void *ucode, size_t size) - { - struct cont_desc desc = { 0 }; - struct microcode_amd *mc; - bool ret = false; -- u32 rev, dummy; - - desc.cpuid_1_eax = cpuid_1_eax; - -@@ -457,22 +454,15 @@ static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size) - if (!mc) - return ret; - -- native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); -- - /* - * Allow application of the same revision to pick up SMT-specific - * changes even if the revision of the other SMT thread is already - * up-to-date. - */ -- if (rev > mc->hdr.patch_id) -+ if (old_rev > mc->hdr.patch_id) - return ret; - -- if (!__apply_microcode_amd(mc)) { -- ucode_new_rev = mc->hdr.patch_id; -- ret = true; -- } -- -- return ret; -+ return !__apply_microcode_amd(mc); - } - - static bool get_builtin_microcode(struct cpio_data *cp, unsigned int family) -@@ -506,9 +496,12 @@ static void __init find_blobs_in_containers(unsigned int cpuid_1_eax, struct cpi - *ret = cp; - } - --void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax) -+void __init load_ucode_amd_bsp(struct early_load_data *ed, unsigned int cpuid_1_eax) - { - struct cpio_data cp = { }; -+ u32 dummy; -+ -+ native_rdmsr(MSR_AMD64_PATCH_LEVEL, ed->old_rev, dummy); - - /* Needed in load_microcode_amd() */ - ucode_cpu_info[0].cpu_sig.sig = cpuid_1_eax; -@@ -517,7 +510,8 @@ void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax) - if (!(cp.data && cp.size)) - return; - -- early_apply_microcode(cpuid_1_eax, cp.data, cp.size); -+ if (early_apply_microcode(cpuid_1_eax, ed->old_rev, cp.data, cp.size)) -+ native_rdmsr(MSR_AMD64_PATCH_LEVEL, ed->new_rev, dummy); - } - - static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size); -@@ -625,10 +619,8 @@ void reload_ucode_amd(unsigned int cpu) - rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); - - if (rev < mc->hdr.patch_id) { -- if (!__apply_microcode_amd(mc)) { -- ucode_new_rev = mc->hdr.patch_id; -- pr_info("reload patch_level=0x%08x\n", ucode_new_rev); -- } -+ if (!__apply_microcode_amd(mc)) -+ pr_info_once("reload revision: 0x%08x\n", mc->hdr.patch_id); - } - } - -@@ -649,8 +641,6 @@ static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) - if (p && (p->patch_id == csig->rev)) - uci->mc = p->data; - -- pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev); -- - return 0; - } - -@@ -691,8 +681,6 @@ static enum ucode_state apply_microcode_amd(int cpu) - rev = mc_amd->hdr.patch_id; - ret = UCODE_UPDATED; - -- pr_info("CPU%d: new patch_level=0x%08x\n", cpu, rev); -- - out: - uci->cpu_sig.rev = rev; - c->microcode = rev; -@@ -935,11 +923,6 @@ struct microcode_ops * __init init_amd_microcode(void) - pr_warn("AMD CPU family 0x%x not supported\n", c->x86); - return NULL; - } -- -- if (ucode_new_rev) -- pr_info_once("microcode updated early to new patch_level=0x%08x\n", -- ucode_new_rev); -- - return µcode_amd_ops; - } - -diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c -index 666d25bbc5a..232026a239a 100644 ---- a/arch/x86/kernel/cpu/microcode/core.c -+++ b/arch/x86/kernel/cpu/microcode/core.c -@@ -41,8 +41,6 @@ - - #include "internal.h" - --#define DRIVER_VERSION "2.2" -- - static struct microcode_ops *microcode_ops; - bool dis_ucode_ldr = true; - -@@ -77,6 +75,8 @@ static u32 final_levels[] = { - 0, /* T-101 terminator */ - }; - -+struct early_load_data early_data; -+ - /* - * Check the current patch level on this CPU. - * -@@ -155,9 +155,9 @@ void __init load_ucode_bsp(void) - return; - - if (intel) -- load_ucode_intel_bsp(); -+ load_ucode_intel_bsp(&early_data); - else -- load_ucode_amd_bsp(cpuid_1_eax); -+ load_ucode_amd_bsp(&early_data, cpuid_1_eax); - } - - void load_ucode_ap(void) -@@ -828,6 +828,11 @@ static int __init microcode_init(void) - if (!microcode_ops) - return -ENODEV; - -+ pr_info_once("Current revision: 0x%08x\n", (early_data.new_rev ?: early_data.old_rev)); -+ -+ if (early_data.new_rev) -+ pr_info_once("Updated early from: 0x%08x\n", early_data.old_rev); -+ - microcode_pdev = platform_device_register_simple("microcode", -1, NULL, 0); - if (IS_ERR(microcode_pdev)) - return PTR_ERR(microcode_pdev); -@@ -846,8 +851,6 @@ static int __init microcode_init(void) - cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/microcode:online", - mc_cpu_online, mc_cpu_down_prep); - -- pr_info("Microcode Update Driver: v%s.", DRIVER_VERSION); -- - return 0; - - out_pdev: -diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c -index 6024feb98d2..070426b9895 100644 ---- a/arch/x86/kernel/cpu/microcode/intel.c -+++ b/arch/x86/kernel/cpu/microcode/intel.c -@@ -339,16 +339,9 @@ static enum ucode_state __apply_microcode(struct ucode_cpu_info *uci, - static enum ucode_state apply_microcode_early(struct ucode_cpu_info *uci) - { - struct microcode_intel *mc = uci->mc; -- enum ucode_state ret; -- u32 cur_rev, date; -+ u32 cur_rev; - -- ret = __apply_microcode(uci, mc, &cur_rev); -- if (ret == UCODE_UPDATED) { -- date = mc->hdr.date; -- pr_info_once("updated early: 0x%x -> 0x%x, date = %04x-%02x-%02x\n", -- cur_rev, mc->hdr.rev, date & 0xffff, date >> 24, (date >> 16) & 0xff); -- } -- return ret; -+ return __apply_microcode(uci, mc, &cur_rev); - } - - static __init bool load_builtin_intel_microcode(struct cpio_data *cp) -@@ -413,13 +406,17 @@ static int __init save_builtin_microcode(void) - early_initcall(save_builtin_microcode); - - /* Load microcode on BSP from initrd or builtin blobs */ --void __init load_ucode_intel_bsp(void) -+void __init load_ucode_intel_bsp(struct early_load_data *ed) - { - struct ucode_cpu_info uci; - -+ ed->old_rev = intel_get_microcode_revision(); -+ - uci.mc = get_microcode_blob(&uci, false); - if (uci.mc && apply_microcode_early(&uci) == UCODE_UPDATED) - ucode_patch_va = UCODE_BSP_LOADED; -+ -+ ed->new_rev = uci.cpu_sig.rev; - } - - void load_ucode_intel_ap(void) -diff --git a/arch/x86/kernel/cpu/microcode/internal.h b/arch/x86/kernel/cpu/microcode/internal.h -index f8047b12329..21776c529fa 100644 ---- a/arch/x86/kernel/cpu/microcode/internal.h -+++ b/arch/x86/kernel/cpu/microcode/internal.h -@@ -37,6 +37,12 @@ struct microcode_ops { - use_nmi : 1; - }; - -+struct early_load_data { -+ u32 old_rev; -+ u32 new_rev; -+}; -+ -+extern struct early_load_data early_data; - extern struct ucode_cpu_info ucode_cpu_info[]; - struct cpio_data find_microcode_in_initrd(const char *path); - -@@ -92,14 +98,14 @@ extern bool dis_ucode_ldr; - extern bool force_minrev; - - #ifdef CONFIG_CPU_SUP_AMD --void load_ucode_amd_bsp(unsigned int family); -+void load_ucode_amd_bsp(struct early_load_data *ed, unsigned int family); - void load_ucode_amd_ap(unsigned int family); - int save_microcode_in_initrd_amd(unsigned int family); - void reload_ucode_amd(unsigned int cpu); - struct microcode_ops *init_amd_microcode(void); - void exit_amd_microcode(void); - #else /* CONFIG_CPU_SUP_AMD */ --static inline void load_ucode_amd_bsp(unsigned int family) { } -+static inline void load_ucode_amd_bsp(struct early_load_data *ed, unsigned int family) { } - static inline void load_ucode_amd_ap(unsigned int family) { } - static inline int save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; } - static inline void reload_ucode_amd(unsigned int cpu) { } -@@ -108,12 +114,12 @@ static inline void exit_amd_microcode(void) { } - #endif /* !CONFIG_CPU_SUP_AMD */ - - #ifdef CONFIG_CPU_SUP_INTEL --void load_ucode_intel_bsp(void); -+void load_ucode_intel_bsp(struct early_load_data *ed); - void load_ucode_intel_ap(void); - void reload_ucode_intel(void); - struct microcode_ops *init_intel_microcode(void); - #else /* CONFIG_CPU_SUP_INTEL */ --static inline void load_ucode_intel_bsp(void) { } -+static inline void load_ucode_intel_bsp(struct early_load_data *ed) { } - static inline void load_ucode_intel_ap(void) { } - static inline void reload_ucode_intel(void) { } - static inline struct microcode_ops *init_intel_microcode(void) { return NULL; } -diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c -index e6bba12c759..01fa06dd06b 100644 ---- a/arch/x86/kernel/cpu/mshyperv.c -+++ b/arch/x86/kernel/cpu/mshyperv.c -@@ -262,11 +262,14 @@ static uint32_t __init ms_hyperv_platform(void) - static int hv_nmi_unknown(unsigned int val, struct pt_regs *regs) - { - static atomic_t nmi_cpu = ATOMIC_INIT(-1); -+ unsigned int old_cpu, this_cpu; - - if (!unknown_nmi_panic) - return NMI_DONE; - -- if (atomic_cmpxchg(&nmi_cpu, -1, raw_smp_processor_id()) != -1) -+ old_cpu = -1; -+ this_cpu = raw_smp_processor_id(); -+ if (!atomic_try_cmpxchg(&nmi_cpu, &old_cpu, this_cpu)) - return NMI_HANDLED; - - return NMI_DONE; -diff --git a/block/bdev.c b/block/bdev.c -index e4cfb7adb64..750aec178b6 100644 ---- a/block/bdev.c -+++ b/block/bdev.c -@@ -425,6 +425,8 @@ void bdev_set_nr_sectors(struct block_device *bdev, sector_t sectors) - - void bdev_add(struct block_device *bdev, dev_t dev) - { -+ if (bdev_stable_writes(bdev)) -+ mapping_set_stable_writes(bdev->bd_inode->i_mapping); - bdev->bd_dev = dev; - bdev->bd_inode->i_rdev = dev; - bdev->bd_inode->i_ino = dev; -diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c -index 4a42ea2972a..4b48c2c4409 100644 ---- a/block/blk-cgroup.c -+++ b/block/blk-cgroup.c -@@ -577,6 +577,7 @@ static void blkg_destroy_all(struct gendisk *disk) - struct request_queue *q = disk->queue; - struct blkcg_gq *blkg, *n; - int count = BLKG_DESTROY_BATCH_SIZE; -+ int i; - - restart: - spin_lock_irq(&q->queue_lock); -@@ -602,6 +603,18 @@ static void blkg_destroy_all(struct gendisk *disk) +diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c +index b5464199b63..32503ebb149 100644 +--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c ++++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c +@@ -1415,9 +1415,9 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + int ret; + + if (!pdata->pwm_enabled) { +- ret = pm_runtime_get_sync(pdata->dev); ++ ret = pm_runtime_get_sync(chip->dev); + if (ret < 0) { +- pm_runtime_put_sync(pdata->dev); ++ pm_runtime_put_sync(chip->dev); + return ret; } } +@@ -1433,7 +1433,7 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + SN_GPIO_MUX_MASK << (2 * SN_PWM_GPIO_IDX), + SN_GPIO_MUX_SPECIAL << (2 * SN_PWM_GPIO_IDX)); + if (ret) { +- dev_err(pdata->dev, "failed to mux in PWM function\n"); ++ dev_err(chip->dev, "failed to mux in PWM function\n"); + goto out; + } + } +@@ -1509,7 +1509,7 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, -+ /* -+ * Mark policy deactivated since policy offline has been done, and -+ * the free is scheduled, so future blkcg_deactivate_policy() can -+ * be bypassed -+ */ -+ for (i = 0; i < BLKCG_MAX_POLS; i++) { -+ struct blkcg_policy *pol = blkcg_policy[i]; -+ -+ if (pol) -+ __clear_bit(pol->plid, q->blkcg_pols); -+ } -+ - q->root_blkg = NULL; - spin_unlock_irq(&q->queue_lock); - } -diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h -index 624c03c8fe6..fd482439afb 100644 ---- a/block/blk-cgroup.h -+++ b/block/blk-cgroup.h -@@ -249,8 +249,6 @@ static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg, - { - struct blkcg_gq *blkg; - -- WARN_ON_ONCE(!rcu_read_lock_held()); -- - if (blkcg == &blkcg_root) - return q->root_blkg; - -diff --git a/block/blk-pm.c b/block/blk-pm.c -index 6b72b2e03fc..42e84207471 100644 ---- a/block/blk-pm.c -+++ b/block/blk-pm.c -@@ -163,38 +163,15 @@ EXPORT_SYMBOL(blk_pre_runtime_resume); - * @q: the queue of the device - * - * Description: -- * For historical reasons, this routine merely calls blk_set_runtime_active() -- * to do the real work of restarting the queue. It does this regardless of -- * whether the device's runtime-resume succeeded; even if it failed the -+ * Restart the queue of a runtime suspended device. It does this regardless -+ * of whether the device's runtime-resume succeeded; even if it failed the - * driver or error handler will need to communicate with the device. - * - * This function should be called near the end of the device's -- * runtime_resume callback. -+ * runtime_resume callback to correct queue runtime PM status and re-enable -+ * peeking requests from the queue. - */ - void blk_post_runtime_resume(struct request_queue *q) --{ -- blk_set_runtime_active(q); --} --EXPORT_SYMBOL(blk_post_runtime_resume); -- --/** -- * blk_set_runtime_active - Force runtime status of the queue to be active -- * @q: the queue of the device -- * -- * If the device is left runtime suspended during system suspend the resume -- * hook typically resumes the device and corrects runtime status -- * accordingly. However, that does not affect the queue runtime PM status -- * which is still "suspended". This prevents processing requests from the -- * queue. -- * -- * This function can be used in driver's resume hook to correct queue -- * runtime PM status and re-enable peeking requests from the queue. It -- * should be called before first request is added to the queue. -- * -- * This function is also called by blk_post_runtime_resume() for -- * runtime resumes. It does everything necessary to restart the queue. -- */ --void blk_set_runtime_active(struct request_queue *q) - { - int old_status; - -@@ -211,4 +188,4 @@ void blk_set_runtime_active(struct request_queue *q) - if (old_status != RPM_ACTIVE) - blk_clear_pm_only(q); - } --EXPORT_SYMBOL(blk_set_runtime_active); -+EXPORT_SYMBOL(blk_post_runtime_resume); -diff --git a/block/blk-throttle.c b/block/blk-throttle.c -index 13e4377a8b2..16f5766620a 100644 ---- a/block/blk-throttle.c -+++ b/block/blk-throttle.c -@@ -1320,6 +1320,7 @@ static void tg_conf_updated(struct throtl_grp *tg, bool global) - tg_bps_limit(tg, READ), tg_bps_limit(tg, WRITE), - tg_iops_limit(tg, READ), tg_iops_limit(tg, WRITE)); - -+ rcu_read_lock(); - /* - * Update has_rules[] flags for the updated tg's subtree. A tg is - * considered to have rules if either the tg itself or any of its -@@ -1347,6 +1348,7 @@ static void tg_conf_updated(struct throtl_grp *tg, bool global) - this_tg->latency_target = max(this_tg->latency_target, - parent_tg->latency_target); - } -+ rcu_read_unlock(); - - /* - * We're already holding queue_lock and know @tg is valid. Let's -diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c -index 5c0246b9e52..4ccf1994b97 100644 ---- a/drivers/accel/ivpu/ivpu_hw_37xx.c -+++ b/drivers/accel/ivpu/ivpu_hw_37xx.c -@@ -502,6 +502,16 @@ static int ivpu_boot_pwr_domain_enable(struct ivpu_device *vdev) - return ret; - } - -+static int ivpu_boot_pwr_domain_disable(struct ivpu_device *vdev) -+{ -+ ivpu_boot_dpu_active_drive(vdev, false); -+ ivpu_boot_pwr_island_isolation_drive(vdev, true); -+ ivpu_boot_pwr_island_trickle_drive(vdev, false); -+ ivpu_boot_pwr_island_drive(vdev, false); -+ -+ return ivpu_boot_wait_for_pwr_island_status(vdev, 0x0); -+} -+ - static void ivpu_boot_no_snoop_enable(struct ivpu_device *vdev) - { - u32 val = REGV_RD32(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES); -@@ -600,25 +610,17 @@ static int ivpu_hw_37xx_info_init(struct ivpu_device *vdev) - - static int ivpu_hw_37xx_reset(struct ivpu_device *vdev) - { -- int ret; -- u32 val; -- -- if (IVPU_WA(punit_disabled)) -- return 0; -+ int ret = 0; - -- ret = REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US); -- if (ret) { -- ivpu_err(vdev, "Timed out waiting for TRIGGER bit\n"); -- return ret; -+ if (ivpu_boot_pwr_domain_disable(vdev)) { -+ ivpu_err(vdev, "Failed to disable power domain\n"); -+ ret = -EIO; - } - -- val = REGB_RD32(VPU_37XX_BUTTRESS_VPU_IP_RESET); -- val = REG_SET_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, val); -- REGB_WR32(VPU_37XX_BUTTRESS_VPU_IP_RESET, val); -- -- ret = REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US); -- if (ret) -- ivpu_err(vdev, "Timed out waiting for RESET completion\n"); -+ if (ivpu_pll_disable(vdev)) { -+ ivpu_err(vdev, "Failed to disable PLL\n"); -+ ret = -EIO; -+ } - - return ret; - } -@@ -651,10 +653,6 @@ static int ivpu_hw_37xx_power_up(struct ivpu_device *vdev) - { - int ret; - -- ret = ivpu_hw_37xx_reset(vdev); -- if (ret) -- ivpu_warn(vdev, "Failed to reset HW: %d\n", ret); -- - ret = ivpu_hw_37xx_d0i3_disable(vdev); - if (ret) - ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); -@@ -722,11 +720,11 @@ static int ivpu_hw_37xx_power_down(struct ivpu_device *vdev) - { - int ret = 0; - -- if (!ivpu_hw_37xx_is_idle(vdev) && ivpu_hw_37xx_reset(vdev)) -- ivpu_err(vdev, "Failed to reset the VPU\n"); -+ if (!ivpu_hw_37xx_is_idle(vdev)) -+ ivpu_warn(vdev, "VPU not idle during power down\n"); - -- if (ivpu_pll_disable(vdev)) { -- ivpu_err(vdev, "Failed to disable PLL\n"); -+ if (ivpu_hw_37xx_reset(vdev)) { -+ ivpu_err(vdev, "Failed to reset VPU\n"); - ret = -EIO; - } - -diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c -index 0b7a01f38b6..d321ca7160d 100644 ---- a/drivers/acpi/acpi_video.c -+++ b/drivers/acpi/acpi_video.c -@@ -2031,7 +2031,7 @@ static int acpi_video_bus_add(struct acpi_device *device) - * HP ZBook Fury 16 G10 requires ACPI video's child devices have _PS0 - * evaluated to have functional panel brightness control. - */ -- acpi_device_fix_up_power_extended(device); -+ acpi_device_fix_up_power_children(device); - - pr_info("%s [%s] (multi-head: %s rom: %s post: %s)\n", - ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device), -diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c -index f007116a842..3b4d048c494 100644 ---- a/drivers/acpi/device_pm.c -+++ b/drivers/acpi/device_pm.c -@@ -397,6 +397,19 @@ void acpi_device_fix_up_power_extended(struct acpi_device *adev) - } - EXPORT_SYMBOL_GPL(acpi_device_fix_up_power_extended); - -+/** -+ * acpi_device_fix_up_power_children - Force a device's children into D0. -+ * @adev: Parent device object whose children's power state is to be fixed up. -+ * -+ * Call acpi_device_fix_up_power() for @adev's children so long as they -+ * are reported as present and enabled. -+ */ -+void acpi_device_fix_up_power_children(struct acpi_device *adev) -+{ -+ acpi_dev_for_each_child(adev, fix_up_power_if_applicable, NULL); -+} -+EXPORT_SYMBOL_GPL(acpi_device_fix_up_power_children); -+ - int acpi_device_update_power(struct acpi_device *device, int *state_p) - { - int state; -diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c -index 3a34a8c425f..55437f5e0c3 100644 ---- a/drivers/acpi/processor_idle.c -+++ b/drivers/acpi/processor_idle.c -@@ -592,7 +592,7 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) - while (1) { - - if (cx->entry_method == ACPI_CSTATE_HALT) -- safe_halt(); -+ raw_safe_halt(); - else if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) { - io_idle(cx->address); - } else -diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c -index 15a3bdbd075..9bd9f79cd40 100644 ---- a/drivers/acpi/resource.c -+++ b/drivers/acpi/resource.c -@@ -447,6 +447,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = { - DMI_MATCH(DMI_BOARD_NAME, "B1402CBA"), - }, - }, -+ { -+ /* Asus ExpertBook B1402CVA */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_BOARD_NAME, "B1402CVA"), -+ }, -+ }, - { - /* Asus ExpertBook B1502CBA */ - .matches = { -diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c -index 25a63d043c8..0f77e042406 100644 ---- a/drivers/ata/pata_isapnp.c -+++ b/drivers/ata/pata_isapnp.c -@@ -82,6 +82,9 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev - if (pnp_port_valid(idev, 1)) { - ctl_addr = devm_ioport_map(&idev->dev, - pnp_port_start(idev, 1), 1); -+ if (!ctl_addr) -+ return -ENOMEM; -+ - ap->ioaddr.altstatus_addr = ctl_addr; - ap->ioaddr.ctl_addr = ctl_addr; - ap->ops = &isapnp_port_ops; -diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c -index 855fdf5c3b4..b6414e1e645 100644 ---- a/drivers/block/nbd.c -+++ b/drivers/block/nbd.c -@@ -67,6 +67,7 @@ struct nbd_sock { - struct recv_thread_args { - struct work_struct work; - struct nbd_device *nbd; -+ struct nbd_sock *nsock; - int index; - }; - -@@ -395,6 +396,22 @@ static u32 req_to_nbd_cmd_type(struct request *req) - } - } - -+static struct nbd_config *nbd_get_config_unlocked(struct nbd_device *nbd) -+{ -+ if (refcount_inc_not_zero(&nbd->config_refs)) { -+ /* -+ * Add smp_mb__after_atomic to ensure that reading nbd->config_refs -+ * and reading nbd->config is ordered. The pair is the barrier in -+ * nbd_alloc_and_init_config(), avoid nbd->config_refs is set -+ * before nbd->config. -+ */ -+ smp_mb__after_atomic(); -+ return nbd->config; -+ } -+ -+ return NULL; -+} -+ - static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req) - { - struct nbd_cmd *cmd = blk_mq_rq_to_pdu(req); -@@ -409,13 +426,13 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req) - return BLK_EH_DONE; - } - -- if (!refcount_inc_not_zero(&nbd->config_refs)) { -+ config = nbd_get_config_unlocked(nbd); -+ if (!config) { - cmd->status = BLK_STS_TIMEOUT; - __clear_bit(NBD_CMD_INFLIGHT, &cmd->flags); - mutex_unlock(&cmd->lock); - goto done; - } -- config = nbd->config; - - if (config->num_connections > 1 || - (config->num_connections == 1 && nbd->tag_set.timeout)) { -@@ -489,15 +506,9 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req) - return BLK_EH_DONE; - } - --/* -- * Send or receive packet. Return a positive value on success and -- * negtive value on failue, and never return 0. -- */ --static int sock_xmit(struct nbd_device *nbd, int index, int send, -- struct iov_iter *iter, int msg_flags, int *sent) -+static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send, -+ struct iov_iter *iter, int msg_flags, int *sent) - { -- struct nbd_config *config = nbd->config; -- struct socket *sock = config->socks[index]->sock; - int result; - struct msghdr msg; - unsigned int noreclaim_flag; -@@ -540,6 +551,19 @@ static int sock_xmit(struct nbd_device *nbd, int index, int send, - return result; - } - -+/* -+ * Send or receive packet. Return a positive value on success and -+ * negtive value on failure, and never return 0. -+ */ -+static int sock_xmit(struct nbd_device *nbd, int index, int send, -+ struct iov_iter *iter, int msg_flags, int *sent) -+{ -+ struct nbd_config *config = nbd->config; -+ struct socket *sock = config->socks[index]->sock; -+ -+ return __sock_xmit(nbd, sock, send, iter, msg_flags, sent); -+} -+ - /* - * Different settings for sk->sk_sndtimeo can result in different return values - * if there is a signal pending when we enter sendmsg, because reasons? -@@ -696,7 +720,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) - return 0; - } - --static int nbd_read_reply(struct nbd_device *nbd, int index, -+static int nbd_read_reply(struct nbd_device *nbd, struct socket *sock, - struct nbd_reply *reply) - { - struct kvec iov = {.iov_base = reply, .iov_len = sizeof(*reply)}; -@@ -705,7 +729,7 @@ static int nbd_read_reply(struct nbd_device *nbd, int index, - - reply->magic = 0; - iov_iter_kvec(&to, ITER_DEST, &iov, 1, sizeof(*reply)); -- result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL); -+ result = __sock_xmit(nbd, sock, 0, &to, MSG_WAITALL, NULL); - if (result < 0) { - if (!nbd_disconnected(nbd->config)) - dev_err(disk_to_dev(nbd->disk), -@@ -829,14 +853,14 @@ static void recv_work(struct work_struct *work) - struct nbd_device *nbd = args->nbd; - struct nbd_config *config = nbd->config; - struct request_queue *q = nbd->disk->queue; -- struct nbd_sock *nsock; -+ struct nbd_sock *nsock = args->nsock; - struct nbd_cmd *cmd; - struct request *rq; - - while (1) { - struct nbd_reply reply; - -- if (nbd_read_reply(nbd, args->index, &reply)) -+ if (nbd_read_reply(nbd, nsock->sock, &reply)) - break; - - /* -@@ -871,7 +895,6 @@ static void recv_work(struct work_struct *work) - percpu_ref_put(&q->q_usage_counter); - } - -- nsock = config->socks[args->index]; - mutex_lock(&nsock->tx_lock); - nbd_mark_nsock_dead(nbd, nsock, 1); - mutex_unlock(&nsock->tx_lock); -@@ -977,12 +1000,12 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) - struct nbd_sock *nsock; - int ret; - -- if (!refcount_inc_not_zero(&nbd->config_refs)) { -+ config = nbd_get_config_unlocked(nbd); -+ if (!config) { - dev_err_ratelimited(disk_to_dev(nbd->disk), - "Socks array is empty\n"); - return -EINVAL; - } -- config = nbd->config; - - if (index >= config->num_connections) { - dev_err_ratelimited(disk_to_dev(nbd->disk), -@@ -1215,6 +1238,7 @@ static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg) - INIT_WORK(&args->work, recv_work); - args->index = i; - args->nbd = nbd; -+ args->nsock = nsock; - nsock->cookie++; - mutex_unlock(&nsock->tx_lock); - sockfd_put(old); -@@ -1397,6 +1421,7 @@ static int nbd_start_device(struct nbd_device *nbd) - refcount_inc(&nbd->config_refs); - INIT_WORK(&args->work, recv_work); - args->nbd = nbd; -+ args->nsock = config->socks[i]; - args->index = i; - queue_work(nbd->recv_workq, &args->work); - } -@@ -1530,17 +1555,20 @@ static int nbd_ioctl(struct block_device *bdev, blk_mode_t mode, - return error; - } - --static struct nbd_config *nbd_alloc_config(void) -+static int nbd_alloc_and_init_config(struct nbd_device *nbd) - { - struct nbd_config *config; - -+ if (WARN_ON(nbd->config)) -+ return -EINVAL; -+ - if (!try_module_get(THIS_MODULE)) -- return ERR_PTR(-ENODEV); -+ return -ENODEV; - - config = kzalloc(sizeof(struct nbd_config), GFP_NOFS); - if (!config) { - module_put(THIS_MODULE); -- return ERR_PTR(-ENOMEM); -+ return -ENOMEM; - } - - atomic_set(&config->recv_threads, 0); -@@ -1548,12 +1576,24 @@ static struct nbd_config *nbd_alloc_config(void) - init_waitqueue_head(&config->conn_wait); - config->blksize_bits = NBD_DEF_BLKSIZE_BITS; - atomic_set(&config->live_connections, 0); -- return config; -+ -+ nbd->config = config; -+ /* -+ * Order refcount_set(&nbd->config_refs, 1) and nbd->config assignment, -+ * its pair is the barrier in nbd_get_config_unlocked(). -+ * So nbd_get_config_unlocked() won't see nbd->config as null after -+ * refcount_inc_not_zero() succeed. -+ */ -+ smp_mb__before_atomic(); -+ refcount_set(&nbd->config_refs, 1); -+ -+ return 0; - } - - static int nbd_open(struct gendisk *disk, blk_mode_t mode) - { - struct nbd_device *nbd; -+ struct nbd_config *config; - int ret = 0; - - mutex_lock(&nbd_index_mutex); -@@ -1566,27 +1606,25 @@ static int nbd_open(struct gendisk *disk, blk_mode_t mode) - ret = -ENXIO; - goto out; - } -- if (!refcount_inc_not_zero(&nbd->config_refs)) { -- struct nbd_config *config; - -+ config = nbd_get_config_unlocked(nbd); -+ if (!config) { - mutex_lock(&nbd->config_lock); - if (refcount_inc_not_zero(&nbd->config_refs)) { - mutex_unlock(&nbd->config_lock); + ret = regmap_write(pdata->regmap, SN_PWM_PRE_DIV_REG, pre_div); + if (ret) { +- dev_err(pdata->dev, "failed to update PWM_PRE_DIV\n"); ++ dev_err(chip->dev, "failed to update PWM_PRE_DIV\n"); goto out; } -- config = nbd_alloc_config(); -- if (IS_ERR(config)) { -- ret = PTR_ERR(config); -+ ret = nbd_alloc_and_init_config(nbd); -+ if (ret) { - mutex_unlock(&nbd->config_lock); - goto out; - } -- nbd->config = config; -- refcount_set(&nbd->config_refs, 1); -+ - refcount_inc(&nbd->refs); - mutex_unlock(&nbd->config_lock); - if (max_part) - set_bit(GD_NEED_PART_SCAN, &disk->state); -- } else if (nbd_disconnected(nbd->config)) { -+ } else if (nbd_disconnected(config)) { - if (max_part) - set_bit(GD_NEED_PART_SCAN, &disk->state); - } -@@ -1990,22 +2028,17 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) - pr_err("nbd%d already in use\n", index); - return -EBUSY; - } -- if (WARN_ON(nbd->config)) { -- mutex_unlock(&nbd->config_lock); -- nbd_put(nbd); -- return -EINVAL; -- } -- config = nbd_alloc_config(); -- if (IS_ERR(config)) { -+ -+ ret = nbd_alloc_and_init_config(nbd); -+ if (ret) { - mutex_unlock(&nbd->config_lock); - nbd_put(nbd); - pr_err("couldn't allocate config\n"); -- return PTR_ERR(config); -+ return ret; - } -- nbd->config = config; -- refcount_set(&nbd->config_refs, 1); -- set_bit(NBD_RT_BOUND, &config->runtime_flags); -+ config = nbd->config; -+ set_bit(NBD_RT_BOUND, &config->runtime_flags); - ret = nbd_genl_size_set(info, nbd); - if (ret) +@@ -1521,7 +1521,7 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + FIELD_PREP(SN_PWM_INV_MASK, state->polarity == PWM_POLARITY_INVERSED); + ret = regmap_write(pdata->regmap, SN_PWM_EN_INV_REG, pwm_en_inv); + if (ret) { +- dev_err(pdata->dev, "failed to update PWM_EN/PWM_INV\n"); ++ dev_err(chip->dev, "failed to update PWM_EN/PWM_INV\n"); goto out; -@@ -2208,7 +2241,8 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info) - } - mutex_unlock(&nbd_index_mutex); - -- if (!refcount_inc_not_zero(&nbd->config_refs)) { -+ config = nbd_get_config_unlocked(nbd); -+ if (!config) { - dev_err(nbd_to_dev(nbd), - "not configured, cannot reconfigure\n"); - nbd_put(nbd); -@@ -2216,7 +2250,6 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info) } - mutex_lock(&nbd->config_lock); -- config = nbd->config; - if (!test_bit(NBD_RT_BOUND, &config->runtime_flags) || - !nbd->pid) { - dev_err(nbd_to_dev(nbd), -diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c -index 22a3cf7f32e..3021d58ca51 100644 ---- a/drivers/block/null_blk/main.c -+++ b/drivers/block/null_blk/main.c -@@ -1464,19 +1464,13 @@ blk_status_t null_process_cmd(struct nullb_cmd *cmd, enum req_op op, - return BLK_STS_OK; - } - --static blk_status_t null_handle_cmd(struct nullb_cmd *cmd, sector_t sector, -- sector_t nr_sectors, enum req_op op) -+static void null_handle_cmd(struct nullb_cmd *cmd, sector_t sector, -+ sector_t nr_sectors, enum req_op op) - { - struct nullb_device *dev = cmd->nq->dev; - struct nullb *nullb = dev->nullb; - blk_status_t sts; - -- if (test_bit(NULLB_DEV_FL_THROTTLED, &dev->flags)) { -- sts = null_handle_throttled(cmd); -- if (sts != BLK_STS_OK) -- return sts; -- } -- - if (op == REQ_OP_FLUSH) { - cmd->error = errno_to_blk_status(null_handle_flush(nullb)); - goto out; -@@ -1493,7 +1487,6 @@ static blk_status_t null_handle_cmd(struct nullb_cmd *cmd, sector_t sector, - +@@ -1529,7 +1529,7 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, out: - nullb_complete_cmd(cmd); -- return BLK_STS_OK; - } - static enum hrtimer_restart nullb_bwtimer_fn(struct hrtimer *timer) -@@ -1724,8 +1717,6 @@ static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx, - cmd->fake_timeout = should_timeout_request(rq) || - blk_should_fake_timeout(rq->q); + if (!pdata->pwm_enabled) +- pm_runtime_put_sync(pdata->dev); ++ pm_runtime_put_sync(chip->dev); -- blk_mq_start_request(rq); -- - if (should_requeue_request(rq)) { - /* - * Alternate between hitting the core BUSY path, and the -@@ -1738,6 +1729,15 @@ static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx, - return BLK_STS_OK; - } - -+ if (test_bit(NULLB_DEV_FL_THROTTLED, &nq->dev->flags)) { -+ blk_status_t sts = null_handle_throttled(cmd); -+ -+ if (sts != BLK_STS_OK) -+ return sts; -+ } -+ -+ blk_mq_start_request(rq); -+ - if (is_poll) { - spin_lock(&nq->poll_lock); - list_add_tail(&rq->queuelist, &nq->poll_list); -@@ -1747,7 +1747,8 @@ static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx, - if (cmd->fake_timeout) - return BLK_STS_OK; - -- return null_handle_cmd(cmd, sector, nr_sectors, req_op(rq)); -+ null_handle_cmd(cmd, sector, nr_sectors, req_op(rq)); -+ return BLK_STS_OK; - } - - static void null_queue_rqs(struct request **rqlist) -diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c -index a6dc3997bf5..442a0ebeb95 100644 ---- a/drivers/dpll/dpll_netlink.c -+++ b/drivers/dpll/dpll_netlink.c -@@ -1093,9 +1093,10 @@ int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info) - return -ENOMEM; - hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, - DPLL_CMD_PIN_ID_GET); -- if (!hdr) -+ if (!hdr) { -+ nlmsg_free(msg); - return -EMSGSIZE; -- -+ } - pin = dpll_pin_find_from_nlattr(info); - if (!IS_ERR(pin)) { - ret = dpll_msg_add_pin_handle(msg, pin); -@@ -1123,8 +1124,10 @@ int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info) - return -ENOMEM; - hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, - DPLL_CMD_PIN_GET); -- if (!hdr) -+ if (!hdr) { -+ nlmsg_free(msg); - return -EMSGSIZE; -+ } - ret = dpll_cmd_pin_get_one(msg, pin, info->extack); - if (ret) { - nlmsg_free(msg); -@@ -1256,8 +1259,10 @@ int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info) - return -ENOMEM; - hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, - DPLL_CMD_DEVICE_ID_GET); -- if (!hdr) -+ if (!hdr) { -+ nlmsg_free(msg); - return -EMSGSIZE; -+ } - - dpll = dpll_device_find_from_nlattr(info); - if (!IS_ERR(dpll)) { -@@ -1284,8 +1289,10 @@ int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info) - return -ENOMEM; - hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, - DPLL_CMD_DEVICE_GET); -- if (!hdr) -+ if (!hdr) { -+ nlmsg_free(msg); - return -EMSGSIZE; -+ } - - ret = dpll_device_get_one(dpll, msg, info->extack); - if (ret) { -diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h -index 2aee32344f4..772f3b049c1 100644 ---- a/drivers/gpu/drm/ast/ast_drv.h -+++ b/drivers/gpu/drm/ast/ast_drv.h -@@ -174,6 +174,17 @@ to_ast_sil164_connector(struct drm_connector *connector) - return container_of(connector, struct ast_sil164_connector, base); - } - -+struct ast_bmc_connector { -+ struct drm_connector base; -+ struct drm_connector *physical_connector; -+}; -+ -+static inline struct ast_bmc_connector * -+to_ast_bmc_connector(struct drm_connector *connector) -+{ -+ return container_of(connector, struct ast_bmc_connector, base); -+} -+ - /* - * Device - */ -@@ -218,7 +229,7 @@ struct ast_device { - } astdp; - struct { - struct drm_encoder encoder; -- struct drm_connector connector; -+ struct ast_bmc_connector bmc_connector; - } bmc; - } output; - -diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c -index cb961498428..c20534d0ef7 100644 ---- a/drivers/gpu/drm/ast/ast_mode.c -+++ b/drivers/gpu/drm/ast/ast_mode.c -@@ -1767,6 +1767,30 @@ static const struct drm_encoder_funcs ast_bmc_encoder_funcs = { - .destroy = drm_encoder_cleanup, - }; - -+static int ast_bmc_connector_helper_detect_ctx(struct drm_connector *connector, -+ struct drm_modeset_acquire_ctx *ctx, -+ bool force) -+{ -+ struct ast_bmc_connector *bmc_connector = to_ast_bmc_connector(connector); -+ struct drm_connector *physical_connector = bmc_connector->physical_connector; -+ -+ /* -+ * Most user-space compositors cannot handle more than one connected -+ * connector per CRTC. Hence, we only mark the BMC as connected if the -+ * physical connector is disconnected. If the physical connector's status -+ * is connected or unknown, the BMC remains disconnected. This has no -+ * effect on the output of the BMC. -+ * -+ * FIXME: Remove this logic once user-space compositors can handle more -+ * than one connector per CRTC. The BMC should always be connected. -+ */ -+ -+ if (physical_connector && physical_connector->status == connector_status_disconnected) -+ return connector_status_connected; -+ -+ return connector_status_disconnected; -+} -+ - static int ast_bmc_connector_helper_get_modes(struct drm_connector *connector) - { - return drm_add_modes_noedid(connector, 4096, 4096); -@@ -1774,6 +1798,7 @@ static int ast_bmc_connector_helper_get_modes(struct drm_connector *connector) - - static const struct drm_connector_helper_funcs ast_bmc_connector_helper_funcs = { - .get_modes = ast_bmc_connector_helper_get_modes, -+ .detect_ctx = ast_bmc_connector_helper_detect_ctx, - }; - - static const struct drm_connector_funcs ast_bmc_connector_funcs = { -@@ -1784,12 +1809,33 @@ static const struct drm_connector_funcs ast_bmc_connector_funcs = { - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, - }; - --static int ast_bmc_output_init(struct ast_device *ast) -+static int ast_bmc_connector_init(struct drm_device *dev, -+ struct ast_bmc_connector *bmc_connector, -+ struct drm_connector *physical_connector) -+{ -+ struct drm_connector *connector = &bmc_connector->base; -+ int ret; -+ -+ ret = drm_connector_init(dev, connector, &ast_bmc_connector_funcs, -+ DRM_MODE_CONNECTOR_VIRTUAL); -+ if (ret) -+ return ret; -+ -+ drm_connector_helper_add(connector, &ast_bmc_connector_helper_funcs); -+ -+ bmc_connector->physical_connector = physical_connector; -+ -+ return 0; -+} -+ -+static int ast_bmc_output_init(struct ast_device *ast, -+ struct drm_connector *physical_connector) - { - struct drm_device *dev = &ast->base; - struct drm_crtc *crtc = &ast->crtc; - struct drm_encoder *encoder = &ast->output.bmc.encoder; -- struct drm_connector *connector = &ast->output.bmc.connector; -+ struct ast_bmc_connector *bmc_connector = &ast->output.bmc.bmc_connector; -+ struct drm_connector *connector = &bmc_connector->base; - int ret; - - ret = drm_encoder_init(dev, encoder, -@@ -1799,13 +1845,10 @@ static int ast_bmc_output_init(struct ast_device *ast) - return ret; - encoder->possible_crtcs = drm_crtc_mask(crtc); - -- ret = drm_connector_init(dev, connector, &ast_bmc_connector_funcs, -- DRM_MODE_CONNECTOR_VIRTUAL); -+ ret = ast_bmc_connector_init(dev, bmc_connector, physical_connector); - if (ret) - return ret; - -- drm_connector_helper_add(connector, &ast_bmc_connector_helper_funcs); -- - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) - return ret; -@@ -1864,6 +1907,7 @@ static const struct drm_mode_config_funcs ast_mode_config_funcs = { - int ast_mode_config_init(struct ast_device *ast) - { - struct drm_device *dev = &ast->base; -+ struct drm_connector *physical_connector = NULL; - int ret; - - ret = drmm_mode_config_init(dev); -@@ -1904,23 +1948,27 @@ int ast_mode_config_init(struct ast_device *ast) - ret = ast_vga_output_init(ast); - if (ret) - return ret; -+ physical_connector = &ast->output.vga.vga_connector.base; - } - if (ast->tx_chip_types & AST_TX_SIL164_BIT) { - ret = ast_sil164_output_init(ast); - if (ret) - return ret; -+ physical_connector = &ast->output.sil164.sil164_connector.base; - } - if (ast->tx_chip_types & AST_TX_DP501_BIT) { - ret = ast_dp501_output_init(ast); - if (ret) - return ret; -+ physical_connector = &ast->output.dp501.connector; - } - if (ast->tx_chip_types & AST_TX_ASTDP_BIT) { - ret = ast_astdp_output_init(ast); - if (ret) - return ret; -+ physical_connector = &ast->output.astdp.connector; - } -- ret = ast_bmc_output_init(ast); -+ ret = ast_bmc_output_init(ast, physical_connector); - if (ret) - return ret; - -diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c -index 7b4628f4f12..851b312bd84 100644 ---- a/drivers/gpu/drm/i915/display/intel_dp_mst.c -+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c -@@ -1161,6 +1161,14 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo - intel_connector->port = port; - drm_dp_mst_get_port_malloc(port); - -+ /* -+ * TODO: set the AUX for the actual MST port decompressing the stream. -+ * At the moment the driver only supports enabling this globally in the -+ * first downstream MST branch, via intel_dp's (root port) AUX. -+ */ -+ intel_connector->dp.dsc_decompression_aux = &intel_dp->aux; -+ intel_dp_mst_read_decompression_port_dsc_caps(intel_dp, intel_connector); -+ - connector = &intel_connector->base; - ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, - DRM_MODE_CONNECTOR_DisplayPort); -@@ -1172,14 +1180,6 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo - - drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs); - -- /* -- * TODO: set the AUX for the actual MST port decompressing the stream. -- * At the moment the driver only supports enabling this globally in the -- * first downstream MST branch, via intel_dp's (root port) AUX. -- */ -- intel_connector->dp.dsc_decompression_aux = &intel_dp->aux; -- intel_dp_mst_read_decompression_port_dsc_caps(intel_dp, intel_connector); -- - for_each_pipe(dev_priv, pipe) { - struct drm_encoder *enc = - &intel_dp->mst_encoders[pipe]->base.base; -diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c -index ed32bf5b154..ba1186fc524 100644 ---- a/drivers/gpu/drm/i915/gt/intel_gt.c -+++ b/drivers/gpu/drm/i915/gt/intel_gt.c -@@ -982,8 +982,6 @@ int intel_gt_probe_all(struct drm_i915_private *i915) - - err: - i915_probe_error(i915, "Failed to initialize %s! (%d)\n", gtdef->name, ret); -- intel_gt_release_all(i915); -- return ret; } - -@@ -1002,15 +1000,6 @@ int intel_gt_tiles_init(struct drm_i915_private *i915) - return 0; - } - --void intel_gt_release_all(struct drm_i915_private *i915) --{ -- struct intel_gt *gt; -- unsigned int id; -- -- for_each_gt(gt, i915, id) -- i915->gt[id] = NULL; --} -- - void intel_gt_info_print(const struct intel_gt_info *info, - struct drm_printer *p) +@@ -1589,12 +1589,14 @@ static int ti_sn_pwm_probe(struct auxiliary_device *adev, { -diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c -index 8a0e2c745e1..802de2c6dec 100644 ---- a/drivers/gpu/drm/i915/i915_driver.c -+++ b/drivers/gpu/drm/i915/i915_driver.c -@@ -782,7 +782,7 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent); - ret = i915_driver_mmio_probe(i915); - if (ret < 0) -- goto out_tiles_cleanup; -+ goto out_runtime_pm_put; +- pdata->pchip.dev = pdata->dev; ++ pdata->pchip.dev = &adev->dev; + pdata->pchip.ops = &ti_sn_pwm_ops; + pdata->pchip.npwm = 1; + pdata->pchip.of_xlate = of_pwm_single_xlate; + pdata->pchip.of_pwm_n_cells = 1; - ret = i915_driver_hw_probe(i915); - if (ret < 0) -@@ -842,8 +842,6 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent) - i915_ggtt_driver_late_release(i915); - out_cleanup_mmio: - i915_driver_mmio_release(i915); --out_tiles_cleanup: -- intel_gt_release_all(i915); - out_runtime_pm_put: - enable_rpm_wakeref_asserts(&i915->runtime_pm); - i915_driver_late_release(i915); -diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h -index 1ccd1edd693..4c0528794e7 100644 ---- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h -+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h -@@ -406,6 +406,7 @@ static const struct dpu_perf_cfg sc8280xp_perf_data = { - .min_llcc_ib = 0, - .min_dram_ib = 800000, - .danger_lut_tbl = {0xf, 0xffff, 0x0}, -+ .safe_lut_tbl = {0xfe00, 0xfe00, 0xffff}, - .qos_lut_tbl = { - {.nentry = ARRAY_SIZE(sc8180x_qos_linear), - .entries = sc8180x_qos_linear -diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c -index 11d9fc2c6bf..ec933d597e2 100644 ---- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c -+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c -@@ -844,8 +844,7 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) - - return 0; - fail: -- if (mdp5_kms) -- mdp5_destroy(mdp5_kms); -+ mdp5_destroy(mdp5_kms); - return ret; ++ devm_pm_runtime_enable(&adev->dev); ++ + return pwmchip_add(&pdata->pchip); } -diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c -index e329e03e068..1b88fb52726 100644 ---- a/drivers/gpu/drm/msm/dp/dp_display.c -+++ b/drivers/gpu/drm/msm/dp/dp_display.c -@@ -365,9 +365,11 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp, - /* reset video pattern flag on disconnect */ - if (!hpd) { - dp->panel->video_test = false; -- drm_dp_set_subconnector_property(dp->dp_display.connector, -- connector_status_disconnected, -- dp->panel->dpcd, dp->panel->downstream_ports); -+ if (!dp->dp_display.is_edp) -+ drm_dp_set_subconnector_property(dp->dp_display.connector, -+ connector_status_disconnected, -+ dp->panel->dpcd, -+ dp->panel->downstream_ports); - } +@@ -1605,7 +1607,7 @@ static void ti_sn_pwm_remove(struct auxiliary_device *adev) + pwmchip_remove(&pdata->pchip); - dp->dp_display.is_connected = hpd; -@@ -396,8 +398,11 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) + if (pdata->pwm_enabled) +- pm_runtime_put_sync(pdata->dev); ++ pm_runtime_put_sync(&adev->dev); + } - dp_link_process_request(dp->link); + static const struct auxiliary_device_id ti_sn_pwm_id_table[] = { +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +index 7a0220d29a2..b35626b2df1 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +@@ -2001,12 +2001,7 @@ static void a6xx_recover(struct msm_gpu *gpu) + dev_pm_genpd_add_notifier(gmu->cxpd, &gmu->pd_nb); + dev_pm_genpd_synced_poweroff(gmu->cxpd); -- drm_dp_set_subconnector_property(dp->dp_display.connector, connector_status_connected, -- dp->panel->dpcd, dp->panel->downstream_ports); -+ if (!dp->dp_display.is_edp) -+ drm_dp_set_subconnector_property(dp->dp_display.connector, -+ connector_status_connected, -+ dp->panel->dpcd, -+ dp->panel->downstream_ports); - - edid = dp->panel->edid; - -diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c -index 40e7344180e..e3bdd7dd4cd 100644 ---- a/drivers/gpu/drm/msm/dp/dp_drm.c -+++ b/drivers/gpu/drm/msm/dp/dp_drm.c -@@ -345,6 +345,9 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct dr - if (IS_ERR(connector)) - return connector; - -+ if (!dp_display->is_edp) -+ drm_connector_attach_dp_subconnector_property(connector); -+ - drm_connector_attach_encoder(connector, encoder); - - return connector; -diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c -index 3b1ed02f644..89a6344bc86 100644 ---- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c -+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c -@@ -918,7 +918,7 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, - if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) { - if (phy->cphy_mode) { - vreg_ctrl_0 = 0x45; -- vreg_ctrl_1 = 0x45; -+ vreg_ctrl_1 = 0x41; - glbl_rescode_top_ctrl = 0x00; - glbl_rescode_bot_ctrl = 0x00; - } else { -diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c -index 2aae7d107f3..3f217b57829 100644 ---- a/drivers/gpu/drm/msm/msm_drv.c -+++ b/drivers/gpu/drm/msm/msm_drv.c -@@ -288,8 +288,6 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv) - if (ret) - goto err_msm_uninit; - -- drm_kms_helper_poll_init(ddev); +- /* Drop the rpm refcount from active submits */ +- if (active_submits) +- pm_runtime_put(&gpu->pdev->dev); - - if (priv->kms_init) { - drm_kms_helper_poll_init(ddev); - msm_fbdev_setup(ddev); -diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c -index 3adbb05ff58..d088e636edc 100644 ---- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c -+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c -@@ -539,7 +539,7 @@ r535_fifo_runl_ctor(struct nvkm_fifo *fifo) - struct nvkm_runl *runl; - struct nvkm_engn *engn; - u32 cgids = 2048; -- u32 chids = 2048 / CHID_PER_USERD; -+ u32 chids = 2048; - int ret; - NV2080_CTRL_FIFO_GET_DEVICE_INFO_TABLE_PARAMS *ctrl; +- /* And the final one from recover worker */ +- pm_runtime_put_sync(&gpu->pdev->dev); ++ pm_runtime_force_suspend(&gpu->pdev->dev); + if (!wait_for_completion_timeout(&gmu->pd_gate, msecs_to_jiffies(1000))) + DRM_DEV_ERROR(&gpu->pdev->dev, "cx gdsc didn't collapse\n"); +@@ -2015,10 +2010,7 @@ static void a6xx_recover(struct msm_gpu *gpu) + + pm_runtime_use_autosuspend(&gpu->pdev->dev); + +- if (active_submits) +- pm_runtime_get(&gpu->pdev->dev); +- +- pm_runtime_get_sync(&gpu->pdev->dev); ++ pm_runtime_force_resume(&gpu->pdev->dev); + + gpu->active_submits = active_submits; + mutex_unlock(&gpu->active_lock); diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 99e14dc212e..99124320288 100644 --- a/drivers/gpu/drm/panel/Kconfig @@ -7616,34 +5674,6 @@ index d10c3de51c6..9fd3ac441b3 100644 obj-$(CONFIG_DRM_PANEL_VISIONOX_VTDR6130) += panel-visionox-vtdr6130.o obj-$(CONFIG_DRM_PANEL_VISIONOX_R66451) += panel-visionox-r66451.o obj-$(CONFIG_DRM_PANEL_WIDECHIPS_WS2401) += panel-widechips-ws2401.o -diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c -index 9323e7b9e38..be8f48e3c1d 100644 ---- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c -+++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c -@@ -1709,6 +1709,7 @@ static const struct panel_desc auo_b101uan08_3_desc = { - .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | - MIPI_DSI_MODE_LPM, - .init_cmds = auo_b101uan08_3_init_cmd, -+ .lp11_before_reset = true, - }; - - static const struct drm_display_mode boe_tv105wum_nw0_default_mode = { -@@ -1766,11 +1767,11 @@ static const struct panel_desc starry_qfh032011_53g_desc = { - }; - - static const struct drm_display_mode starry_himax83102_j02_default_mode = { -- .clock = 161600, -+ .clock = 162850, - .hdisplay = 1200, -- .hsync_start = 1200 + 40, -- .hsync_end = 1200 + 40 + 20, -- .htotal = 1200 + 40 + 20 + 40, -+ .hsync_start = 1200 + 50, -+ .hsync_end = 1200 + 50 + 20, -+ .htotal = 1200 + 50 + 20 + 50, - .vdisplay = 1920, - .vsync_start = 1920 + 116, - .vsync_end = 1920 + 116 + 8, diff --git a/drivers/gpu/drm/panel/panel-ebbg-ft8719.c b/drivers/gpu/drm/panel/panel-ebbg-ft8719.c index e85d63a176d..2ad37758079 100644 --- a/drivers/gpu/drm/panel/panel-ebbg-ft8719.c @@ -8807,38 +6837,6 @@ index 04ce925b3d9..d7df52a25fb 100644 { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sofef00_panel_of_match); -diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c -index 6cd32b90908..9367a4572dc 100644 ---- a/drivers/gpu/drm/panel/panel-simple.c -+++ b/drivers/gpu/drm/panel/panel-simple.c -@@ -2379,13 +2379,13 @@ static const struct panel_desc innolux_g070y2_t02 = { - static const struct display_timing innolux_g101ice_l01_timing = { - .pixelclock = { 60400000, 71100000, 74700000 }, - .hactive = { 1280, 1280, 1280 }, -- .hfront_porch = { 41, 80, 100 }, -- .hback_porch = { 40, 79, 99 }, -- .hsync_len = { 1, 1, 1 }, -+ .hfront_porch = { 30, 60, 70 }, -+ .hback_porch = { 30, 60, 70 }, -+ .hsync_len = { 22, 40, 60 }, - .vactive = { 800, 800, 800 }, -- .vfront_porch = { 5, 11, 14 }, -- .vback_porch = { 4, 11, 14 }, -- .vsync_len = { 1, 1, 1 }, -+ .vfront_porch = { 3, 8, 14 }, -+ .vback_porch = { 3, 8, 14 }, -+ .vsync_len = { 4, 7, 12 }, - .flags = DISPLAY_FLAGS_DE_HIGH, - }; - -@@ -2402,6 +2402,7 @@ static const struct panel_desc innolux_g101ice_l01 = { - .disable = 200, - }, - .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, -+ .bus_flags = DRM_BUS_FLAG_DE_HIGH, - .connector_type = DRM_MODE_CONNECTOR_LVDS, - }; - diff --git a/drivers/gpu/drm/panel/panel-visionox-rm69299-shift.c b/drivers/gpu/drm/panel/panel-visionox-rm69299-shift.c new file mode 100644 index 00000000000..c9d760dc992 @@ -9602,169 +7600,8 @@ index 00000000000..c9d760dc992 + +MODULE_DESCRIPTION("DRM driver for SHIFT6mq RM69299 1080p panel"); +MODULE_LICENSE("GPL"); -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -index 066299894d0..a13473b2d54 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -@@ -247,14 +247,22 @@ static inline void vop_cfg_done(struct vop *vop) - VOP_REG_SET(vop, common, cfg_done, 1); - } - --static bool has_rb_swapped(uint32_t format) -+static bool has_rb_swapped(uint32_t version, uint32_t format) - { - switch (format) { - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ABGR8888: -- case DRM_FORMAT_BGR888: - case DRM_FORMAT_BGR565: - return true; -+ /* -+ * full framework (IP version 3.x) only need rb swapped for RGB888 and -+ * little framework (IP version 2.x) only need rb swapped for BGR888, -+ * check for 3.x to also only rb swap BGR888 for unknown vop version -+ */ -+ case DRM_FORMAT_RGB888: -+ return VOP_MAJOR(version) == 3; -+ case DRM_FORMAT_BGR888: -+ return VOP_MAJOR(version) != 3; - default: - return false; - } -@@ -1030,7 +1038,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, - VOP_WIN_SET(vop, win, dsp_info, dsp_info); - VOP_WIN_SET(vop, win, dsp_st, dsp_st); - -- rb_swap = has_rb_swapped(fb->format->format); -+ rb_swap = has_rb_swapped(vop->data->version, fb->format->format); - VOP_WIN_SET(vop, win, rb_swap, rb_swap); - - /* -diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c -index 3ca45975c68..d9e9829b220 100644 ---- a/drivers/hid/hid-apple.c -+++ b/drivers/hid/hid-apple.c -@@ -345,6 +345,8 @@ static const struct apple_non_apple_keyboard non_apple_keyboards[] = { - { "AONE" }, - { "GANSS" }, - { "Hailuck" }, -+ { "Jamesdonkey" }, -+ { "A3R" }, - }; - - static bool apple_is_non_apple_keyboard(struct hid_device *hdev) -diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c -index fd61dba8823..78cdfb8b9a7 100644 ---- a/drivers/hid/hid-asus.c -+++ b/drivers/hid/hid-asus.c -@@ -381,7 +381,7 @@ static int asus_raw_event(struct hid_device *hdev, - return 0; - } - --static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size) -+static int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size) - { - unsigned char *dmabuf; - int ret; -@@ -404,7 +404,7 @@ static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size - - static int asus_kbd_init(struct hid_device *hdev) - { -- u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54, -+ const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54, - 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; - int ret; - -@@ -418,7 +418,7 @@ static int asus_kbd_init(struct hid_device *hdev) - static int asus_kbd_get_functions(struct hid_device *hdev, - unsigned char *kbd_func) - { -- u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x05, 0x20, 0x31, 0x00, 0x08 }; -+ const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x05, 0x20, 0x31, 0x00, 0x08 }; - u8 *readbuf; - int ret; - -@@ -449,7 +449,7 @@ static int asus_kbd_get_functions(struct hid_device *hdev, - - static int rog_nkey_led_init(struct hid_device *hdev) - { -- u8 buf_init_start[] = { FEATURE_KBD_LED_REPORT_ID1, 0xB9 }; -+ const u8 buf_init_start[] = { FEATURE_KBD_LED_REPORT_ID1, 0xB9 }; - u8 buf_init2[] = { FEATURE_KBD_LED_REPORT_ID1, 0x41, 0x53, 0x55, 0x53, 0x20, - 0x54, 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; - u8 buf_init3[] = { FEATURE_KBD_LED_REPORT_ID1, -@@ -1000,6 +1000,24 @@ static int asus_start_multitouch(struct hid_device *hdev) - return 0; - } - -+static int __maybe_unused asus_resume(struct hid_device *hdev) { -+ struct asus_drvdata *drvdata = hid_get_drvdata(hdev); -+ int ret = 0; -+ -+ if (drvdata->kbd_backlight) { -+ const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4, -+ drvdata->kbd_backlight->cdev.brightness }; -+ ret = asus_kbd_set_report(hdev, buf, sizeof(buf)); -+ if (ret < 0) { -+ hid_err(hdev, "Asus failed to set keyboard backlight: %d\n", ret); -+ goto asus_resume_err; -+ } -+ } -+ -+asus_resume_err: -+ return ret; -+} -+ - static int __maybe_unused asus_reset_resume(struct hid_device *hdev) - { - struct asus_drvdata *drvdata = hid_get_drvdata(hdev); -@@ -1294,6 +1312,7 @@ static struct hid_driver asus_driver = { - .input_configured = asus_input_configured, - #ifdef CONFIG_PM - .reset_resume = asus_reset_resume, -+ .resume = asus_resume, - #endif - .event = asus_event, - .raw_event = asus_raw_event -diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c -index 8992e3c1e76..e0181218ad8 100644 ---- a/drivers/hid/hid-core.c -+++ b/drivers/hid/hid-core.c -@@ -702,15 +702,22 @@ static void hid_close_report(struct hid_device *device) - * Free a device structure, all reports, and all fields. - */ - --static void hid_device_release(struct device *dev) -+void hiddev_free(struct kref *ref) - { -- struct hid_device *hid = to_hid_device(dev); -+ struct hid_device *hid = container_of(ref, struct hid_device, ref); - - hid_close_report(hid); - kfree(hid->dev_rdesc); - kfree(hid); - } - -+static void hid_device_release(struct device *dev) -+{ -+ struct hid_device *hid = to_hid_device(dev); -+ -+ kref_put(&hid->ref, hiddev_free); -+} -+ - /* - * Fetch a report description item from the data stream. We support long - * items, though they are not used yet. -@@ -2846,6 +2853,7 @@ struct hid_device *hid_allocate_device(void) - spin_lock_init(&hdev->debug_list_lock); - sema_init(&hdev->driver_input_lock, 1); - mutex_init(&hdev->ll_open_lock); -+ kref_init(&hdev->ref); - - hid_bpf_device_init(hdev); - diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c -index e7ef1ea107c..2c63ea3e6f8 100644 +index 7dd83ec74f8..2c63ea3e6f8 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -1019,6 +1019,7 @@ static const char *absolutes[ABS_CNT] = { @@ -9775,203 +7612,6 @@ index e7ef1ea107c..2c63ea3e6f8 100644 [ABS_MISC] = "Misc", [ABS_MT_TOUCH_MAJOR] = "MTMajor", [ABS_MT_TOUCH_MINOR] = "MTMinor", -@@ -1135,6 +1136,7 @@ static int hid_debug_events_open(struct inode *inode, struct file *file) - goto out; - } - list->hdev = (struct hid_device *) inode->i_private; -+ kref_get(&list->hdev->ref); - file->private_data = list; - mutex_init(&list->read_mutex); - -@@ -1227,6 +1229,8 @@ static int hid_debug_events_release(struct inode *inode, struct file *file) - list_del(&list->node); - spin_unlock_irqrestore(&list->hdev->debug_list_lock, flags); - kfifo_free(&list->hid_debug_fifo); -+ -+ kref_put(&list->hdev->ref, hiddev_free); - kfree(list); - - return 0; -diff --git a/drivers/hid/hid-glorious.c b/drivers/hid/hid-glorious.c -index 558eb08c19e..281b3a7187c 100644 ---- a/drivers/hid/hid-glorious.c -+++ b/drivers/hid/hid-glorious.c -@@ -21,6 +21,10 @@ MODULE_DESCRIPTION("HID driver for Glorious PC Gaming Race mice"); - * Glorious Model O and O- specify the const flag in the consumer input - * report descriptor, which leads to inputs being ignored. Fix this - * by patching the descriptor. -+ * -+ * Glorious Model I incorrectly specifes the Usage Minimum for its -+ * keyboard HID report, causing keycodes to be misinterpreted. -+ * Fix this by setting Usage Minimum to 0 in that report. - */ - static __u8 *glorious_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) -@@ -32,6 +36,10 @@ static __u8 *glorious_report_fixup(struct hid_device *hdev, __u8 *rdesc, - rdesc[85] = rdesc[113] = rdesc[141] = \ - HID_MAIN_ITEM_VARIABLE | HID_MAIN_ITEM_RELATIVE; - } -+ if (*rsize == 156 && rdesc[41] == 1) { -+ hid_info(hdev, "patching Glorious Model I keyboard report descriptor\n"); -+ rdesc[41] = 0; -+ } - return rdesc; - } - -@@ -44,6 +52,8 @@ static void glorious_update_name(struct hid_device *hdev) - model = "Model O"; break; - case USB_DEVICE_ID_GLORIOUS_MODEL_D: - model = "Model D"; break; -+ case USB_DEVICE_ID_GLORIOUS_MODEL_I: -+ model = "Model I"; break; - } - - snprintf(hdev->name, sizeof(hdev->name), "%s %s", "Glorious", model); -@@ -66,10 +76,12 @@ static int glorious_probe(struct hid_device *hdev, - } - - static const struct hid_device_id glorious_devices[] = { -- { HID_USB_DEVICE(USB_VENDOR_ID_GLORIOUS, -+ { HID_USB_DEVICE(USB_VENDOR_ID_SINOWEALTH, - USB_DEVICE_ID_GLORIOUS_MODEL_O) }, -- { HID_USB_DEVICE(USB_VENDOR_ID_GLORIOUS, -+ { HID_USB_DEVICE(USB_VENDOR_ID_SINOWEALTH, - USB_DEVICE_ID_GLORIOUS_MODEL_D) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_LAVIEW, -+ USB_DEVICE_ID_GLORIOUS_MODEL_I) }, - { } - }; - MODULE_DEVICE_TABLE(hid, glorious_devices); -diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index f7973ccd84a..c6e4e0d1f21 100644 ---- a/drivers/hid/hid-ids.h -+++ b/drivers/hid/hid-ids.h -@@ -511,10 +511,6 @@ - #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_010A 0x010a - #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100 0xe100 - --#define USB_VENDOR_ID_GLORIOUS 0x258a --#define USB_DEVICE_ID_GLORIOUS_MODEL_D 0x0033 --#define USB_DEVICE_ID_GLORIOUS_MODEL_O 0x0036 -- - #define I2C_VENDOR_ID_GOODIX 0x27c6 - #define I2C_DEVICE_ID_GOODIX_01F0 0x01f0 - -@@ -745,6 +741,9 @@ - #define USB_VENDOR_ID_LABTEC 0x1020 - #define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006 - -+#define USB_VENDOR_ID_LAVIEW 0x22D4 -+#define USB_DEVICE_ID_GLORIOUS_MODEL_I 0x1503 -+ - #define USB_VENDOR_ID_LCPOWER 0x1241 - #define USB_DEVICE_ID_LCPOWER_LC1000 0xf767 - -@@ -869,7 +868,6 @@ - #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2 0xc534 - #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1 0xc539 - #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1 0xc53f --#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2 0xc547 - #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a - #define USB_DEVICE_ID_SPACETRAVELLER 0xc623 - #define USB_DEVICE_ID_SPACENAVIGATOR 0xc626 -@@ -1160,6 +1158,10 @@ - #define USB_VENDOR_ID_SIGMATEL 0x066F - #define USB_DEVICE_ID_SIGMATEL_STMP3780 0x3780 - -+#define USB_VENDOR_ID_SINOWEALTH 0x258a -+#define USB_DEVICE_ID_GLORIOUS_MODEL_D 0x0033 -+#define USB_DEVICE_ID_GLORIOUS_MODEL_O 0x0036 -+ - #define USB_VENDOR_ID_SIS_TOUCH 0x0457 - #define USB_DEVICE_ID_SIS9200_TOUCH 0x9200 - #define USB_DEVICE_ID_SIS817_TOUCH 0x0817 -diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c -index 8afe3be683b..e6a8b6d8eab 100644 ---- a/drivers/hid/hid-logitech-dj.c -+++ b/drivers/hid/hid-logitech-dj.c -@@ -1695,12 +1695,11 @@ static int logi_dj_raw_event(struct hid_device *hdev, - } - /* - * Mouse-only receivers send unnumbered mouse data. The 27 MHz -- * receiver uses 6 byte packets, the nano receiver 8 bytes, -- * the lightspeed receiver (Pro X Superlight) 13 bytes. -+ * receiver uses 6 byte packets, the nano receiver 8 bytes. - */ - if (djrcv_dev->unnumbered_application == HID_GD_MOUSE && -- size <= 13){ -- u8 mouse_report[14]; -+ size <= 8) { -+ u8 mouse_report[9]; - - /* Prepend report id */ - mouse_report[0] = REPORT_TYPE_MOUSE; -@@ -1984,10 +1983,6 @@ static const struct hid_device_id logi_dj_receivers[] = { - HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, - USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1), - .driver_data = recvr_type_gaming_hidpp}, -- { /* Logitech lightspeed receiver (0xc547) */ -- HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, -- USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2), -- .driver_data = recvr_type_gaming_hidpp}, - - { /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */ - HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER), -diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c -index 72883e0ce75..aef0785c91c 100644 ---- a/drivers/hid/hid-mcp2221.c -+++ b/drivers/hid/hid-mcp2221.c -@@ -1142,6 +1142,8 @@ static int mcp2221_probe(struct hid_device *hdev, - if (ret) - return ret; - -+ hid_device_io_start(hdev); -+ - /* Set I2C bus clock diviser */ - if (i2c_clk_freq > 400) - i2c_clk_freq = 400; -@@ -1157,12 +1159,12 @@ static int mcp2221_probe(struct hid_device *hdev, - snprintf(mcp->adapter.name, sizeof(mcp->adapter.name), - "MCP2221 usb-i2c bridge"); - -+ i2c_set_adapdata(&mcp->adapter, mcp); - ret = devm_i2c_add_adapter(&hdev->dev, &mcp->adapter); - if (ret) { - hid_err(hdev, "can't add usb-i2c adapter: %d\n", ret); - return ret; - } -- i2c_set_adapdata(&mcp->adapter, mcp); - - #if IS_REACHABLE(CONFIG_GPIOLIB) - /* Setup GPIO chip */ -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index e098cc7b394..fd5b0637dad 100644 ---- a/drivers/hid/hid-multitouch.c -+++ b/drivers/hid/hid-multitouch.c -@@ -2046,6 +2046,11 @@ static const struct hid_device_id mt_devices[] = { - MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, - USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) }, - -+ /* HONOR GLO-GXXX panel */ -+ { .driver_data = MT_CLS_VTL, -+ HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, -+ 0x347d, 0x7853) }, -+ - /* Ilitek dual touch panel */ - { .driver_data = MT_CLS_NSMU, - MT_USB_DEVICE(USB_VENDOR_ID_ILITEK, -diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c -index 5a48fcaa32f..ea472923fab 100644 ---- a/drivers/hid/hid-quirks.c -+++ b/drivers/hid/hid-quirks.c -@@ -33,6 +33,7 @@ static const struct hid_device_id hid_quirks[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_AKAI, USB_DEVICE_ID_AKAI_MPKMINI2), HID_QUIRK_NO_INIT_REPORTS }, - { HID_USB_DEVICE(USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD), HID_QUIRK_BADPAD }, - { HID_USB_DEVICE(USB_VENDOR_ID_AMI, USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE), HID_QUIRK_ALWAYS_POLL }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI), HID_QUIRK_ALWAYS_POLL }, - { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM), HID_QUIRK_NOGET }, - { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC), HID_QUIRK_NOGET }, - { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM), HID_QUIRK_NOGET }, diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 6ba984d7f0b..6ed273a9b3c 100644 --- a/drivers/input/misc/Kconfig @@ -13112,18 +10752,18 @@ index 00000000000..da8a85456f5 +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c -index 549ae4dba3a..0fd2c124299 100644 +index d326fa230b9..c74b2eee686 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c -@@ -245,6 +245,7 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { - { .compatible = "qcom,adreno" }, +@@ -246,6 +246,7 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { + { .compatible = "qcom,adreno-gmu" }, { .compatible = "qcom,mdp4" }, { .compatible = "qcom,mdss" }, + { .compatible = "qcom,qcm2290-mdss" }, { .compatible = "qcom,sc7180-mdss" }, { .compatible = "qcom,sc7180-mss-pil" }, { .compatible = "qcom,sc7280-mdss" }, -@@ -254,6 +255,7 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { +@@ -255,6 +256,7 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { { .compatible = "qcom,sdm670-mdss" }, { .compatible = "qcom,sdm845-mdss" }, { .compatible = "qcom,sdm845-mss-pil" }, @@ -13131,189 +10771,2854 @@ index 549ae4dba3a..0fd2c124299 100644 { .compatible = "qcom,sm6350-mdss" }, { .compatible = "qcom,sm6375-mdss" }, { .compatible = "qcom,sm8150-mdss" }, -diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h -index 05be59ae21b..6ae2329052c 100644 ---- a/drivers/md/bcache/bcache.h -+++ b/drivers/md/bcache/bcache.h -@@ -265,6 +265,7 @@ struct bcache_device { - #define BCACHE_DEV_WB_RUNNING 3 - #define BCACHE_DEV_RATE_DW_RUNNING 4 - int nr_stripes; -+#define BCH_MIN_STRIPE_SZ ((4 << 20) >> SECTOR_SHIFT) - unsigned int stripe_size; - atomic_t *stripe_sectors_dirty; - unsigned long *full_dirty_stripes; -diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c -index ae5cbb55861..de3019972b3 100644 ---- a/drivers/md/bcache/btree.c -+++ b/drivers/md/bcache/btree.c -@@ -1000,6 +1000,9 @@ static struct btree *mca_alloc(struct cache_set *c, struct btree_op *op, - * - * The btree node will have either a read or a write lock held, depending on - * level and op->lock. +diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig +index 59ee0ca2c97..34cc13370d2 100644 +--- a/drivers/media/i2c/Kconfig ++++ b/drivers/media/i2c/Kconfig +@@ -201,6 +201,20 @@ config VIDEO_IMX415 + To compile this driver as a module, choose M here: the + module will be called imx415. + ++config VIDEO_IMX519 ++ tristate "Sony IMX519 sensor support" ++ depends on I2C && VIDEO_DEV ++ select MEDIA_CONTROLLER ++ select VIDEO_V4L2_SUBDEV_API ++ select V4L2_CCI_I2C ++ select V4L2_FWNODE ++ help ++ This is a Video4Linux2 sensor driver for the Sony ++ IMX519 camera. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called imx519. ++ + config VIDEO_MAX9271_LIB + tristate + +diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile +index f5010f80a21..b8c543f0a03 100644 +--- a/drivers/media/i2c/Makefile ++++ b/drivers/media/i2c/Makefile +@@ -53,6 +53,7 @@ obj-$(CONFIG_VIDEO_IMX335) += imx335.o + obj-$(CONFIG_VIDEO_IMX355) += imx355.o + obj-$(CONFIG_VIDEO_IMX412) += imx412.o + obj-$(CONFIG_VIDEO_IMX415) += imx415.o ++obj-$(CONFIG_VIDEO_IMX519) += imx519.o + obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o + obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o + obj-$(CONFIG_VIDEO_KS0127) += ks0127.o +diff --git a/drivers/media/i2c/imx519.c b/drivers/media/i2c/imx519.c +new file mode 100644 +index 00000000000..5d799209817 +--- /dev/null ++++ b/drivers/media/i2c/imx519.c +@@ -0,0 +1,1864 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * A V4L2 driver for Sony IMX519 cameras. ++ * Copyright (C) 2022 Arducam Technology co., Ltd. + * -+ * Note: Only error code or btree pointer will be returned, it is unncessary -+ * for callers to check NULL pointer. ++ * Based on Sony IMX477 camera driver ++ * Copyright (C) 2020 Raspberry Pi (Trading) Ltd ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Chip ID */ ++#define IMX519_REG_CHIP_ID CCI_REG16(0x0016) ++#define IMX519_CHIP_ID 0x0519 ++ ++#define IMX519_REG_MODE_SELECT CCI_REG8(0x0100) ++#define IMX519_MODE_STANDBY 0x00 ++#define IMX519_MODE_STREAMING 0x01 ++ ++#define IMX519_REG_ORIENTATION CCI_REG8(0x101) ++ ++#define IMX519_XCLK_FREQ 24000000 ++ ++#define IMX519_DEFAULT_LINK_FREQ 493500000 ++ ++/* Pixel rate is fixed at 686MHz for all the modes */ ++#define IMX519_PIXEL_RATE 426666667 ++ ++/* V_TIMING internal */ ++#define IMX519_REG_FRAME_LENGTH CCI_REG16(0x0340) ++#define IMX519_FRAME_LENGTH_MAX 0xffdc ++ ++/* Long exposure multiplier */ ++#define IMX519_LONG_EXP_SHIFT_MAX 7 ++#define IMX519_LONG_EXP_SHIFT_REG CCI_REG8(0x3100) ++ ++/* Exposure control */ ++#define IMX519_REG_EXPOSURE CCI_REG16(0x0202) ++#define IMX519_EXPOSURE_OFFSET 32 ++#define IMX519_EXPOSURE_MIN 20 ++#define IMX519_EXPOSURE_STEP 1 ++#define IMX519_EXPOSURE_DEFAULT 0x3e8 ++#define IMX519_EXPOSURE_MAX (IMX519_FRAME_LENGTH_MAX - \ ++ IMX519_EXPOSURE_OFFSET) ++ ++/* Analog gain control */ ++#define IMX519_REG_ANALOG_GAIN CCI_REG16(0x0204) ++#define IMX519_ANA_GAIN_MIN 0 ++#define IMX519_ANA_GAIN_MAX 960 ++#define IMX519_ANA_GAIN_STEP 1 ++#define IMX519_ANA_GAIN_DEFAULT 0x0 ++ ++/* Digital gain control */ ++#define IMX519_REG_DIGITAL_GAIN CCI_REG16(0x020e) ++#define IMX519_DGTL_GAIN_MIN 0x0100 ++#define IMX519_DGTL_GAIN_MAX 0xffff ++#define IMX519_DGTL_GAIN_DEFAULT 0x0100 ++#define IMX519_DGTL_GAIN_STEP 1 ++ ++/* Test Pattern Control */ ++#define IMX519_REG_TEST_PATTERN CCI_REG16(0x0600) ++#define IMX519_TEST_PATTERN_DISABLE 0 ++#define IMX519_TEST_PATTERN_SOLID_COLOR 1 ++#define IMX519_TEST_PATTERN_COLOR_BARS 2 ++#define IMX519_TEST_PATTERN_GREY_COLOR 3 ++#define IMX519_TEST_PATTERN_PN9 4 ++ ++/* Test pattern colour components */ ++#define IMX519_REG_TEST_PATTERN_R CCI_REG16(0x0602) ++#define IMX519_REG_TEST_PATTERN_GR CCI_REG16(0x0604) ++#define IMX519_REG_TEST_PATTERN_B CCI_REG16(0x0606) ++#define IMX519_REG_TEST_PATTERN_GB CCI_REG16(0x0608) ++#define IMX519_TEST_PATTERN_COLOUR_MIN 0 ++#define IMX519_TEST_PATTERN_COLOUR_MAX 0x0fff ++#define IMX519_TEST_PATTERN_COLOUR_STEP 1 ++#define IMX519_TEST_PATTERN_R_DEFAULT IMX519_TEST_PATTERN_COLOUR_MAX ++#define IMX519_TEST_PATTERN_GR_DEFAULT 0 ++#define IMX519_TEST_PATTERN_B_DEFAULT 0 ++#define IMX519_TEST_PATTERN_GB_DEFAULT 0 ++ ++/* IMX519 native and active pixel array size. */ ++#define IMX519_NATIVE_WIDTH 4672U ++#define IMX519_NATIVE_HEIGHT 3648U ++#define IMX519_PIXEL_ARRAY_LEFT 8U ++#define IMX519_PIXEL_ARRAY_TOP 48U ++#define IMX519_PIXEL_ARRAY_WIDTH 4656U ++#define IMX519_PIXEL_ARRAY_HEIGHT 3496U ++ ++struct imx519_reg_list { ++ unsigned int num_of_regs; ++ const struct cci_reg_sequence *regs; ++}; ++ ++/* Mode : resolution and related config&values */ ++struct imx519_mode { ++ /* Frame width */ ++ unsigned int width; ++ ++ /* Frame height */ ++ unsigned int height; ++ ++ /* H-timing in pixels */ ++ unsigned int line_length_pix; ++ ++ /* Analog crop rectangle. */ ++ struct v4l2_rect crop; ++ ++ /* Highest possible framerate. */ ++ struct v4l2_fract timeperframe_min; ++ ++ /* Default framerate. */ ++ struct v4l2_fract timeperframe_default; ++ ++ /* Default register values */ ++ struct imx519_reg_list reg_list; ++}; ++ ++static const struct cci_reg_sequence mode_common_regs[] = { ++ { CCI_REG8(0x0136), 0x18 }, ++ { CCI_REG8(0x0137), 0x00 }, ++ { CCI_REG8(0x3c7e), 0x01 }, ++ { CCI_REG8(0x3c7f), 0x07 }, ++ { CCI_REG8(0x3020), 0x00 }, ++ { CCI_REG8(0x3e35), 0x01 }, ++ { CCI_REG8(0x3f7f), 0x01 }, ++ { CCI_REG8(0x5609), 0x57 }, ++ { CCI_REG8(0x5613), 0x51 }, ++ { CCI_REG8(0x561f), 0x5e }, ++ { CCI_REG8(0x5623), 0xd2 }, ++ { CCI_REG8(0x5637), 0x11 }, ++ { CCI_REG8(0x5657), 0x11 }, ++ { CCI_REG8(0x5659), 0x12 }, ++ { CCI_REG8(0x5733), 0x60 }, ++ { CCI_REG8(0x5905), 0x57 }, ++ { CCI_REG8(0x590f), 0x51 }, ++ { CCI_REG8(0x591b), 0x5e }, ++ { CCI_REG8(0x591f), 0xd2 }, ++ { CCI_REG8(0x5933), 0x11 }, ++ { CCI_REG8(0x5953), 0x11 }, ++ { CCI_REG8(0x5955), 0x12 }, ++ { CCI_REG8(0x5a2f), 0x60 }, ++ { CCI_REG8(0x5a85), 0x57 }, ++ { CCI_REG8(0x5a8f), 0x51 }, ++ { CCI_REG8(0x5a9b), 0x5e }, ++ { CCI_REG8(0x5a9f), 0xd2 }, ++ { CCI_REG8(0x5ab3), 0x11 }, ++ { CCI_REG8(0x5ad3), 0x11 }, ++ { CCI_REG8(0x5ad5), 0x12 }, ++ { CCI_REG8(0x5baf), 0x60 }, ++ { CCI_REG8(0x5c15), 0x2a }, ++ { CCI_REG8(0x5c17), 0x80 }, ++ { CCI_REG8(0x5c19), 0x31 }, ++ { CCI_REG8(0x5c1b), 0x87 }, ++ { CCI_REG8(0x5c25), 0x25 }, ++ { CCI_REG8(0x5c27), 0x7b }, ++ { CCI_REG8(0x5c29), 0x2a }, ++ { CCI_REG8(0x5c2b), 0x80 }, ++ { CCI_REG8(0x5c2d), 0x31 }, ++ { CCI_REG8(0x5c2f), 0x87 }, ++ { CCI_REG8(0x5c35), 0x2b }, ++ { CCI_REG8(0x5c37), 0x81 }, ++ { CCI_REG8(0x5c39), 0x31 }, ++ { CCI_REG8(0x5c3b), 0x87 }, ++ { CCI_REG8(0x5c45), 0x25 }, ++ { CCI_REG8(0x5c47), 0x7b }, ++ { CCI_REG8(0x5c49), 0x2a }, ++ { CCI_REG8(0x5c4b), 0x80 }, ++ { CCI_REG8(0x5c4d), 0x31 }, ++ { CCI_REG8(0x5c4f), 0x87 }, ++ { CCI_REG8(0x5c55), 0x2d }, ++ { CCI_REG8(0x5c57), 0x83 }, ++ { CCI_REG8(0x5c59), 0x32 }, ++ { CCI_REG8(0x5c5b), 0x88 }, ++ { CCI_REG8(0x5c65), 0x29 }, ++ { CCI_REG8(0x5c67), 0x7f }, ++ { CCI_REG8(0x5c69), 0x2e }, ++ { CCI_REG8(0x5c6b), 0x84 }, ++ { CCI_REG8(0x5c6d), 0x32 }, ++ { CCI_REG8(0x5c6f), 0x88 }, ++ { CCI_REG8(0x5e69), 0x04 }, ++ { CCI_REG8(0x5e9d), 0x00 }, ++ { CCI_REG8(0x5f18), 0x10 }, ++ { CCI_REG8(0x5f1a), 0x0e }, ++ { CCI_REG8(0x5f20), 0x12 }, ++ { CCI_REG8(0x5f22), 0x10 }, ++ { CCI_REG8(0x5f24), 0x0e }, ++ { CCI_REG8(0x5f28), 0x10 }, ++ { CCI_REG8(0x5f2a), 0x0e }, ++ { CCI_REG8(0x5f30), 0x12 }, ++ { CCI_REG8(0x5f32), 0x10 }, ++ { CCI_REG8(0x5f34), 0x0e }, ++ { CCI_REG8(0x5f38), 0x0f }, ++ { CCI_REG8(0x5f39), 0x0d }, ++ { CCI_REG8(0x5f3c), 0x11 }, ++ { CCI_REG8(0x5f3d), 0x0f }, ++ { CCI_REG8(0x5f3e), 0x0d }, ++ { CCI_REG8(0x5f61), 0x07 }, ++ { CCI_REG8(0x5f64), 0x05 }, ++ { CCI_REG8(0x5f67), 0x03 }, ++ { CCI_REG8(0x5f6a), 0x03 }, ++ { CCI_REG8(0x5f6d), 0x07 }, ++ { CCI_REG8(0x5f70), 0x07 }, ++ { CCI_REG8(0x5f73), 0x05 }, ++ { CCI_REG8(0x5f76), 0x02 }, ++ { CCI_REG8(0x5f79), 0x07 }, ++ { CCI_REG8(0x5f7c), 0x07 }, ++ { CCI_REG8(0x5f7f), 0x07 }, ++ { CCI_REG8(0x5f82), 0x07 }, ++ { CCI_REG8(0x5f85), 0x03 }, ++ { CCI_REG8(0x5f88), 0x02 }, ++ { CCI_REG8(0x5f8b), 0x01 }, ++ { CCI_REG8(0x5f8e), 0x01 }, ++ { CCI_REG8(0x5f91), 0x04 }, ++ { CCI_REG8(0x5f94), 0x05 }, ++ { CCI_REG8(0x5f97), 0x02 }, ++ { CCI_REG8(0x5f9d), 0x07 }, ++ { CCI_REG8(0x5fa0), 0x07 }, ++ { CCI_REG8(0x5fa3), 0x07 }, ++ { CCI_REG8(0x5fa6), 0x07 }, ++ { CCI_REG8(0x5fa9), 0x03 }, ++ { CCI_REG8(0x5fac), 0x01 }, ++ { CCI_REG8(0x5faf), 0x01 }, ++ { CCI_REG8(0x5fb5), 0x03 }, ++ { CCI_REG8(0x5fb8), 0x02 }, ++ { CCI_REG8(0x5fbb), 0x01 }, ++ { CCI_REG8(0x5fc1), 0x07 }, ++ { CCI_REG8(0x5fc4), 0x07 }, ++ { CCI_REG8(0x5fc7), 0x07 }, ++ { CCI_REG8(0x5fd1), 0x00 }, ++ { CCI_REG8(0x6302), 0x79 }, ++ { CCI_REG8(0x6305), 0x78 }, ++ { CCI_REG8(0x6306), 0xa5 }, ++ { CCI_REG8(0x6308), 0x03 }, ++ { CCI_REG8(0x6309), 0x20 }, ++ { CCI_REG8(0x630b), 0x0a }, ++ { CCI_REG8(0x630d), 0x48 }, ++ { CCI_REG8(0x630f), 0x06 }, ++ { CCI_REG8(0x6311), 0xa4 }, ++ { CCI_REG8(0x6313), 0x03 }, ++ { CCI_REG8(0x6314), 0x20 }, ++ { CCI_REG8(0x6316), 0x0a }, ++ { CCI_REG8(0x6317), 0x31 }, ++ { CCI_REG8(0x6318), 0x4a }, ++ { CCI_REG8(0x631a), 0x06 }, ++ { CCI_REG8(0x631b), 0x40 }, ++ { CCI_REG8(0x631c), 0xa4 }, ++ { CCI_REG8(0x631e), 0x03 }, ++ { CCI_REG8(0x631f), 0x20 }, ++ { CCI_REG8(0x6321), 0x0a }, ++ { CCI_REG8(0x6323), 0x4a }, ++ { CCI_REG8(0x6328), 0x80 }, ++ { CCI_REG8(0x6329), 0x01 }, ++ { CCI_REG8(0x632a), 0x30 }, ++ { CCI_REG8(0x632b), 0x02 }, ++ { CCI_REG8(0x632c), 0x20 }, ++ { CCI_REG8(0x632d), 0x02 }, ++ { CCI_REG8(0x632e), 0x30 }, ++ { CCI_REG8(0x6330), 0x60 }, ++ { CCI_REG8(0x6332), 0x90 }, ++ { CCI_REG8(0x6333), 0x01 }, ++ { CCI_REG8(0x6334), 0x30 }, ++ { CCI_REG8(0x6335), 0x02 }, ++ { CCI_REG8(0x6336), 0x20 }, ++ { CCI_REG8(0x6338), 0x80 }, ++ { CCI_REG8(0x633a), 0xa0 }, ++ { CCI_REG8(0x633b), 0x01 }, ++ { CCI_REG8(0x633c), 0x60 }, ++ { CCI_REG8(0x633d), 0x02 }, ++ { CCI_REG8(0x633e), 0x60 }, ++ { CCI_REG8(0x633f), 0x01 }, ++ { CCI_REG8(0x6340), 0x30 }, ++ { CCI_REG8(0x6341), 0x02 }, ++ { CCI_REG8(0x6342), 0x20 }, ++ { CCI_REG8(0x6343), 0x03 }, ++ { CCI_REG8(0x6344), 0x80 }, ++ { CCI_REG8(0x6345), 0x03 }, ++ { CCI_REG8(0x6346), 0x90 }, ++ { CCI_REG8(0x6348), 0xf0 }, ++ { CCI_REG8(0x6349), 0x01 }, ++ { CCI_REG8(0x634a), 0x20 }, ++ { CCI_REG8(0x634b), 0x02 }, ++ { CCI_REG8(0x634c), 0x10 }, ++ { CCI_REG8(0x634d), 0x03 }, ++ { CCI_REG8(0x634e), 0x60 }, ++ { CCI_REG8(0x6350), 0xa0 }, ++ { CCI_REG8(0x6351), 0x01 }, ++ { CCI_REG8(0x6352), 0x60 }, ++ { CCI_REG8(0x6353), 0x02 }, ++ { CCI_REG8(0x6354), 0x50 }, ++ { CCI_REG8(0x6355), 0x02 }, ++ { CCI_REG8(0x6356), 0x60 }, ++ { CCI_REG8(0x6357), 0x01 }, ++ { CCI_REG8(0x6358), 0x30 }, ++ { CCI_REG8(0x6359), 0x02 }, ++ { CCI_REG8(0x635a), 0x30 }, ++ { CCI_REG8(0x635b), 0x03 }, ++ { CCI_REG8(0x635c), 0x90 }, ++ { CCI_REG8(0x635f), 0x01 }, ++ { CCI_REG8(0x6360), 0x10 }, ++ { CCI_REG8(0x6361), 0x01 }, ++ { CCI_REG8(0x6362), 0x40 }, ++ { CCI_REG8(0x6363), 0x02 }, ++ { CCI_REG8(0x6364), 0x50 }, ++ { CCI_REG8(0x6368), 0x70 }, ++ { CCI_REG8(0x636a), 0xa0 }, ++ { CCI_REG8(0x636b), 0x01 }, ++ { CCI_REG8(0x636c), 0x50 }, ++ { CCI_REG8(0x637d), 0xe4 }, ++ { CCI_REG8(0x637e), 0xb4 }, ++ { CCI_REG8(0x638c), 0x8e }, ++ { CCI_REG8(0x638d), 0x38 }, ++ { CCI_REG8(0x638e), 0xe3 }, ++ { CCI_REG8(0x638f), 0x4c }, ++ { CCI_REG8(0x6390), 0x30 }, ++ { CCI_REG8(0x6391), 0xc3 }, ++ { CCI_REG8(0x6392), 0xae }, ++ { CCI_REG8(0x6393), 0xba }, ++ { CCI_REG8(0x6394), 0xeb }, ++ { CCI_REG8(0x6395), 0x6e }, ++ { CCI_REG8(0x6396), 0x34 }, ++ { CCI_REG8(0x6397), 0xe3 }, ++ { CCI_REG8(0x6398), 0xcf }, ++ { CCI_REG8(0x6399), 0x3c }, ++ { CCI_REG8(0x639a), 0xf3 }, ++ { CCI_REG8(0x639b), 0x0c }, ++ { CCI_REG8(0x639c), 0x30 }, ++ { CCI_REG8(0x639d), 0xc1 }, ++ { CCI_REG8(0x63b9), 0xa3 }, ++ { CCI_REG8(0x63ba), 0xfe }, ++ { CCI_REG8(0x7600), 0x01 }, ++ { CCI_REG8(0x79a0), 0x01 }, ++ { CCI_REG8(0x79a1), 0x01 }, ++ { CCI_REG8(0x79a2), 0x01 }, ++ { CCI_REG8(0x79a3), 0x01 }, ++ { CCI_REG8(0x79a4), 0x01 }, ++ { CCI_REG8(0x79a5), 0x20 }, ++ { CCI_REG8(0x79a9), 0x00 }, ++ { CCI_REG8(0x79aa), 0x01 }, ++ { CCI_REG8(0x79ad), 0x00 }, ++ { CCI_REG8(0x79af), 0x00 }, ++ { CCI_REG8(0x8173), 0x01 }, ++ { CCI_REG8(0x835c), 0x01 }, ++ { CCI_REG8(0x8a74), 0x01 }, ++ { CCI_REG8(0x8c1f), 0x00 }, ++ { CCI_REG8(0x8c27), 0x00 }, ++ { CCI_REG8(0x8c3b), 0x03 }, ++ { CCI_REG8(0x9004), 0x0b }, ++ { CCI_REG8(0x920c), 0x6a }, ++ { CCI_REG8(0x920d), 0x22 }, ++ { CCI_REG8(0x920e), 0x6a }, ++ { CCI_REG8(0x920f), 0x23 }, ++ { CCI_REG8(0x9214), 0x6a }, ++ { CCI_REG8(0x9215), 0x20 }, ++ { CCI_REG8(0x9216), 0x6a }, ++ { CCI_REG8(0x9217), 0x21 }, ++ { CCI_REG8(0x9385), 0x3e }, ++ { CCI_REG8(0x9387), 0x1b }, ++ { CCI_REG8(0x938d), 0x4d }, ++ { CCI_REG8(0x938f), 0x43 }, ++ { CCI_REG8(0x9391), 0x1b }, ++ { CCI_REG8(0x9395), 0x4d }, ++ { CCI_REG8(0x9397), 0x43 }, ++ { CCI_REG8(0x9399), 0x1b }, ++ { CCI_REG8(0x939d), 0x3e }, ++ { CCI_REG8(0x939f), 0x2f }, ++ { CCI_REG8(0x93a5), 0x43 }, ++ { CCI_REG8(0x93a7), 0x2f }, ++ { CCI_REG8(0x93a9), 0x2f }, ++ { CCI_REG8(0x93ad), 0x34 }, ++ { CCI_REG8(0x93af), 0x2f }, ++ { CCI_REG8(0x93b5), 0x3e }, ++ { CCI_REG8(0x93b7), 0x2f }, ++ { CCI_REG8(0x93bd), 0x4d }, ++ { CCI_REG8(0x93bf), 0x43 }, ++ { CCI_REG8(0x93c1), 0x2f }, ++ { CCI_REG8(0x93c5), 0x4d }, ++ { CCI_REG8(0x93c7), 0x43 }, ++ { CCI_REG8(0x93c9), 0x2f }, ++ { CCI_REG8(0x974b), 0x02 }, ++ { CCI_REG8(0x995c), 0x8c }, ++ { CCI_REG8(0x995d), 0x00 }, ++ { CCI_REG8(0x995e), 0x00 }, ++ { CCI_REG8(0x9963), 0x64 }, ++ { CCI_REG8(0x9964), 0x50 }, ++ { CCI_REG8(0xaa0a), 0x26 }, ++ { CCI_REG8(0xae03), 0x04 }, ++ { CCI_REG8(0xae04), 0x03 }, ++ { CCI_REG8(0xae05), 0x03 }, ++ { CCI_REG8(0xbc1c), 0x08 }, ++ { CCI_REG8(0xbcf1), 0x02 }, ++}; ++ ++/* 16 mpix 10fps */ ++static const struct cci_reg_sequence mode_4656x3496_regs[] = { ++ { CCI_REG8(0x0111), 0x02 }, ++ { CCI_REG8(0x0112), 0x0a }, ++ { CCI_REG8(0x0113), 0x0a }, ++ { CCI_REG8(0x0114), 0x01 }, ++ { CCI_REG8(0x0342), 0x42 }, ++ { CCI_REG8(0x0343), 0x00 }, ++ { CCI_REG8(0x0340), 0x0d }, ++ { CCI_REG8(0x0341), 0xf4 }, ++ { CCI_REG8(0x0344), 0x00 }, ++ { CCI_REG8(0x0345), 0x00 }, ++ { CCI_REG8(0x0346), 0x00 }, ++ { CCI_REG8(0x0347), 0x00 }, ++ { CCI_REG8(0x0348), 0x12 }, ++ { CCI_REG8(0x0349), 0x2f }, ++ { CCI_REG8(0x034a), 0x0d }, ++ { CCI_REG8(0x034b), 0xa7 }, ++ { CCI_REG8(0x0220), 0x00 }, ++ { CCI_REG8(0x0221), 0x11 }, ++ { CCI_REG8(0x0222), 0x01 }, ++ { CCI_REG8(0x0900), 0x00 }, ++ { CCI_REG8(0x0901), 0x11 }, ++ { CCI_REG8(0x0902), 0x0a }, ++ { CCI_REG8(0x3f4c), 0x01 }, ++ { CCI_REG8(0x3f4d), 0x01 }, ++ { CCI_REG8(0x4254), 0x7f }, ++ { CCI_REG8(0x0401), 0x00 }, ++ { CCI_REG8(0x0404), 0x00 }, ++ { CCI_REG8(0x0405), 0x10 }, ++ { CCI_REG8(0x0408), 0x00 }, ++ { CCI_REG8(0x0409), 0x00 }, ++ { CCI_REG8(0x040a), 0x00 }, ++ { CCI_REG8(0x040b), 0x00 }, ++ { CCI_REG8(0x040c), 0x12 }, ++ { CCI_REG8(0x040d), 0x30 }, ++ { CCI_REG8(0x040e), 0x0d }, ++ { CCI_REG8(0x040f), 0xa8 }, ++ { CCI_REG8(0x034c), 0x12 }, ++ { CCI_REG8(0x034d), 0x30 }, ++ { CCI_REG8(0x034e), 0x0d }, ++ { CCI_REG8(0x034f), 0xa8 }, ++ { CCI_REG8(0x0301), 0x06 }, ++ { CCI_REG8(0x0303), 0x04 }, ++ { CCI_REG8(0x0305), 0x04 }, ++ { CCI_REG8(0x0306), 0x01 }, ++ { CCI_REG8(0x0307), 0x57 }, ++ { CCI_REG8(0x0309), 0x0a }, ++ { CCI_REG8(0x030b), 0x02 }, ++ { CCI_REG8(0x030d), 0x04 }, ++ { CCI_REG8(0x030e), 0x01 }, ++ { CCI_REG8(0x030f), 0x49 }, ++ { CCI_REG8(0x0310), 0x01 }, ++ { CCI_REG8(0x0820), 0x07 }, ++ { CCI_REG8(0x0821), 0xb6 }, ++ { CCI_REG8(0x0822), 0x00 }, ++ { CCI_REG8(0x0823), 0x00 }, ++ { CCI_REG8(0x3e20), 0x01 }, ++ { CCI_REG8(0x3e37), 0x00 }, ++ { CCI_REG8(0x3e3b), 0x00 }, ++ { CCI_REG8(0x0106), 0x00 }, ++ { CCI_REG8(0x0b00), 0x00 }, ++ { CCI_REG8(0x3230), 0x00 }, ++ { CCI_REG8(0x3f14), 0x01 }, ++ { CCI_REG8(0x3f3c), 0x01 }, ++ { CCI_REG8(0x3f0d), 0x0a }, ++ { CCI_REG8(0x3fbc), 0x00 }, ++ { CCI_REG8(0x3c06), 0x00 }, ++ { CCI_REG8(0x3c07), 0x48 }, ++ { CCI_REG8(0x3c0a), 0x00 }, ++ { CCI_REG8(0x3c0b), 0x00 }, ++ { CCI_REG8(0x3f78), 0x00 }, ++ { CCI_REG8(0x3f79), 0x40 }, ++ { CCI_REG8(0x3f7c), 0x00 }, ++ { CCI_REG8(0x3f7d), 0x00 }, ++}; ++ ++/* 4k 21fps mode */ ++static const struct cci_reg_sequence mode_3840x2160_regs[] = { ++ { CCI_REG8(0x0111), 0x02 }, ++ { CCI_REG8(0x0112), 0x0a }, ++ { CCI_REG8(0x0113), 0x0a }, ++ { CCI_REG8(0x0114), 0x01 }, ++ { CCI_REG8(0x0342), 0x38 }, ++ { CCI_REG8(0x0343), 0x70 }, ++ { CCI_REG8(0x0340), 0x08 }, ++ { CCI_REG8(0x0341), 0xd4 }, ++ { CCI_REG8(0x0344), 0x01 }, ++ { CCI_REG8(0x0345), 0x98 }, ++ { CCI_REG8(0x0346), 0x02 }, ++ { CCI_REG8(0x0347), 0xa0 }, ++ { CCI_REG8(0x0348), 0x10 }, ++ { CCI_REG8(0x0349), 0x97 }, ++ { CCI_REG8(0x034a), 0x0b }, ++ { CCI_REG8(0x034b), 0x17 }, ++ { CCI_REG8(0x0220), 0x00 }, ++ { CCI_REG8(0x0221), 0x11 }, ++ { CCI_REG8(0x0222), 0x01 }, ++ { CCI_REG8(0x0900), 0x00 }, ++ { CCI_REG8(0x0901), 0x11 }, ++ { CCI_REG8(0x0902), 0x0a }, ++ { CCI_REG8(0x3f4c), 0x01 }, ++ { CCI_REG8(0x3f4d), 0x01 }, ++ { CCI_REG8(0x4254), 0x7f }, ++ { CCI_REG8(0x0401), 0x00 }, ++ { CCI_REG8(0x0404), 0x00 }, ++ { CCI_REG8(0x0405), 0x10 }, ++ { CCI_REG8(0x0408), 0x00 }, ++ { CCI_REG8(0x0409), 0x00 }, ++ { CCI_REG8(0x040a), 0x00 }, ++ { CCI_REG8(0x040b), 0x00 }, ++ { CCI_REG8(0x040c), 0x0f }, ++ { CCI_REG8(0x040d), 0x00 }, ++ { CCI_REG8(0x040e), 0x08 }, ++ { CCI_REG8(0x040f), 0x70 }, ++ { CCI_REG8(0x034c), 0x0f }, ++ { CCI_REG8(0x034d), 0x00 }, ++ { CCI_REG8(0x034e), 0x08 }, ++ { CCI_REG8(0x034f), 0x70 }, ++ { CCI_REG8(0x0301), 0x06 }, ++ { CCI_REG8(0x0303), 0x04 }, ++ { CCI_REG8(0x0305), 0x04 }, ++ { CCI_REG8(0x0306), 0x01 }, ++ { CCI_REG8(0x0307), 0x57 }, ++ { CCI_REG8(0x0309), 0x0a }, ++ { CCI_REG8(0x030b), 0x02 }, ++ { CCI_REG8(0x030d), 0x04 }, ++ { CCI_REG8(0x030e), 0x01 }, ++ { CCI_REG8(0x030f), 0x49 }, ++ { CCI_REG8(0x0310), 0x01 }, ++ { CCI_REG8(0x0820), 0x07 }, ++ { CCI_REG8(0x0821), 0xb6 }, ++ { CCI_REG8(0x0822), 0x00 }, ++ { CCI_REG8(0x0823), 0x00 }, ++ { CCI_REG8(0x3e20), 0x01 }, ++ { CCI_REG8(0x3e37), 0x00 }, ++ { CCI_REG8(0x3e3b), 0x00 }, ++ { CCI_REG8(0x0106), 0x00 }, ++ { CCI_REG8(0x0b00), 0x00 }, ++ { CCI_REG8(0x3230), 0x00 }, ++ { CCI_REG8(0x3f14), 0x01 }, ++ { CCI_REG8(0x3f3c), 0x01 }, ++ { CCI_REG8(0x3f0d), 0x0a }, ++ { CCI_REG8(0x3fbc), 0x00 }, ++ { CCI_REG8(0x3c06), 0x00 }, ++ { CCI_REG8(0x3c07), 0x48 }, ++ { CCI_REG8(0x3c0a), 0x00 }, ++ { CCI_REG8(0x3c0b), 0x00 }, ++ { CCI_REG8(0x3f78), 0x00 }, ++ { CCI_REG8(0x3f79), 0x40 }, ++ { CCI_REG8(0x3f7c), 0x00 }, ++ { CCI_REG8(0x3f7d), 0x00 }, ++}; ++ ++/* 2x2 binned 30fps mode */ ++static const struct cci_reg_sequence mode_2328x1748_regs[] = { ++ { CCI_REG8(0x0111), 0x02 }, ++ { CCI_REG8(0x0112), 0x0a }, ++ { CCI_REG8(0x0113), 0x0a }, ++ { CCI_REG8(0x0114), 0x01 }, ++ { CCI_REG8(0x0342), 0x24 }, ++ { CCI_REG8(0x0343), 0x12 }, ++ { CCI_REG8(0x0340), 0x09 }, ++ { CCI_REG8(0x0341), 0xac }, ++ { CCI_REG8(0x0344), 0x00 }, ++ { CCI_REG8(0x0345), 0x00 }, ++ { CCI_REG8(0x0346), 0x00 }, ++ { CCI_REG8(0x0347), 0x00 }, ++ { CCI_REG8(0x0348), 0x12 }, ++ { CCI_REG8(0x0349), 0x2f }, ++ { CCI_REG8(0x034a), 0x0d }, ++ { CCI_REG8(0x034b), 0xa7 }, ++ { CCI_REG8(0x0220), 0x00 }, ++ { CCI_REG8(0x0221), 0x11 }, ++ { CCI_REG8(0x0222), 0x01 }, ++ { CCI_REG8(0x0900), 0x01 }, ++ { CCI_REG8(0x0901), 0x22 }, ++ { CCI_REG8(0x0902), 0x0a }, ++ { CCI_REG8(0x3f4c), 0x01 }, ++ { CCI_REG8(0x3f4d), 0x01 }, ++ { CCI_REG8(0x4254), 0x7f }, ++ { CCI_REG8(0x0401), 0x00 }, ++ { CCI_REG8(0x0404), 0x00 }, ++ { CCI_REG8(0x0405), 0x10 }, ++ { CCI_REG8(0x0408), 0x00 }, ++ { CCI_REG8(0x0409), 0x00 }, ++ { CCI_REG8(0x040a), 0x00 }, ++ { CCI_REG8(0x040b), 0x00 }, ++ { CCI_REG8(0x040c), 0x09 }, ++ { CCI_REG8(0x040d), 0x18 }, ++ { CCI_REG8(0x040e), 0x06 }, ++ { CCI_REG8(0x040f), 0xd4 }, ++ { CCI_REG8(0x034c), 0x09 }, ++ { CCI_REG8(0x034d), 0x18 }, ++ { CCI_REG8(0x034e), 0x06 }, ++ { CCI_REG8(0x034f), 0xd4 }, ++ { CCI_REG8(0x0301), 0x06 }, ++ { CCI_REG8(0x0303), 0x04 }, ++ { CCI_REG8(0x0305), 0x04 }, ++ { CCI_REG8(0x0306), 0x01 }, ++ { CCI_REG8(0x0307), 0x57 }, ++ { CCI_REG8(0x0309), 0x0a }, ++ { CCI_REG8(0x030b), 0x02 }, ++ { CCI_REG8(0x030d), 0x04 }, ++ { CCI_REG8(0x030e), 0x01 }, ++ { CCI_REG8(0x030f), 0x49 }, ++ { CCI_REG8(0x0310), 0x01 }, ++ { CCI_REG8(0x0820), 0x07 }, ++ { CCI_REG8(0x0821), 0xb6 }, ++ { CCI_REG8(0x0822), 0x00 }, ++ { CCI_REG8(0x0823), 0x00 }, ++ { CCI_REG8(0x3e20), 0x01 }, ++ { CCI_REG8(0x3e37), 0x00 }, ++ { CCI_REG8(0x3e3b), 0x00 }, ++ { CCI_REG8(0x0106), 0x00 }, ++ { CCI_REG8(0x0b00), 0x00 }, ++ { CCI_REG8(0x3230), 0x00 }, ++ { CCI_REG8(0x3f14), 0x01 }, ++ { CCI_REG8(0x3f3c), 0x01 }, ++ { CCI_REG8(0x3f0d), 0x0a }, ++ { CCI_REG8(0x3fbc), 0x00 }, ++ { CCI_REG8(0x3c06), 0x00 }, ++ { CCI_REG8(0x3c07), 0x48 }, ++ { CCI_REG8(0x3c0a), 0x00 }, ++ { CCI_REG8(0x3c0b), 0x00 }, ++ { CCI_REG8(0x3f78), 0x00 }, ++ { CCI_REG8(0x3f79), 0x40 }, ++ { CCI_REG8(0x3f7c), 0x00 }, ++ { CCI_REG8(0x3f7d), 0x00 }, ++}; ++ ++/* 1080p 60fps mode */ ++static const struct cci_reg_sequence mode_1920x1080_regs[] = { ++ { CCI_REG8(0x0111), 0x02 }, ++ { CCI_REG8(0x0112), 0x0a }, ++ { CCI_REG8(0x0113), 0x0a }, ++ { CCI_REG8(0x0114), 0x01 }, ++ { CCI_REG8(0x0342), 0x25 }, ++ { CCI_REG8(0x0343), 0xd9 }, ++ { CCI_REG8(0x0340), 0x04 }, ++ { CCI_REG8(0x0341), 0x9c }, ++ { CCI_REG8(0x0344), 0x01 }, ++ { CCI_REG8(0x0345), 0x98 }, ++ { CCI_REG8(0x0346), 0x02 }, ++ { CCI_REG8(0x0347), 0xa2 }, ++ { CCI_REG8(0x0348), 0x10 }, ++ { CCI_REG8(0x0349), 0x97 }, ++ { CCI_REG8(0x034a), 0x0b }, ++ { CCI_REG8(0x034b), 0x15 }, ++ { CCI_REG8(0x0220), 0x00 }, ++ { CCI_REG8(0x0221), 0x11 }, ++ { CCI_REG8(0x0222), 0x01 }, ++ { CCI_REG8(0x0900), 0x01 }, ++ { CCI_REG8(0x0901), 0x22 }, ++ { CCI_REG8(0x0902), 0x0a }, ++ { CCI_REG8(0x3f4c), 0x01 }, ++ { CCI_REG8(0x3f4d), 0x01 }, ++ { CCI_REG8(0x4254), 0x7f }, ++ { CCI_REG8(0x0401), 0x00 }, ++ { CCI_REG8(0x0404), 0x00 }, ++ { CCI_REG8(0x0405), 0x10 }, ++ { CCI_REG8(0x0408), 0x00 }, ++ { CCI_REG8(0x0409), 0x00 }, ++ { CCI_REG8(0x040a), 0x00 }, ++ { CCI_REG8(0x040b), 0x00 }, ++ { CCI_REG8(0x040c), 0x07 }, ++ { CCI_REG8(0x040d), 0x80 }, ++ { CCI_REG8(0x040e), 0x04 }, ++ { CCI_REG8(0x040f), 0x38 }, ++ { CCI_REG8(0x034c), 0x07 }, ++ { CCI_REG8(0x034d), 0x80 }, ++ { CCI_REG8(0x034e), 0x04 }, ++ { CCI_REG8(0x034f), 0x38 }, ++ { CCI_REG8(0x0301), 0x06 }, ++ { CCI_REG8(0x0303), 0x04 }, ++ { CCI_REG8(0x0305), 0x04 }, ++ { CCI_REG8(0x0306), 0x01 }, ++ { CCI_REG8(0x0307), 0x57 }, ++ { CCI_REG8(0x0309), 0x0a }, ++ { CCI_REG8(0x030b), 0x02 }, ++ { CCI_REG8(0x030d), 0x04 }, ++ { CCI_REG8(0x030e), 0x01 }, ++ { CCI_REG8(0x030f), 0x49 }, ++ { CCI_REG8(0x0310), 0x01 }, ++ { CCI_REG8(0x0820), 0x07 }, ++ { CCI_REG8(0x0821), 0xb6 }, ++ { CCI_REG8(0x0822), 0x00 }, ++ { CCI_REG8(0x0823), 0x00 }, ++ { CCI_REG8(0x3e20), 0x01 }, ++ { CCI_REG8(0x3e37), 0x00 }, ++ { CCI_REG8(0x3e3b), 0x00 }, ++ { CCI_REG8(0x0106), 0x00 }, ++ { CCI_REG8(0x0b00), 0x00 }, ++ { CCI_REG8(0x3230), 0x00 }, ++ { CCI_REG8(0x3f14), 0x01 }, ++ { CCI_REG8(0x3f3c), 0x01 }, ++ { CCI_REG8(0x3f0d), 0x0a }, ++ { CCI_REG8(0x3fbc), 0x00 }, ++ { CCI_REG8(0x3c06), 0x00 }, ++ { CCI_REG8(0x3c07), 0x48 }, ++ { CCI_REG8(0x3c0a), 0x00 }, ++ { CCI_REG8(0x3c0b), 0x00 }, ++ { CCI_REG8(0x3f78), 0x00 }, ++ { CCI_REG8(0x3f79), 0x40 }, ++ { CCI_REG8(0x3f7c), 0x00 }, ++ { CCI_REG8(0x3f7d), 0x00 }, ++}; ++ ++/* 720p 120fps mode */ ++static const struct cci_reg_sequence mode_1280x720_regs[] = { ++ { CCI_REG8(0x0111), 0x02 }, ++ { CCI_REG8(0x0112), 0x0a }, ++ { CCI_REG8(0x0113), 0x0a }, ++ { CCI_REG8(0x0114), 0x01 }, ++ { CCI_REG8(0x0342), 0x1b }, ++ { CCI_REG8(0x0343), 0x3b }, ++ { CCI_REG8(0x0340), 0x03 }, ++ { CCI_REG8(0x0341), 0x34 }, ++ { CCI_REG8(0x0344), 0x04 }, ++ { CCI_REG8(0x0345), 0x18 }, ++ { CCI_REG8(0x0346), 0x04 }, ++ { CCI_REG8(0x0347), 0x12 }, ++ { CCI_REG8(0x0348), 0x0e }, ++ { CCI_REG8(0x0349), 0x17 }, ++ { CCI_REG8(0x034a), 0x09 }, ++ { CCI_REG8(0x034b), 0xb6 }, ++ { CCI_REG8(0x0220), 0x00 }, ++ { CCI_REG8(0x0221), 0x11 }, ++ { CCI_REG8(0x0222), 0x01 }, ++ { CCI_REG8(0x0900), 0x01 }, ++ { CCI_REG8(0x0901), 0x22 }, ++ { CCI_REG8(0x0902), 0x0a }, ++ { CCI_REG8(0x3f4c), 0x01 }, ++ { CCI_REG8(0x3f4d), 0x01 }, ++ { CCI_REG8(0x4254), 0x7f }, ++ { CCI_REG8(0x0401), 0x00 }, ++ { CCI_REG8(0x0404), 0x00 }, ++ { CCI_REG8(0x0405), 0x10 }, ++ { CCI_REG8(0x0408), 0x00 }, ++ { CCI_REG8(0x0409), 0x00 }, ++ { CCI_REG8(0x040a), 0x00 }, ++ { CCI_REG8(0x040b), 0x00 }, ++ { CCI_REG8(0x040c), 0x05 }, ++ { CCI_REG8(0x040d), 0x00 }, ++ { CCI_REG8(0x040e), 0x02 }, ++ { CCI_REG8(0x040f), 0xd0 }, ++ { CCI_REG8(0x034c), 0x05 }, ++ { CCI_REG8(0x034d), 0x00 }, ++ { CCI_REG8(0x034e), 0x02 }, ++ { CCI_REG8(0x034f), 0xd0 }, ++ { CCI_REG8(0x0301), 0x06 }, ++ { CCI_REG8(0x0303), 0x04 }, ++ { CCI_REG8(0x0305), 0x04 }, ++ { CCI_REG8(0x0306), 0x01 }, ++ { CCI_REG8(0x0307), 0x57 }, ++ { CCI_REG8(0x0309), 0x0a }, ++ { CCI_REG8(0x030b), 0x02 }, ++ { CCI_REG8(0x030d), 0x04 }, ++ { CCI_REG8(0x030e), 0x01 }, ++ { CCI_REG8(0x030f), 0x49 }, ++ { CCI_REG8(0x0310), 0x01 }, ++ { CCI_REG8(0x0820), 0x07 }, ++ { CCI_REG8(0x0821), 0xb6 }, ++ { CCI_REG8(0x0822), 0x00 }, ++ { CCI_REG8(0x0823), 0x00 }, ++ { CCI_REG8(0x3e20), 0x01 }, ++ { CCI_REG8(0x3e37), 0x00 }, ++ { CCI_REG8(0x3e3b), 0x00 }, ++ { CCI_REG8(0x0106), 0x00 }, ++ { CCI_REG8(0x0b00), 0x00 }, ++ { CCI_REG8(0x3230), 0x00 }, ++ { CCI_REG8(0x3f14), 0x01 }, ++ { CCI_REG8(0x3f3c), 0x01 }, ++ { CCI_REG8(0x3f0d), 0x0a }, ++ { CCI_REG8(0x3fbc), 0x00 }, ++ { CCI_REG8(0x3c06), 0x00 }, ++ { CCI_REG8(0x3c07), 0x48 }, ++ { CCI_REG8(0x3c0a), 0x00 }, ++ { CCI_REG8(0x3c0b), 0x00 }, ++ { CCI_REG8(0x3f78), 0x00 }, ++ { CCI_REG8(0x3f79), 0x40 }, ++ { CCI_REG8(0x3f7c), 0x00 }, ++ { CCI_REG8(0x3f7d), 0x00 }, ++}; ++ ++/* Mode configs */ ++static const struct imx519_mode supported_modes_10bit[] = { ++ { ++ .width = 4656, ++ .height = 3496, ++ .line_length_pix = 0x4200, ++ .crop = { ++ .left = IMX519_PIXEL_ARRAY_LEFT, ++ .top = IMX519_PIXEL_ARRAY_TOP, ++ .width = 4656, ++ .height = 3496, ++ }, ++ .timeperframe_min = { ++ .numerator = 100, ++ .denominator = 1000 ++ }, ++ .timeperframe_default = { ++ .numerator = 100, ++ .denominator = 1000 ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_4656x3496_regs), ++ .regs = mode_4656x3496_regs, ++ } ++ }, ++ { ++ .width = 3840, ++ .height = 2160, ++ .line_length_pix = 0x3870, ++ .crop = { ++ .left = IMX519_PIXEL_ARRAY_LEFT + 408, ++ .top = IMX519_PIXEL_ARRAY_TOP + 672, ++ .width = 3840, ++ .height = 2160, ++ }, ++ .timeperframe_min = { ++ .numerator = 100, ++ .denominator = 2100 ++ }, ++ .timeperframe_default = { ++ .numerator = 100, ++ .denominator = 2100 ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_3840x2160_regs), ++ .regs = mode_3840x2160_regs, ++ } ++ }, ++ { ++ .width = 2328, ++ .height = 1748, ++ .line_length_pix = 0x2412, ++ .crop = { ++ .left = IMX519_PIXEL_ARRAY_LEFT, ++ .top = IMX519_PIXEL_ARRAY_TOP, ++ .width = 4656, ++ .height = 3496, ++ }, ++ .timeperframe_min = { ++ .numerator = 100, ++ .denominator = 3000 ++ }, ++ .timeperframe_default = { ++ .numerator = 100, ++ .denominator = 3000 ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_2328x1748_regs), ++ .regs = mode_2328x1748_regs, ++ } ++ }, ++ { ++ .width = 1920, ++ .height = 1080, ++ .line_length_pix = 0x25D9, ++ .crop = { ++ .left = IMX519_PIXEL_ARRAY_LEFT + 408, ++ .top = IMX519_PIXEL_ARRAY_TOP + 674, ++ .width = 3840, ++ .height = 2160, ++ }, ++ .timeperframe_min = { ++ .numerator = 100, ++ .denominator = 6000 ++ }, ++ .timeperframe_default = { ++ .numerator = 100, ++ .denominator = 6000 ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_1920x1080_regs), ++ .regs = mode_1920x1080_regs, ++ } ++ }, ++ { ++ .width = 1280, ++ .height = 720, ++ .line_length_pix = 0x1B3B, ++ .crop = { ++ .left = IMX519_PIXEL_ARRAY_LEFT + 1048, ++ .top = IMX519_PIXEL_ARRAY_TOP + 1042, ++ .width = 2560, ++ .height = 1440, ++ }, ++ .timeperframe_min = { ++ .numerator = 100, ++ .denominator = 12000 ++ }, ++ .timeperframe_default = { ++ .numerator = 100, ++ .denominator = 12000 ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), ++ .regs = mode_1280x720_regs, ++ } ++ } ++}; ++ ++/* ++ * The supported formats. ++ * This table MUST contain 4 entries per format, to cover the various flip ++ * combinations in the order ++ * - no flip ++ * - h flip ++ * - v flip ++ * - h&v flips ++ */ ++static const u32 imx519_mbus_formats[] = { ++ /* 10-bit modes. */ ++ MEDIA_BUS_FMT_SRGGB10_1X10, ++ MEDIA_BUS_FMT_SGRBG10_1X10, ++ MEDIA_BUS_FMT_SGBRG10_1X10, ++ MEDIA_BUS_FMT_SBGGR10_1X10, ++}; ++ ++static const char * const imx519_test_pattern_menu[] = { ++ "Disabled", ++ "Color Bars", ++ "Solid Color", ++ "Grey Color Bars", ++ "PN9" ++}; ++ ++static const int imx519_test_pattern_val[] = { ++ IMX519_TEST_PATTERN_DISABLE, ++ IMX519_TEST_PATTERN_COLOR_BARS, ++ IMX519_TEST_PATTERN_SOLID_COLOR, ++ IMX519_TEST_PATTERN_GREY_COLOR, ++ IMX519_TEST_PATTERN_PN9, ++}; ++ ++/* regulator supplies */ ++static const char * const imx519_supply_name[] = { ++ /* Supplies can be enabled in any order */ ++ "vana", /* Analog (2.8V) supply */ ++ "vdig", /* Digital Core (1.05V) supply */ ++ "vddl", /* IF (1.8V) supply */ ++}; ++ ++/* ++ * Initialisation delay between XCLR low->high and the moment when the sensor ++ * can start capture (i.e. can leave software standby), given by T7 in the ++ * datasheet is 8ms. This does include I2C setup time as well. ++ * ++ * Note, that delay between XCLR low->high and reading the CCI ID register (T6 ++ * in the datasheet) is much smaller - 600us. ++ */ ++#define IMX519_XCLR_MIN_DELAY_US 8000 ++#define IMX519_XCLR_DELAY_RANGE_US 1000 ++ ++struct imx519 { ++ struct v4l2_subdev sd; ++ struct media_pad pad; ++ ++ struct regmap *regmap; ++ struct clk *xclk; ++ ++ struct gpio_desc *reset_gpio; ++ struct regulator_bulk_data supplies[ARRAY_SIZE(imx519_supply_name)]; ++ ++ struct v4l2_ctrl_handler ctrl_handler; ++ /* V4L2 Controls */ ++ struct v4l2_ctrl *link_freq; ++ struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *vflip; ++ struct v4l2_ctrl *hflip; ++ struct v4l2_ctrl *vblank; ++ struct v4l2_ctrl *hblank; ++ ++ /* Current mode */ ++ const struct imx519_mode *mode; ++ ++ /* Rewrite common registers on stream on? */ ++ bool common_regs_written; ++ ++ /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */ ++ unsigned int long_exp_shift; ++}; ++ ++static inline struct imx519 *to_imx519(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct imx519, sd); ++} ++ ++/* Get bayer order based on flip setting. */ ++static u32 imx519_get_format_code(struct imx519 *imx519) ++{ ++ unsigned int i; ++ ++ i = (imx519->vflip->val ? 2 : 0) | ++ (imx519->hflip->val ? 1 : 0); ++ ++ return imx519_mbus_formats[i]; ++} ++ ++static void imx519_adjust_exposure_range(struct imx519 *imx519) ++{ ++ int exposure_max, exposure_def; ++ ++ /* Honour the VBLANK limits when setting exposure. */ ++ exposure_max = imx519->mode->height + imx519->vblank->val - ++ IMX519_EXPOSURE_OFFSET; ++ exposure_def = min(exposure_max, imx519->exposure->val); ++ __v4l2_ctrl_modify_range(imx519->exposure, imx519->exposure->minimum, ++ exposure_max, imx519->exposure->step, ++ exposure_def); ++} ++ ++static int imx519_set_frame_length(struct imx519 *imx519, unsigned int val) ++{ ++ int ret = 0; ++ ++ imx519->long_exp_shift = 0; ++ ++ while (val > IMX519_FRAME_LENGTH_MAX) { ++ imx519->long_exp_shift++; ++ val >>= 1; ++ } ++ ++ cci_write(imx519->regmap, IMX519_REG_FRAME_LENGTH, val, &ret); ++ if (ret) ++ return ret; ++ ++ cci_write(imx519->regmap, IMX519_LONG_EXP_SHIFT_REG, ++ imx519->long_exp_shift, &ret); ++ ++ return ret; ++} ++ ++static int imx519_set_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct imx519 *imx519 = ++ container_of(ctrl->handler, struct imx519, ctrl_handler); ++ struct i2c_client *client = v4l2_get_subdevdata(&imx519->sd); ++ int ret = 0; ++ ++ /* ++ * The VBLANK control may change the limits of usable exposure, so check ++ * and adjust if necessary. ++ */ ++ if (ctrl->id == V4L2_CID_VBLANK) ++ imx519_adjust_exposure_range(imx519); ++ ++ /* ++ * Applying V4L2 control value only happens ++ * when power is up for streaming ++ */ ++ if (pm_runtime_get_if_in_use(&client->dev) == 0) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_ANALOGUE_GAIN: ++ cci_write(imx519->regmap, IMX519_REG_ANALOG_GAIN, ++ ctrl->val, &ret); ++ break; ++ case V4L2_CID_EXPOSURE: ++ cci_write(imx519->regmap, IMX519_REG_EXPOSURE, ++ ctrl->val >> imx519->long_exp_shift, &ret); ++ break; ++ case V4L2_CID_DIGITAL_GAIN: ++ cci_write(imx519->regmap, IMX519_REG_DIGITAL_GAIN, ++ ctrl->val, &ret); ++ break; ++ case V4L2_CID_TEST_PATTERN: ++ cci_write(imx519->regmap, IMX519_REG_TEST_PATTERN, ++ imx519_test_pattern_val[ctrl->val], &ret); ++ break; ++ case V4L2_CID_TEST_PATTERN_RED: ++ cci_write(imx519->regmap, IMX519_REG_TEST_PATTERN_R, ++ ctrl->val, &ret); ++ break; ++ case V4L2_CID_TEST_PATTERN_GREENR: ++ cci_write(imx519->regmap, IMX519_REG_TEST_PATTERN_GR, ++ ctrl->val, &ret); ++ break; ++ case V4L2_CID_TEST_PATTERN_BLUE: ++ cci_write(imx519->regmap, IMX519_REG_TEST_PATTERN_B, ++ ctrl->val, &ret); ++ break; ++ case V4L2_CID_TEST_PATTERN_GREENB: ++ cci_write(imx519->regmap, IMX519_REG_TEST_PATTERN_GB, ++ ctrl->val, &ret); ++ break; ++ case V4L2_CID_HFLIP: ++ case V4L2_CID_VFLIP: ++ cci_write(imx519->regmap, IMX519_REG_ORIENTATION, ++ imx519->hflip->val | imx519->vflip->val << 1, &ret); ++ break; ++ case V4L2_CID_VBLANK: ++ ret = imx519_set_frame_length(imx519, ++ imx519->mode->height + ctrl->val); ++ break; ++ default: ++ dev_info(&client->dev, ++ "ctrl(id:0x%x,val:0x%x) is not handled\n", ++ ctrl->id, ctrl->val); ++ ret = -EINVAL; ++ break; ++ } ++ ++ pm_runtime_mark_last_busy(&client->dev); ++ pm_runtime_put_autosuspend(&client->dev); ++ ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops imx519_ctrl_ops = { ++ .s_ctrl = imx519_set_ctrl, ++}; ++ ++static int imx519_init_cfg(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state) ++{ ++ struct imx519 *imx519 = to_imx519(sd); ++ struct v4l2_mbus_framefmt *format; ++ struct v4l2_rect *crop; ++ ++ /* Initialize try_fmt. */ ++ format = v4l2_subdev_get_pad_format(sd, state, 0); ++ format->width = supported_modes_10bit[0].width; ++ format->height = supported_modes_10bit[0].height; ++ format->code = imx519_get_format_code(imx519); ++ format->field = V4L2_FIELD_NONE; ++ format->colorspace = V4L2_COLORSPACE_RAW; ++ format->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(format->colorspace); ++ format->quantization = V4L2_QUANTIZATION_FULL_RANGE; ++ format->xfer_func = V4L2_XFER_FUNC_NONE; ++ ++ /* Initialize crop rectangle. */ ++ crop = v4l2_subdev_get_pad_crop(sd, state, 0); ++ crop->top = IMX519_PIXEL_ARRAY_TOP; ++ crop->left = IMX519_PIXEL_ARRAY_LEFT; ++ crop->width = IMX519_PIXEL_ARRAY_WIDTH; ++ crop->height = IMX519_PIXEL_ARRAY_HEIGHT; ++ ++ return 0; ++} ++ ++static int imx519_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ struct imx519 *imx519 = to_imx519(sd); ++ ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = imx519_get_format_code(imx519); ++ ++ return 0; ++} ++ ++static int imx519_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ struct imx519 *imx519 = to_imx519(sd); ++ ++ if (fse->index >= ARRAY_SIZE(supported_modes_10bit)) ++ return -EINVAL; ++ ++ if (fse->code != imx519_get_format_code(imx519)) ++ return -EINVAL; ++ ++ fse->min_width = supported_modes_10bit[fse->index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = supported_modes_10bit[fse->index].height; ++ fse->max_height = fse->min_height; ++ ++ return 0; ++} ++ ++static void imx519_update_image_pad_format(struct imx519 *imx519, ++ const struct imx519_mode *mode, ++ struct v4l2_subdev_format *fmt) ++{ ++ fmt->format.width = mode->width; ++ fmt->format.height = mode->height; ++ fmt->format.field = V4L2_FIELD_NONE; ++ fmt->format.colorspace = V4L2_COLORSPACE_RAW; ++ fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; ++ fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_601; ++ fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE; ++} ++ ++static ++unsigned int imx519_get_frame_length(const struct imx519_mode *mode, ++ const struct v4l2_fract *timeperframe) ++{ ++ u64 frame_length; ++ ++ frame_length = (u64)timeperframe->numerator * IMX519_PIXEL_RATE; ++ do_div(frame_length, ++ (u64)timeperframe->denominator * mode->line_length_pix); ++ ++ if (WARN_ON(frame_length > IMX519_FRAME_LENGTH_MAX)) ++ frame_length = IMX519_FRAME_LENGTH_MAX; ++ ++ return max_t(unsigned int, frame_length, mode->height); ++} ++ ++static void imx519_set_framing_limits(struct imx519 *imx519) ++{ ++ unsigned int frm_length_min, frm_length_default, hblank; ++ const struct imx519_mode *mode = imx519->mode; ++ ++ frm_length_min = imx519_get_frame_length(mode, &mode->timeperframe_min); ++ frm_length_default = ++ imx519_get_frame_length(mode, &mode->timeperframe_default); ++ ++ /* Default to no long exposure multiplier. */ ++ imx519->long_exp_shift = 0; ++ ++ /* Update limits and set FPS to default */ ++ __v4l2_ctrl_modify_range(imx519->vblank, frm_length_min - mode->height, ++ ((1 << IMX519_LONG_EXP_SHIFT_MAX) * ++ IMX519_FRAME_LENGTH_MAX) - mode->height, ++ 1, frm_length_default - mode->height); ++ ++ /* Setting this will adjust the exposure limits as well. */ ++ __v4l2_ctrl_s_ctrl(imx519->vblank, frm_length_default - mode->height); ++ ++ /* ++ * Currently PPL is fixed to the mode specified value, so hblank ++ * depends on mode->width only, and is not changeable in any ++ * way other than changing the mode. ++ */ ++ hblank = mode->line_length_pix - mode->width; ++ __v4l2_ctrl_modify_range(imx519->hblank, hblank, hblank, 1, hblank); ++} ++ ++static int imx519_set_pad_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct v4l2_mbus_framefmt *format; ++ const struct imx519_mode *mode; ++ struct imx519 *imx519 = to_imx519(sd); ++ ++ /* Bayer order varies with flips */ ++ fmt->format.code = imx519_get_format_code(imx519); ++ ++ mode = v4l2_find_nearest_size(supported_modes_10bit, ++ ARRAY_SIZE(supported_modes_10bit), ++ width, height, ++ fmt->format.width, ++ fmt->format.height); ++ imx519_update_image_pad_format(imx519, mode, fmt); ++ format = v4l2_subdev_get_pad_format(sd, sd_state, 0); ++ if (imx519->mode == mode && format->code == fmt->format.code) ++ return 0; ++ ++ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { ++ imx519->mode = mode; ++ imx519_set_framing_limits(imx519); ++ } ++ ++ *format = fmt->format; ++ ++ return 0; ++} ++ ++static int imx519_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_selection *sel) ++{ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP: { ++ sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0); ++ return 0; ++ } ++ ++ case V4L2_SEL_TGT_NATIVE_SIZE: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = IMX519_NATIVE_WIDTH; ++ sel->r.height = IMX519_NATIVE_HEIGHT; ++ ++ return 0; ++ ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = IMX519_PIXEL_ARRAY_LEFT; ++ sel->r.top = IMX519_PIXEL_ARRAY_TOP; ++ sel->r.width = IMX519_PIXEL_ARRAY_WIDTH; ++ sel->r.height = IMX519_PIXEL_ARRAY_HEIGHT; ++ ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++/* Start streaming */ ++static int imx519_start_streaming(struct imx519 *imx519, ++ struct v4l2_subdev_state *state) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx519->sd); ++ const struct imx519_reg_list *reg_list; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(&client->dev); ++ if (ret < 0) ++ return ret; ++ ++ if (!imx519->common_regs_written) { ++ ret = cci_multi_reg_write(imx519->regmap, mode_common_regs, ++ ARRAY_SIZE(mode_common_regs), NULL); ++ ++ if (ret) { ++ dev_err(&client->dev, "%s failed to set common settings\n", ++ __func__); ++ goto err_rpm_put; ++ } ++ imx519->common_regs_written = true; ++ } ++ ++ /* Apply default values of current mode */ ++ reg_list = &imx519->mode->reg_list; ++ ret = cci_multi_reg_write(imx519->regmap, reg_list->regs, ++ reg_list->num_of_regs, NULL); ++ if (ret) { ++ dev_err(&client->dev, "%s failed to set mode\n", __func__); ++ goto err_rpm_put; ++ } ++ ++ /* Apply customized values from user */ ++ ret = __v4l2_ctrl_handler_setup(imx519->sd.ctrl_handler); ++ if (ret) ++ goto err_rpm_put; ++ ++ /* set stream on register */ ++ ret = cci_write(imx519->regmap, IMX519_REG_MODE_SELECT, ++ IMX519_MODE_STREAMING, NULL); ++ if (ret) ++ goto err_rpm_put; ++ ++ /* vflip and hflip cannot change during streaming */ ++ __v4l2_ctrl_grab(imx519->vflip, true); ++ __v4l2_ctrl_grab(imx519->hflip, true); ++ ++ return 0; ++ ++err_rpm_put: ++ pm_runtime_mark_last_busy(&client->dev); ++ pm_runtime_put_autosuspend(&client->dev); ++ ++ return ret; ++} ++ ++/* Stop streaming */ ++static void imx519_stop_streaming(struct imx519 *imx519) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx519->sd); ++ int ret; ++ ++ /* set stream off register */ ++ ret = cci_write(imx519->regmap, IMX519_REG_MODE_SELECT, ++ IMX519_MODE_STANDBY, NULL); ++ if (ret) ++ dev_err(&client->dev, "%s failed to set stream\n", __func__); ++ ++ __v4l2_ctrl_grab(imx519->vflip, false); ++ __v4l2_ctrl_grab(imx519->hflip, false); ++ ++ pm_runtime_mark_last_busy(&client->dev); ++ pm_runtime_put_autosuspend(&client->dev); ++} ++ ++static int imx519_set_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct imx519 *imx519 = to_imx519(sd); ++ struct v4l2_subdev_state *state; ++ int ret = 0; ++ ++ state = v4l2_subdev_lock_and_get_active_state(sd); ++ ++ if (enable) ++ ret = imx519_start_streaming(imx519, state); ++ else ++ imx519_stop_streaming(imx519); ++ ++ v4l2_subdev_unlock_state(state); ++ ++ return ret; ++} ++ ++static const struct v4l2_subdev_core_ops imx519_core_ops = { ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static const struct v4l2_subdev_video_ops imx519_video_ops = { ++ .s_stream = imx519_set_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops imx519_pad_ops = { ++ .init_cfg = imx519_init_cfg, ++ .enum_mbus_code = imx519_enum_mbus_code, ++ .get_fmt = v4l2_subdev_get_fmt, ++ .set_fmt = imx519_set_pad_format, ++ .get_selection = imx519_get_selection, ++ .enum_frame_size = imx519_enum_frame_size, ++}; ++ ++static const struct v4l2_subdev_ops imx519_subdev_ops = { ++ .core = &imx519_core_ops, ++ .video = &imx519_video_ops, ++ .pad = &imx519_pad_ops, ++}; ++ ++static const struct media_entity_operations imx519_subdev_entity_ops = { ++ .link_validate = v4l2_subdev_link_validate, ++}; ++ ++/* Power/clock management functions */ ++static int imx519_power_on(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx519 *imx519 = to_imx519(sd); ++ int ret; ++ ++ ret = regulator_bulk_enable(ARRAY_SIZE(imx519_supply_name), ++ imx519->supplies); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to enable regulators\n", ++ __func__); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(imx519->xclk); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to enable clock\n", ++ __func__); ++ goto reg_off; ++ } ++ ++ gpiod_set_value_cansleep(imx519->reset_gpio, 1); ++ usleep_range(IMX519_XCLR_MIN_DELAY_US, ++ IMX519_XCLR_MIN_DELAY_US + IMX519_XCLR_DELAY_RANGE_US); ++ ++ return 0; ++ ++reg_off: ++ regulator_bulk_disable(ARRAY_SIZE(imx519_supply_name), imx519->supplies); ++ ++ return ret; ++} ++ ++static int imx519_power_off(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx519 *imx519 = to_imx519(sd); ++ ++ gpiod_set_value_cansleep(imx519->reset_gpio, 0); ++ regulator_bulk_disable(ARRAY_SIZE(imx519_supply_name), imx519->supplies); ++ clk_disable_unprepare(imx519->xclk); ++ ++ /* Force reprogramming of the common registers when powered up again. */ ++ imx519->common_regs_written = false; ++ ++ return 0; ++} ++ ++static int imx519_get_regulators(struct imx519 *imx519) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx519->sd); ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(imx519_supply_name); i++) ++ imx519->supplies[i].supply = imx519_supply_name[i]; ++ ++ return devm_regulator_bulk_get(&client->dev, ++ ARRAY_SIZE(imx519_supply_name), ++ imx519->supplies); ++} ++ ++/* Verify chip ID */ ++static int imx519_identify_module(struct imx519 *imx519) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx519->sd); ++ int ret; ++ u64 val; ++ ++ ret = cci_read(imx519->regmap, IMX519_REG_CHIP_ID, &val, NULL); ++ if (ret) { ++ dev_err(&client->dev, "failed to read chip id %x, with error %d\n", ++ IMX519_CHIP_ID, ret); ++ return ret; ++ } ++ ++ if (val != IMX519_CHIP_ID) { ++ dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", ++ IMX519_CHIP_ID, val); ++ return -EIO; ++ } ++ ++ dev_info(&client->dev, "Device found is imx%llx\n", val); ++ ++ return 0; ++} ++ ++/* Initialize control handlers */ ++static int imx519_init_controls(struct imx519 *imx519) ++{ ++ struct v4l2_ctrl_handler *ctrl_hdlr; ++ struct i2c_client *client = v4l2_get_subdevdata(&imx519->sd); ++ struct v4l2_fwnode_device_properties props; ++ unsigned int i; ++ int ret; ++ static const u64 link_freq[] = { ++ IMX519_DEFAULT_LINK_FREQ, ++ }; ++ ++ ctrl_hdlr = &imx519->ctrl_handler; ++ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 16); ++ if (ret) ++ return ret; ++ ++ /* By default, PIXEL_RATE is read only */ ++ v4l2_ctrl_new_std(ctrl_hdlr, &imx519_ctrl_ops, V4L2_CID_PIXEL_RATE, ++ IMX519_PIXEL_RATE, IMX519_PIXEL_RATE, 1, ++ IMX519_PIXEL_RATE); ++ ++ imx519->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, NULL, ++ V4L2_CID_LINK_FREQ, ++ ARRAY_SIZE(link_freq) - 1, ++ 0, link_freq); ++ if (imx519->link_freq) ++ imx519->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ++ /* ++ * Create the controls here, but mode specific limits are setup ++ * in the imx519_set_framing_limits() call below. ++ */ ++ imx519->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx519_ctrl_ops, ++ V4L2_CID_VBLANK, 0, 0xffff, 1, 0); ++ imx519->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx519_ctrl_ops, ++ V4L2_CID_HBLANK, 0, 0xffff, 1, 0); ++ ++ /* HBLANK is read-only for now, but does change with mode. */ ++ if (imx519->hblank) ++ imx519->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ++ imx519->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx519_ctrl_ops, ++ V4L2_CID_EXPOSURE, ++ IMX519_EXPOSURE_MIN, ++ IMX519_EXPOSURE_MAX, ++ IMX519_EXPOSURE_STEP, ++ IMX519_EXPOSURE_DEFAULT); ++ ++ v4l2_ctrl_new_std(ctrl_hdlr, &imx519_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, ++ IMX519_ANA_GAIN_MIN, IMX519_ANA_GAIN_MAX, ++ IMX519_ANA_GAIN_STEP, IMX519_ANA_GAIN_DEFAULT); ++ ++ v4l2_ctrl_new_std(ctrl_hdlr, &imx519_ctrl_ops, V4L2_CID_DIGITAL_GAIN, ++ IMX519_DGTL_GAIN_MIN, IMX519_DGTL_GAIN_MAX, ++ IMX519_DGTL_GAIN_STEP, IMX519_DGTL_GAIN_DEFAULT); ++ ++ imx519->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx519_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ if (imx519->hflip) ++ imx519->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ imx519->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx519_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ if (imx519->vflip) ++ imx519->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx519_ctrl_ops, ++ V4L2_CID_TEST_PATTERN, ++ ARRAY_SIZE(imx519_test_pattern_menu) - 1, ++ 0, 0, imx519_test_pattern_menu); ++ for (i = 0; i < 4; i++) { ++ /* ++ * The assumption is that ++ * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1 ++ * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2 ++ * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3 ++ */ ++ v4l2_ctrl_new_std(ctrl_hdlr, &imx519_ctrl_ops, ++ V4L2_CID_TEST_PATTERN_RED + i, ++ IMX519_TEST_PATTERN_COLOUR_MIN, ++ IMX519_TEST_PATTERN_COLOUR_MAX, ++ IMX519_TEST_PATTERN_COLOUR_STEP, ++ IMX519_TEST_PATTERN_COLOUR_MAX); ++ /* The "Solid color" pattern is white by default */ ++ } ++ ++ if (ctrl_hdlr->error) { ++ ret = ctrl_hdlr->error; ++ dev_err(&client->dev, "%s control init failed (%d)\n", ++ __func__, ret); ++ goto error; ++ } ++ ++ ret = v4l2_fwnode_device_parse(&client->dev, &props); ++ if (ret) ++ goto error; ++ ++ ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx519_ctrl_ops, ++ &props); ++ if (ret) ++ goto error; ++ ++ imx519->sd.ctrl_handler = ctrl_hdlr; ++ ++ mutex_lock(imx519->ctrl_handler.lock); ++ ++ /* Setup exposure and frame/line length limits. */ ++ imx519_set_framing_limits(imx519); ++ ++ mutex_unlock(imx519->ctrl_handler.lock); ++ ++ return 0; ++ ++error: ++ v4l2_ctrl_handler_free(ctrl_hdlr); ++ ++ return ret; ++} ++ ++static void imx519_free_controls(struct imx519 *imx519) ++{ ++ v4l2_ctrl_handler_free(imx519->sd.ctrl_handler); ++} ++ ++static int imx519_check_hwcfg(struct device *dev) ++{ ++ struct fwnode_handle *endpoint; ++ struct v4l2_fwnode_endpoint ep_cfg = { ++ .bus_type = V4L2_MBUS_CSI2_DPHY ++ }; ++ int ret = -EINVAL; ++ ++ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); ++ if (!endpoint) { ++ dev_err(dev, "endpoint node not found\n"); ++ return -EINVAL; ++ } ++ ++ if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) { ++ dev_err(dev, "could not parse endpoint\n"); ++ goto out; ++ } ++ ++ /* Check the number of MIPI CSI2 data lanes */ ++ if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) { ++ dev_err(dev, "only 2 data lanes are currently supported\n"); ++ goto out; ++ } ++ ++ /* Check the link frequency set in device tree */ ++ if (!ep_cfg.nr_of_link_frequencies) { ++ dev_err(dev, "link-frequency property not found in DT\n"); ++ goto out; ++ } ++ ++ if (ep_cfg.nr_of_link_frequencies != 1 || ++ ep_cfg.link_frequencies[0] != IMX519_DEFAULT_LINK_FREQ) { ++ dev_err(dev, "Link frequency not supported: %lld\n", ++ ep_cfg.link_frequencies[0]); ++ goto out; ++ } ++ ++ ret = 0; ++ ++out: ++ v4l2_fwnode_endpoint_free(&ep_cfg); ++ fwnode_handle_put(endpoint); ++ ++ return ret; ++} ++ ++static const struct of_device_id imx519_dt_ids[] = { ++ { .compatible = "sony,imx519" }, ++ { /* sentinel */ } ++}; ++ ++static int imx519_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct imx519 *imx519; ++ u32 xclk_freq; ++ int ret; ++ ++ imx519 = devm_kzalloc(&client->dev, sizeof(*imx519), GFP_KERNEL); ++ if (!imx519) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&imx519->sd, client, &imx519_subdev_ops); ++ ++ /* Check the hardware configuration in device tree */ ++ if (imx519_check_hwcfg(dev)) ++ return -EINVAL; ++ ++ imx519->regmap = devm_cci_regmap_init_i2c(client, 16); ++ if (IS_ERR(imx519->regmap)) ++ return dev_err_probe(dev, PTR_ERR(imx519->regmap), ++ "failed to initialize CCI\n"); ++ ++ /* Get system clock (xclk) */ ++ imx519->xclk = devm_clk_get(dev, NULL); ++ if (IS_ERR(imx519->xclk)) ++ return dev_err_probe(dev, PTR_ERR(imx519->xclk), ++ "failed to get xclk\n"); ++ ++ ret = clk_set_rate(imx519->xclk, IMX519_XCLK_FREQ); ++ if (ret < 0) { ++ dev_err(dev, "failed to set xclk rate\n"); ++ return ret; ++ } ++ ++ xclk_freq = clk_get_rate(imx519->xclk); ++ if (xclk_freq != IMX519_XCLK_FREQ) ++ return dev_err_probe(dev, -EINVAL, ++ "xclk frequency not supported: %d Hz\n", ++ xclk_freq); ++ ++ ret = imx519_get_regulators(imx519); ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to get regulators\n"); ++ ++ /* Request optional enable pin */ ++ imx519->reset_gpio = devm_gpiod_get_optional(dev, "reset", ++ GPIOD_OUT_HIGH); ++ if (IS_ERR(imx519->reset_gpio)) ++ return dev_err_probe(dev, PTR_ERR(imx519->reset_gpio), ++ "failed to get reset gpio\n"); ++ ++ /* ++ * The sensor must be powered for imx519_identify_module() ++ * to be able to read the CHIP_ID register ++ */ ++ ret = imx519_power_on(dev); ++ if (ret) ++ return ret; ++ ++ ret = imx519_identify_module(imx519); ++ if (ret) ++ goto error_power_off; ++ ++ /* Set default mode to max resolution */ ++ imx519->mode = &supported_modes_10bit[0]; ++ ++ /* ++ * Enable runtime PM. As the device has been powered manually, mark it ++ * as active, and increase the usage count without resuming the device. ++ */ ++ pm_runtime_set_active(dev); ++ pm_runtime_get_noresume(dev); ++ pm_runtime_enable(dev); ++ ++ pm_runtime_set_autosuspend_delay(dev, 1000); ++ pm_runtime_use_autosuspend(dev); ++ ++ /* This needs the pm runtime to be registered. */ ++ ret = imx519_init_controls(imx519); ++ if (ret) ++ goto error_rpm_disable; ++ ++ /* Initialize subdev */ ++ imx519->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | ++ V4L2_SUBDEV_FL_HAS_EVENTS; ++ imx519->sd.entity.ops = &imx519_subdev_entity_ops; ++ imx519->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ++ /* Initialize source pads */ ++ imx519->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&imx519->sd.entity, 1, &imx519->pad); ++ if (ret) { ++ dev_err(dev, "failed to init entity pads: %d\n", ret); ++ goto error_handler_free; ++ } ++ ++ imx519->sd.state_lock = imx519->ctrl_handler.lock; ++ ret = v4l2_subdev_init_finalize(&imx519->sd); ++ if (ret < 0) { ++ dev_err(dev, "subdev init error: %d\n", ret); ++ goto error_media_entity; ++ } ++ ++ ret = v4l2_async_register_subdev_sensor(&imx519->sd); ++ if (ret < 0) { ++ dev_err(dev, "failed to register sensor sub-device: %d\n", ret); ++ goto error_subdev_cleanup; ++ } ++ ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); ++ ++ return 0; ++ ++error_subdev_cleanup: ++ v4l2_subdev_cleanup(&imx519->sd); ++ ++error_media_entity: ++ media_entity_cleanup(&imx519->sd.entity); ++ ++error_handler_free: ++ imx519_free_controls(imx519); ++ ++error_rpm_disable: ++ pm_runtime_disable(&client->dev); ++ pm_runtime_put_noidle(&client->dev); ++ ++error_power_off: ++ imx519_power_off(&client->dev); ++ ++ return ret; ++} ++ ++static void imx519_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx519 *imx519 = to_imx519(sd); ++ ++ v4l2_async_unregister_subdev(sd); ++ v4l2_subdev_cleanup(sd); ++ media_entity_cleanup(&sd->entity); ++ imx519_free_controls(imx519); ++ ++ pm_runtime_disable(&client->dev); ++ if (!pm_runtime_status_suspended(&client->dev)) ++ imx519_power_off(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++} ++ ++MODULE_DEVICE_TABLE(of, imx519_dt_ids); ++ ++static const struct dev_pm_ops imx519_pm_ops = { ++ SET_RUNTIME_PM_OPS(imx519_power_off, imx519_power_on, NULL) ++}; ++ ++static struct i2c_driver imx519_i2c_driver = { ++ .driver = { ++ .name = "imx519", ++ .of_match_table = imx519_dt_ids, ++ .pm = &imx519_pm_ops, ++ }, ++ .probe = imx519_probe, ++ .remove = imx519_remove, ++}; ++ ++module_i2c_driver(imx519_i2c_driver); ++ ++MODULE_AUTHOR("Lee Jackson "); ++MODULE_DESCRIPTION("Sony IMX519 sensor driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen2.c b/drivers/media/platform/qcom/camss/camss-csid-gen2.c +index 05ff5fa8095..b11de4797cc 100644 +--- a/drivers/media/platform/qcom/camss/camss-csid-gen2.c ++++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.c +@@ -21,7 +21,6 @@ + * interface support. As a result of that it has an + * alternate register layout. */ - struct btree *bch_btree_node_get(struct cache_set *c, struct btree_op *op, - struct bkey *k, int level, bool write, -@@ -1111,6 +1114,10 @@ static void btree_node_free(struct btree *b) - mutex_unlock(&b->c->bucket_lock); +-#define IS_LITE (csid->id >= 2 ? 1 : 0) + + #define CSID_HW_VERSION 0x0 + #define HW_VERSION_STEPPING 0 +@@ -35,13 +34,13 @@ + #define CSID_CSI2_RX_IRQ_MASK 0x24 + #define CSID_CSI2_RX_IRQ_CLEAR 0x28 + +-#define CSID_CSI2_RDIN_IRQ_STATUS(rdi) ((IS_LITE ? 0x30 : 0x40) \ ++#define CSID_CSI2_RDIN_IRQ_STATUS(rdi) ((csid_is_lite(csid) ? 0x30 : 0x40) \ + + 0x10 * (rdi)) +-#define CSID_CSI2_RDIN_IRQ_MASK(rdi) ((IS_LITE ? 0x34 : 0x44) \ ++#define CSID_CSI2_RDIN_IRQ_MASK(rdi) ((csid_is_lite(csid) ? 0x34 : 0x44) \ + + 0x10 * (rdi)) +-#define CSID_CSI2_RDIN_IRQ_CLEAR(rdi) ((IS_LITE ? 0x38 : 0x48) \ ++#define CSID_CSI2_RDIN_IRQ_CLEAR(rdi) ((csid_is_lite(csid) ? 0x38 : 0x48) \ + + 0x10 * (rdi)) +-#define CSID_CSI2_RDIN_IRQ_SET(rdi) ((IS_LITE ? 0x3C : 0x4C) \ ++#define CSID_CSI2_RDIN_IRQ_SET(rdi) ((csid_is_lite(csid) ? 0x3C : 0x4C) \ + + 0x10 * (rdi)) + + #define CSID_TOP_IRQ_STATUS 0x70 +@@ -73,7 +72,7 @@ + #define CGC_MODE_DYNAMIC_GATING 0 + #define CGC_MODE_ALWAYS_ON 1 + +-#define CSID_RDI_CFG0(rdi) ((IS_LITE ? 0x200 : 0x300) \ ++#define CSID_RDI_CFG0(rdi) ((csid_is_lite(csid) ? 0x200 : 0x300) \ + + 0x100 * (rdi)) + #define RDI_CFG0_BYTE_CNTR_EN 0 + #define RDI_CFG0_FORMAT_MEASURE_EN 1 +@@ -98,32 +97,32 @@ + #define RDI_CFG0_PACKING_FORMAT 30 + #define RDI_CFG0_ENABLE 31 + +-#define CSID_RDI_CFG1(rdi) ((IS_LITE ? 0x204 : 0x304)\ ++#define CSID_RDI_CFG1(rdi) ((csid_is_lite(csid) ? 0x204 : 0x304)\ + + 0x100 * (rdi)) + #define RDI_CFG1_TIMESTAMP_STB_SEL 0 + +-#define CSID_RDI_CTRL(rdi) ((IS_LITE ? 0x208 : 0x308)\ ++#define CSID_RDI_CTRL(rdi) ((csid_is_lite(csid) ? 0x208 : 0x308)\ + + 0x100 * (rdi)) + #define RDI_CTRL_HALT_CMD 0 + #define HALT_CMD_HALT_AT_FRAME_BOUNDARY 0 + #define HALT_CMD_RESUME_AT_FRAME_BOUNDARY 1 + #define RDI_CTRL_HALT_MODE 2 + +-#define CSID_RDI_FRM_DROP_PATTERN(rdi) ((IS_LITE ? 0x20C : 0x30C)\ ++#define CSID_RDI_FRM_DROP_PATTERN(rdi) ((csid_is_lite(csid) ? 0x20C : 0x30C)\ + + 0x100 * (rdi)) +-#define CSID_RDI_FRM_DROP_PERIOD(rdi) ((IS_LITE ? 0x210 : 0x310)\ ++#define CSID_RDI_FRM_DROP_PERIOD(rdi) ((csid_is_lite(csid) ? 0x210 : 0x310)\ + + 0x100 * (rdi)) +-#define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi) ((IS_LITE ? 0x214 : 0x314)\ ++#define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi) ((csid_is_lite(csid) ? 0x214 : 0x314)\ + + 0x100 * (rdi)) +-#define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi) ((IS_LITE ? 0x218 : 0x318)\ ++#define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi) ((csid_is_lite(csid) ? 0x218 : 0x318)\ + + 0x100 * (rdi)) +-#define CSID_RDI_RPP_PIX_DROP_PATTERN(rdi) ((IS_LITE ? 0x224 : 0x324)\ ++#define CSID_RDI_RPP_PIX_DROP_PATTERN(rdi) ((csid_is_lite(csid) ? 0x224 : 0x324)\ + + 0x100 * (rdi)) +-#define CSID_RDI_RPP_PIX_DROP_PERIOD(rdi) ((IS_LITE ? 0x228 : 0x328)\ ++#define CSID_RDI_RPP_PIX_DROP_PERIOD(rdi) ((csid_is_lite(csid) ? 0x228 : 0x328)\ + + 0x100 * (rdi)) +-#define CSID_RDI_RPP_LINE_DROP_PATTERN(rdi) ((IS_LITE ? 0x22C : 0x32C)\ ++#define CSID_RDI_RPP_LINE_DROP_PATTERN(rdi) ((csid_is_lite(csid) ? 0x22C : 0x32C)\ + + 0x100 * (rdi)) +-#define CSID_RDI_RPP_LINE_DROP_PERIOD(rdi) ((IS_LITE ? 0x230 : 0x330)\ ++#define CSID_RDI_RPP_LINE_DROP_PERIOD(rdi) ((csid_is_lite(csid) ? 0x230 : 0x330)\ + + 0x100 * (rdi)) + + #define CSID_TPG_CTRL 0x600 +diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c +index 95873f988f7..d393618ed54 100644 +--- a/drivers/media/platform/qcom/camss/camss-csid.c ++++ b/drivers/media/platform/qcom/camss/camss-csid.c +@@ -897,3 +897,8 @@ void msm_csid_unregister_entity(struct csid_device *csid) + media_entity_cleanup(&csid->subdev.entity); + v4l2_ctrl_handler_free(&csid->ctrls); + } ++ ++inline bool csid_is_lite(struct csid_device *csid) ++{ ++ return csid->camss->res->csid_res[csid->id].is_lite; ++} +diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h +index 30d94eb2eb0..fddccb69da1 100644 +--- a/drivers/media/platform/qcom/camss/camss-csid.h ++++ b/drivers/media/platform/qcom/camss/camss-csid.h +@@ -215,5 +215,12 @@ extern const struct csid_hw_ops csid_ops_4_1; + extern const struct csid_hw_ops csid_ops_4_7; + extern const struct csid_hw_ops csid_ops_gen2; + ++/* ++ * csid_is_lite - Check if CSID is CSID lite. ++ * @csid: CSID Device ++ * ++ * Return whether CSID is CSID lite ++ */ ++bool csid_is_lite(struct csid_device *csid); + + #endif /* QC_MSM_CAMSS_CSID_H */ +diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c +index 0b211fed127..795ac381533 100644 +--- a/drivers/media/platform/qcom/camss/camss-vfe-170.c ++++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c +@@ -627,42 +627,6 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm) + spin_unlock_irqrestore(&vfe->output_lock, flags); + } + +-/* +- * vfe_pm_domain_off - Disable power domains specific to this VFE. +- * @vfe: VFE Device +- */ +-static void vfe_pm_domain_off(struct vfe_device *vfe) +-{ +- struct camss *camss = vfe->camss; +- +- if (vfe->id >= camss->res->vfe_num) +- return; +- +- device_link_del(camss->genpd_link[vfe->id]); +-} +- +-/* +- * vfe_pm_domain_on - Enable power domains specific to this VFE. +- * @vfe: VFE Device +- */ +-static int vfe_pm_domain_on(struct vfe_device *vfe) +-{ +- struct camss *camss = vfe->camss; +- enum vfe_line_id id = vfe->id; +- +- if (id >= camss->res->vfe_num) +- return 0; +- +- camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], +- DL_FLAG_STATELESS | +- DL_FLAG_PM_RUNTIME | +- DL_FLAG_RPM_ACTIVE); +- if (!camss->genpd_link[id]) +- return -EINVAL; +- +- return 0; +-} +- + /* + * vfe_queue_buffer - Add empty buffer + * @vid: Video device structure +diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +index 2911e4126e7..ef6b34c915d 100644 +--- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c ++++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +@@ -936,7 +936,7 @@ static irqreturn_t vfe_isr(int irq, void *dev) + * vfe_pm_domain_off - Disable power domains specific to this VFE. + * @vfe: VFE Device + */ +-static void vfe_pm_domain_off(struct vfe_device *vfe) ++static void vfe_4_1_pm_domain_off(struct vfe_device *vfe) + { + /* nop */ + } +@@ -945,7 +945,7 @@ static void vfe_pm_domain_off(struct vfe_device *vfe) + * vfe_pm_domain_on - Enable power domains specific to this VFE. + * @vfe: VFE Device + */ +-static int vfe_pm_domain_on(struct vfe_device *vfe) ++static int vfe_4_1_pm_domain_on(struct vfe_device *vfe) + { + return 0; + } +@@ -999,8 +999,8 @@ const struct vfe_hw_ops vfe_ops_4_1 = { + .hw_version = vfe_hw_version, + .isr_read = vfe_isr_read, + .isr = vfe_isr, +- .pm_domain_off = vfe_pm_domain_off, +- .pm_domain_on = vfe_pm_domain_on, ++ .pm_domain_off = vfe_4_1_pm_domain_off, ++ .pm_domain_on = vfe_4_1_pm_domain_on, + .reg_update_clear = vfe_reg_update_clear, + .reg_update = vfe_reg_update, + .subdev_init = vfe_subdev_init, +diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +index b65ed0fef59..7655d22a9fd 100644 +--- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c ++++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +@@ -1103,42 +1103,6 @@ static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1) + writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD); + } + +-/* +- * vfe_pm_domain_off - Disable power domains specific to this VFE. +- * @vfe: VFE Device +- */ +-static void vfe_pm_domain_off(struct vfe_device *vfe) +-{ +- struct camss *camss; +- +- if (!vfe) +- return; +- +- camss = vfe->camss; +- +- device_link_del(camss->genpd_link[vfe->id]); +-} +- +-/* +- * vfe_pm_domain_on - Enable power domains specific to this VFE. +- * @vfe: VFE Device +- */ +-static int vfe_pm_domain_on(struct vfe_device *vfe) +-{ +- struct camss *camss = vfe->camss; +- enum vfe_line_id id = vfe->id; +- +- camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], DL_FLAG_STATELESS | +- DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); +- +- if (!camss->genpd_link[id]) { +- dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", id); +- return -EINVAL; +- } +- +- return 0; +-} +- + static void vfe_violation_read(struct vfe_device *vfe) + { + u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS); +diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c +index 7b3805177f0..f52fa30f385 100644 +--- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c ++++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c +@@ -1093,37 +1093,6 @@ static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1) + writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD); + } + +-/* +- * vfe_pm_domain_off - Disable power domains specific to this VFE. +- * @vfe: VFE Device +- */ +-static void vfe_pm_domain_off(struct vfe_device *vfe) +-{ +- struct camss *camss = vfe->camss; +- +- device_link_del(camss->genpd_link[vfe->id]); +-} +- +-/* +- * vfe_pm_domain_on - Enable power domains specific to this VFE. +- * @vfe: VFE Device +- */ +-static int vfe_pm_domain_on(struct vfe_device *vfe) +-{ +- struct camss *camss = vfe->camss; +- enum vfe_line_id id = vfe->id; +- +- camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], DL_FLAG_STATELESS | +- DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); +- +- if (!camss->genpd_link[id]) { +- dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", id); +- return -EINVAL; +- } +- +- return 0; +-} +- + static void vfe_violation_read(struct vfe_device *vfe) + { + u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS); +diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c +index f2368b77fc6..dc2735476c8 100644 +--- a/drivers/media/platform/qcom/camss/camss-vfe-480.c ++++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c +@@ -15,31 +15,28 @@ + #include "camss.h" + #include "camss-vfe.h" + +-/* VFE 2/3 are lite and have a different register layout */ +-#define IS_LITE (vfe->id >= 2 ? 1 : 0) +- + #define VFE_HW_VERSION (0x00) + +-#define VFE_GLOBAL_RESET_CMD (IS_LITE ? 0x0c : 0x1c) +-#define GLOBAL_RESET_HW_AND_REG (IS_LITE ? BIT(1) : BIT(0)) ++#define VFE_GLOBAL_RESET_CMD (vfe_is_lite(vfe) ? 0x0c : 0x1c) ++#define GLOBAL_RESET_HW_AND_REG (vfe_is_lite(vfe) ? BIT(1) : BIT(0)) + +-#define VFE_REG_UPDATE_CMD (IS_LITE ? 0x20 : 0x34) ++#define VFE_REG_UPDATE_CMD (vfe_is_lite(vfe) ? 0x20 : 0x34) + static inline int reg_update_rdi(struct vfe_device *vfe, int n) + { +- return IS_LITE ? BIT(n) : BIT(1 + (n)); ++ return vfe_is_lite(vfe) ? BIT(n) : BIT(1 + (n)); + } + + #define REG_UPDATE_RDI reg_update_rdi +-#define VFE_IRQ_CMD (IS_LITE ? 0x24 : 0x38) ++#define VFE_IRQ_CMD (vfe_is_lite(vfe) ? 0x24 : 0x38) + #define IRQ_CMD_GLOBAL_CLEAR BIT(0) + +-#define VFE_IRQ_MASK(n) ((IS_LITE ? 0x28 : 0x3c) + (n) * 4) +-#define IRQ_MASK_0_RESET_ACK (IS_LITE ? BIT(17) : BIT(0)) +-#define IRQ_MASK_0_BUS_TOP_IRQ (IS_LITE ? BIT(4) : BIT(7)) +-#define VFE_IRQ_CLEAR(n) ((IS_LITE ? 0x34 : 0x48) + (n) * 4) +-#define VFE_IRQ_STATUS(n) ((IS_LITE ? 0x40 : 0x54) + (n) * 4) ++#define VFE_IRQ_MASK(n) ((vfe_is_lite(vfe) ? 0x28 : 0x3c) + (n) * 4) ++#define IRQ_MASK_0_RESET_ACK (vfe_is_lite(vfe) ? BIT(17) : BIT(0)) ++#define IRQ_MASK_0_BUS_TOP_IRQ (vfe_is_lite(vfe) ? BIT(4) : BIT(7)) ++#define VFE_IRQ_CLEAR(n) ((vfe_is_lite(vfe) ? 0x34 : 0x48) + (n) * 4) ++#define VFE_IRQ_STATUS(n) ((vfe_is_lite(vfe) ? 0x40 : 0x54) + (n) * 4) + +-#define BUS_REG_BASE (IS_LITE ? 0x1a00 : 0xaa00) ++#define BUS_REG_BASE (vfe_is_lite(vfe) ? 0x1a00 : 0xaa00) + + #define VFE_BUS_WM_CGC_OVERRIDE (BUS_REG_BASE + 0x08) + #define WM_CGC_OVERRIDE_ALL (0x3FFFFFF) +@@ -49,13 +46,13 @@ static inline int reg_update_rdi(struct vfe_device *vfe, int n) + #define VFE_BUS_IRQ_MASK(n) (BUS_REG_BASE + 0x18 + (n) * 4) + static inline int bus_irq_mask_0_rdi_rup(struct vfe_device *vfe, int n) + { +- return IS_LITE ? BIT(n) : BIT(3 + (n)); ++ return vfe_is_lite(vfe) ? BIT(n) : BIT(3 + (n)); + } + + #define BUS_IRQ_MASK_0_RDI_RUP bus_irq_mask_0_rdi_rup + static inline int bus_irq_mask_0_comp_done(struct vfe_device *vfe, int n) + { +- return IS_LITE ? BIT(4 + (n)) : BIT(6 + (n)); ++ return vfe_is_lite(vfe) ? BIT(4 + (n)) : BIT(6 + (n)); + } + + #define BUS_IRQ_MASK_0_COMP_DONE bus_irq_mask_0_comp_done +@@ -90,8 +87,8 @@ static inline int bus_irq_mask_0_comp_done(struct vfe_device *vfe, int n) + /* for titan 480, each bus client is hardcoded to a specific path + * and each bus client is part of a hardcoded "comp group" + */ +-#define RDI_WM(n) ((IS_LITE ? 0 : 23) + (n)) +-#define RDI_COMP_GROUP(n) ((IS_LITE ? 0 : 11) + (n)) ++#define RDI_WM(n) ((vfe_is_lite(vfe) ? 0 : 23) + (n)) ++#define RDI_COMP_GROUP(n) ((vfe_is_lite(vfe) ? 0 : 11) + (n)) + + #define MAX_VFE_OUTPUT_LINES 4 + +@@ -452,42 +449,6 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm) + spin_unlock_irqrestore(&vfe->output_lock, flags); + } + +-/* +- * vfe_pm_domain_off - Disable power domains specific to this VFE. +- * @vfe: VFE Device +- */ +-static void vfe_pm_domain_off(struct vfe_device *vfe) +-{ +- struct camss *camss = vfe->camss; +- +- if (vfe->id >= camss->res->vfe_num) +- return; +- +- device_link_del(camss->genpd_link[vfe->id]); +-} +- +-/* +- * vfe_pm_domain_on - Enable power domains specific to this VFE. +- * @vfe: VFE Device +- */ +-static int vfe_pm_domain_on(struct vfe_device *vfe) +-{ +- struct camss *camss = vfe->camss; +- enum vfe_line_id id = vfe->id; +- +- if (id >= camss->res->vfe_num) +- return 0; +- +- camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], +- DL_FLAG_STATELESS | +- DL_FLAG_PM_RUNTIME | +- DL_FLAG_RPM_ACTIVE); +- if (!camss->genpd_link[id]) +- return -EINVAL; +- +- return 0; +-} +- + /* + * vfe_queue_buffer - Add empty buffer + * @vid: Video device structure +diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c +index 4839e2cedfe..b6ec0dc425b 100644 +--- a/drivers/media/platform/qcom/camss/camss-vfe.c ++++ b/drivers/media/platform/qcom/camss/camss-vfe.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -474,6 +475,40 @@ void vfe_isr_reset_ack(struct vfe_device *vfe) + complete(&vfe->reset_complete); } +/* -+ * Only error code or btree pointer will be returned, it is unncessary for -+ * callers to check NULL pointer. ++ * vfe_pm_domain_off - Disable power domains specific to this VFE. ++ * @vfe: VFE Device + */ - struct btree *__bch_btree_node_alloc(struct cache_set *c, struct btree_op *op, - int level, bool wait, - struct btree *parent) -@@ -1368,7 +1375,7 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op, - memset(new_nodes, 0, sizeof(new_nodes)); - closure_init_stack(&cl); - -- while (nodes < GC_MERGE_NODES && !IS_ERR(r[nodes].b)) -+ while (nodes < GC_MERGE_NODES && !IS_ERR_OR_NULL(r[nodes].b)) - keys += r[nodes++].keys; - - blocks = btree_default_blocks(b->c) * 2 / 3; -@@ -1532,6 +1539,8 @@ static int btree_gc_rewrite_node(struct btree *b, struct btree_op *op, - return 0; - - n = btree_node_alloc_replacement(replace, NULL); -+ if (IS_ERR(n)) ++void vfe_pm_domain_off(struct vfe_device *vfe) ++{ ++ if (!vfe->genpd) ++ return; ++ ++ device_link_del(vfe->genpd_link); ++ vfe->genpd_link = NULL; ++} ++ ++/* ++ * vfe_pm_domain_on - Enable power domains specific to this VFE. ++ * @vfe: VFE Device ++ */ ++int vfe_pm_domain_on(struct vfe_device *vfe) ++{ ++ struct camss *camss = vfe->camss; ++ ++ if (!vfe->genpd) + return 0; - - /* recheck reserve after allocating replacement node */ - if (btree_check_reserve(b, NULL)) { -diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c -index 8bd89976637..bfe1685dbae 100644 ---- a/drivers/md/bcache/super.c -+++ b/drivers/md/bcache/super.c -@@ -905,6 +905,8 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size, - - if (!d->stripe_size) - d->stripe_size = 1 << 31; -+ else if (d->stripe_size < BCH_MIN_STRIPE_SZ) -+ d->stripe_size = roundup(BCH_MIN_STRIPE_SZ, d->stripe_size); - - n = DIV_ROUND_UP_ULL(sectors, d->stripe_size); - if (!n || n > max_stripes) { -@@ -2016,7 +2018,7 @@ static int run_cache_set(struct cache_set *c) - c->root = bch_btree_node_get(c, NULL, k, - j->btree_level, - true, NULL); -- if (IS_ERR_OR_NULL(c->root)) -+ if (IS_ERR(c->root)) - goto err; - - list_del_init(&c->root->list); -diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c -index 45d8af755de..a438efb6606 100644 ---- a/drivers/md/bcache/sysfs.c -+++ b/drivers/md/bcache/sysfs.c -@@ -1104,7 +1104,7 @@ SHOW(__bch_cache) - sum += INITIAL_PRIO - cached[i]; - - if (n) -- do_div(sum, n); -+ sum = div64_u64(sum, n); - - for (i = 0; i < ARRAY_SIZE(q); i++) - q[i] = INITIAL_PRIO - cached[n * (i + 1) / -diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c -index 24c049067f6..3accfdaee6b 100644 ---- a/drivers/md/bcache/writeback.c -+++ b/drivers/md/bcache/writeback.c -@@ -913,7 +913,7 @@ static int bch_dirty_init_thread(void *arg) - int cur_idx, prev_idx, skip_nr; - - k = p = NULL; -- cur_idx = prev_idx = 0; -+ prev_idx = 0; - - bch_btree_iter_init(&c->root->keys, &iter, NULL); - k = bch_btree_iter_next_filter(&iter, &c->root->keys, bch_ptr_bad); -@@ -977,24 +977,35 @@ static int bch_btre_dirty_init_thread_nr(void) - void bch_sectors_dirty_init(struct bcache_device *d) ++ ++ vfe->genpd_link = device_link_add(camss->dev, vfe->genpd, ++ DL_FLAG_STATELESS | ++ DL_FLAG_PM_RUNTIME | ++ DL_FLAG_RPM_ACTIVE); ++ if (!vfe->genpd_link) ++ return -EINVAL; ++ ++ return 0; ++} ++ + static int vfe_match_clock_names(struct vfe_device *vfe, + struct camss_clock *clock) { - int i; -+ struct btree *b = NULL; - struct bkey *k = NULL; - struct btree_iter iter; - struct sectors_dirty_init op; - struct cache_set *c = d->c; - struct bch_dirty_init_state state; +@@ -1347,6 +1382,34 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, + if (!res->line_num) + return -EINVAL; -+retry_lock: -+ b = c->root; -+ rw_lock(0, b, b->level); -+ if (b != c->root) { -+ rw_unlock(0, b); -+ goto retry_lock; ++ /* Power domain */ ++ ++ if (res->pd_name) { ++ vfe->genpd = dev_pm_domain_attach_by_name(camss->dev, ++ res->pd_name); ++ if (IS_ERR(vfe->genpd)) { ++ ret = PTR_ERR(vfe->genpd); ++ return ret; ++ } + } + - /* Just count root keys if no leaf node */ -- rw_lock(0, c->root, c->root->level); - if (c->root->level == 0) { - bch_btree_op_init(&op.op, -1); - op.inode = d->id; - op.count = 0; ++ if (!vfe->genpd && res->has_pd) { ++ /* ++ * Legacy magic index. ++ * Requires ++ * power-domain = , ++ * , ++ * ++ * id must correspondng to the index of the VFE which must ++ * come before the TOP GDSC. VFE Lite has no individually ++ * collapasible domain which is why id < vfe_num is a valid ++ * check. ++ */ ++ vfe->genpd = dev_pm_domain_attach_by_id(camss->dev, id); ++ if (IS_ERR(vfe->genpd)) ++ return PTR_ERR(vfe->genpd); ++ } ++ + vfe->line_num = res->line_num; + vfe->ops->subdev_init(dev, vfe); - for_each_key_filter(&c->root->keys, -- k, &iter, bch_ptr_invalid) -+ k, &iter, bch_ptr_invalid) { -+ if (KEY_INODE(k) != op.inode) -+ continue; - sectors_dirty_init_fn(&op.op, c->root, k); -+ } - -- rw_unlock(0, c->root); -+ rw_unlock(0, b); - return; - } - -@@ -1014,23 +1025,24 @@ void bch_sectors_dirty_init(struct bcache_device *d) - if (atomic_read(&state.enough)) - break; - -+ atomic_inc(&state.started); - state.infos[i].state = &state; - state.infos[i].thread = - kthread_run(bch_dirty_init_thread, &state.infos[i], - "bch_dirtcnt[%d]", i); - if (IS_ERR(state.infos[i].thread)) { - pr_err("fails to run thread bch_dirty_init[%d]\n", i); -+ atomic_dec(&state.started); - for (--i; i >= 0; i--) - kthread_stop(state.infos[i].thread); - goto out; - } -- atomic_inc(&state.started); - } - - out: - /* Must wait for all threads to stop. */ - wait_event(state.wait, atomic_read(&state.started) == 0); -- rw_unlock(0, c->root); -+ rw_unlock(0, b); +@@ -1469,6 +1532,19 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, + return 0; } - void bch_cached_dev_writeback_init(struct cached_dev *dc) -diff --git a/drivers/md/md.c b/drivers/md/md.c -index 4ee4593c874..c94373d64f2 100644 ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -8666,7 +8666,8 @@ static void md_end_clone_io(struct bio *bio) - struct bio *orig_bio = md_io_clone->orig_bio; - struct mddev *mddev = md_io_clone->mddev; ++/* ++ * msm_vfe_genpd_cleanup - Cleanup VFE genpd linkages ++ * @vfe: VFE device ++ */ ++void msm_vfe_genpd_cleanup(struct vfe_device *vfe) ++{ ++ if (vfe->genpd_link) ++ device_link_del(vfe->genpd_link); ++ ++ if (vfe->genpd) ++ dev_pm_domain_detach(vfe->genpd, true); ++} ++ + /* + * vfe_link_setup - Setup VFE connections + * @entity: Pointer to media entity structure +@@ -1663,3 +1739,8 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe) + media_entity_cleanup(&sd->entity); + } + } ++ ++bool vfe_is_lite(struct vfe_device *vfe) ++{ ++ return vfe->camss->res->vfe_res[vfe->id].is_lite; ++} +diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h +index 09baded0dcd..0572c9b08e1 100644 +--- a/drivers/media/platform/qcom/camss/camss-vfe.h ++++ b/drivers/media/platform/qcom/camss/camss-vfe.h +@@ -150,6 +150,8 @@ struct vfe_device { + const struct vfe_hw_ops_gen1 *ops_gen1; + struct vfe_isr_ops isr_ops; + struct camss_video_ops video_ops; ++ struct device *genpd; ++ struct device_link *genpd_link; + }; -- orig_bio->bi_status = bio->bi_status; -+ if (bio->bi_status && !orig_bio->bi_status) -+ orig_bio->bi_status = bio->bi_status; + struct camss_subdev_resources; +@@ -157,6 +159,8 @@ struct camss_subdev_resources; + int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, + const struct camss_subdev_resources *res, u8 id); - if (md_io_clone->start_time) - bio_end_io_acct(orig_bio, md_io_clone->start_time); ++void msm_vfe_genpd_cleanup(struct vfe_device *vfe); ++ + int msm_vfe_register_entities(struct vfe_device *vfe, + struct v4l2_device *v4l2_dev); + +@@ -201,6 +205,18 @@ int vfe_reset(struct vfe_device *vfe); + */ + int vfe_disable(struct vfe_line *line); + ++/* ++ * vfe_pm_domain_off - Disable power domains specific to this VFE. ++ * @vfe: VFE Device ++ */ ++void vfe_pm_domain_off(struct vfe_device *vfe); ++ ++/* ++ * vfe_pm_domain_on - Enable power domains specific to this VFE. ++ * @vfe: VFE Device ++ */ ++int vfe_pm_domain_on(struct vfe_device *vfe); ++ + extern const struct vfe_hw_ops vfe_ops_4_1; + extern const struct vfe_hw_ops vfe_ops_4_7; + extern const struct vfe_hw_ops vfe_ops_4_8; +@@ -210,4 +226,14 @@ extern const struct vfe_hw_ops vfe_ops_480; + int vfe_get(struct vfe_device *vfe); + void vfe_put(struct vfe_device *vfe); + ++/* ++ * vfe_is_lite - Return if VFE is VFE lite. ++ * @vfe: VFE Device ++ * ++ * Some VFE lites have a different register layout. ++ * ++ * Return whether VFE is VFE lite ++ */ ++bool vfe_is_lite(struct vfe_device *vfe); ++ + #endif /* QC_MSM_CAMSS_VFE_H */ +diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c +index 8e78dd8d596..3bb23fd2995 100644 +--- a/drivers/media/platform/qcom/camss/camss.c ++++ b/drivers/media/platform/qcom/camss/camss.c +@@ -278,6 +278,7 @@ static const struct camss_subdev_resources vfe_res_8x96[] = { + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, + .line_num = 3, ++ .has_pd = true, + .ops = &vfe_ops_4_7 + }, + +@@ -298,6 +299,7 @@ static const struct camss_subdev_resources vfe_res_8x96[] = { + .reg = { "vfe1" }, + .interrupt = { "vfe1" }, + .line_num = 3, ++ .has_pd = true, + .ops = &vfe_ops_4_7 + } + }; +@@ -468,6 +470,7 @@ static const struct camss_subdev_resources vfe_res_660[] = { + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, + .line_num = 3, ++ .has_pd = true, + .ops = &vfe_ops_4_8 + }, + +@@ -491,6 +494,7 @@ static const struct camss_subdev_resources vfe_res_660[] = { + .reg = { "vfe1" }, + .interrupt = { "vfe1" }, + .line_num = 3, ++ .has_pd = true, + .ops = &vfe_ops_4_8 + } + }; +@@ -634,6 +638,7 @@ static const struct camss_subdev_resources csid_res_845[] = { + { 384000000 } }, + .reg = { "csid2" }, + .interrupt = { "csid2" }, ++ .is_lite = true, + .ops = &csid_ops_gen2 + } + }; +@@ -658,6 +663,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, + .line_num = 4, ++ .has_pd = true, + .ops = &vfe_ops_170 + }, + +@@ -680,6 +686,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { + .reg = { "vfe1" }, + .interrupt = { "vfe1" }, + .line_num = 4, ++ .has_pd = true, + .ops = &vfe_ops_170 + }, + +@@ -700,6 +707,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { + { 384000000 } }, + .reg = { "vfe_lite" }, + .interrupt = { "vfe_lite" }, ++ .is_lite = true, + .line_num = 4, + .ops = &vfe_ops_170 + } +@@ -805,6 +813,7 @@ static const struct camss_subdev_resources csid_res_8250[] = { + { 0 } }, + .reg = { "csid2" }, + .interrupt = { "csid2" }, ++ .is_lite = true, + .ops = &csid_ops_gen2 + }, + /* CSID3 */ +@@ -817,6 +826,7 @@ static const struct camss_subdev_resources csid_res_8250[] = { + { 0 } }, + .reg = { "csid3" }, + .interrupt = { "csid3" }, ++ .is_lite = true, + .ops = &csid_ops_gen2 + } + }; +@@ -839,7 +849,9 @@ static const struct camss_subdev_resources vfe_res_8250[] = { + { 0 } }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, ++ .pd_name = "ife0", + .line_num = 3, ++ .has_pd = true, + .ops = &vfe_ops_480 + }, + /* VFE1 */ +@@ -859,7 +871,9 @@ static const struct camss_subdev_resources vfe_res_8250[] = { + { 0 } }, + .reg = { "vfe1" }, + .interrupt = { "vfe1" }, ++ .pd_name = "ife1", + .line_num = 3, ++ .has_pd = true, + .ops = &vfe_ops_480 + }, + /* VFE2 (lite) */ +@@ -878,6 +892,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { + { 0 } }, + .reg = { "vfe_lite0" }, + .interrupt = { "vfe_lite0" }, ++ .is_lite = true, + .line_num = 4, + .ops = &vfe_ops_480 + }, +@@ -897,6 +912,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { + { 0 } }, + .reg = { "vfe_lite1" }, + .interrupt = { "vfe_lite1" }, ++ .is_lite = true, + .line_num = 4, + .ops = &vfe_ops_480 + }, +@@ -1196,7 +1212,7 @@ static int camss_init_subdevices(struct camss *camss) + } + + /* note: SM8250 requires VFE to be initialized before CSID */ +- for (i = 0; i < camss->vfe_total_num; i++) { ++ for (i = 0; i < camss->res->vfe_num; i++) { + ret = msm_vfe_subdev_init(camss, &camss->vfe[i], + &res->vfe_res[i], i); + if (ret < 0) { +@@ -1268,7 +1284,7 @@ static int camss_register_entities(struct camss *camss) + goto err_reg_ispif; + } + +- for (i = 0; i < camss->vfe_total_num; i++) { ++ for (i = 0; i < camss->res->vfe_num; i++) { + ret = msm_vfe_register_entities(&camss->vfe[i], + &camss->v4l2_dev); + if (ret < 0) { +@@ -1340,7 +1356,7 @@ static int camss_register_entities(struct camss *camss) + } + } else { + for (i = 0; i < camss->res->csid_num; i++) +- for (k = 0; k < camss->vfe_total_num; k++) ++ for (k = 0; k < camss->res->vfe_num; k++) + for (j = 0; j < camss->vfe[k].line_num; j++) { + struct v4l2_subdev *csid = &camss->csid[i].subdev; + struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev; +@@ -1364,7 +1380,7 @@ static int camss_register_entities(struct camss *camss) + return 0; + + err_link: +- i = camss->vfe_total_num; ++ i = camss->res->vfe_num; + err_reg_vfe: + for (i--; i >= 0; i--) + msm_vfe_unregister_entities(&camss->vfe[i]); +@@ -1403,7 +1419,7 @@ static void camss_unregister_entities(struct camss *camss) + + msm_ispif_unregister_entities(camss->ispif); + +- for (i = 0; i < camss->vfe_total_num; i++) ++ for (i = 0; i < camss->res->vfe_num; i++) + msm_vfe_unregister_entities(&camss->vfe[i]); + } + +@@ -1478,7 +1494,9 @@ static const struct media_device_ops camss_media_ops = { + + static int camss_configure_pd(struct camss *camss) + { ++ const struct camss_resources *res = camss->res; + struct device *dev = camss->dev; ++ int vfepd_num; + int i; + int ret; + +@@ -1498,45 +1516,57 @@ static int camss_configure_pd(struct camss *camss) + if (camss->genpd_num == 1) + return 0; + +- camss->genpd = devm_kmalloc_array(dev, camss->genpd_num, +- sizeof(*camss->genpd), GFP_KERNEL); +- if (!camss->genpd) +- return -ENOMEM; ++ /* count the # of VFEs which have flagged power-domain */ ++ for (vfepd_num = i = 0; i < camss->res->vfe_num; i++) { ++ if (res->vfe_res[i].has_pd) ++ vfepd_num++; ++ } + +- camss->genpd_link = devm_kmalloc_array(dev, camss->genpd_num, +- sizeof(*camss->genpd_link), +- GFP_KERNEL); +- if (!camss->genpd_link) +- return -ENOMEM; ++ /* ++ * If the number of power-domains is greater than the number of VFEs ++ * then the additional power-domain is for the entire CAMSS block. ++ */ ++ if (!(camss->genpd_num > vfepd_num)) ++ return 0; + + /* +- * VFE power domains are in the beginning of the list, and while all +- * power domains should be attached, only if TITAN_TOP power domain is +- * found in the list, it should be linked over here. ++ * If a power-domain name is defined try to use it. ++ * It is possible we are running a new kernel with an old dtb so ++ * fallback to indexes even if a pd_name is defined but not found. + */ +- for (i = 0; i < camss->genpd_num; i++) { +- camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i); +- if (IS_ERR(camss->genpd[i])) { +- ret = PTR_ERR(camss->genpd[i]); ++ if (camss->res->pd_name) { ++ camss->genpd = dev_pm_domain_attach_by_name(camss->dev, ++ camss->res->pd_name); ++ if (IS_ERR(camss->genpd)) { ++ ret = PTR_ERR(camss->genpd); + goto fail_pm; + } + } + +- if (i > camss->res->vfe_num) { +- camss->genpd_link[i - 1] = device_link_add(camss->dev, camss->genpd[i - 1], +- DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | +- DL_FLAG_RPM_ACTIVE); +- if (!camss->genpd_link[i - 1]) { +- ret = -EINVAL; +- goto fail_pm; +- } ++ if (!camss->genpd) { ++ /* ++ * Legacy magic index. TITAN_TOP GDSC must be the last ++ * item in the power-domain list. ++ */ ++ camss->genpd = dev_pm_domain_attach_by_id(camss->dev, ++ camss->genpd_num - 1); ++ } ++ if (IS_ERR_OR_NULL(camss->genpd)) { ++ ret = PTR_ERR(camss->genpd); ++ goto fail_pm; ++ } ++ camss->genpd_link = device_link_add(camss->dev, camss->genpd, ++ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | ++ DL_FLAG_RPM_ACTIVE); ++ if (!camss->genpd_link) { ++ ret = -EINVAL; ++ goto fail_pm; + } + + return 0; + + fail_pm: +- for (--i ; i >= 0; i--) +- dev_pm_domain_detach(camss->genpd[i], true); ++ dev_pm_domain_detach(camss->genpd, true); + + return ret; + } +@@ -1558,18 +1588,25 @@ static int camss_icc_get(struct camss *camss) + return 0; + } + +-static void camss_genpd_cleanup(struct camss *camss) ++static void camss_genpd_subdevice_cleanup(struct camss *camss) + { + int i; + ++ for (i = 0; i < camss->res->vfe_num; i++) ++ msm_vfe_genpd_cleanup(&camss->vfe[i]); ++} ++ ++static void camss_genpd_cleanup(struct camss *camss) ++{ + if (camss->genpd_num == 1) + return; + +- if (camss->genpd_num > camss->res->vfe_num) +- device_link_del(camss->genpd_link[camss->genpd_num - 1]); ++ camss_genpd_subdevice_cleanup(camss); ++ ++ if (camss->genpd_link) ++ device_link_del(camss->genpd_link); + +- for (i = 0; i < camss->genpd_num; i++) +- dev_pm_domain_detach(camss->genpd[i], true); ++ dev_pm_domain_detach(camss->genpd, true); + } + + /* +@@ -1612,8 +1649,7 @@ static int camss_probe(struct platform_device *pdev) + return -ENOMEM; + } + +- camss->vfe_total_num = camss->res->vfe_num + camss->res->vfe_lite_num; +- camss->vfe = devm_kcalloc(dev, camss->vfe_total_num, ++ camss->vfe = devm_kcalloc(dev, camss->res->vfe_num, + sizeof(*camss->vfe), GFP_KERNEL); + if (!camss->vfe) + return -ENOMEM; +@@ -1771,12 +1807,12 @@ static const struct camss_resources sdm845_resources = { + .vfe_res = vfe_res_845, + .csiphy_num = ARRAY_SIZE(csiphy_res_845), + .csid_num = ARRAY_SIZE(csid_res_845), +- .vfe_num = 2, +- .vfe_lite_num = 1, ++ .vfe_num = ARRAY_SIZE(vfe_res_845), + }; + + static const struct camss_resources sm8250_resources = { + .version = CAMSS_8250, ++ .pd_name = "top", + .csiphy_res = csiphy_res_8250, + .csid_res = csid_res_8250, + .vfe_res = vfe_res_8250, +@@ -1784,8 +1820,7 @@ static const struct camss_resources sm8250_resources = { + .icc_path_num = ARRAY_SIZE(icc_res_sm8250), + .csiphy_num = ARRAY_SIZE(csiphy_res_8250), + .csid_num = ARRAY_SIZE(csid_res_8250), +- .vfe_num = 2, +- .vfe_lite_num = 2, ++ .vfe_num = ARRAY_SIZE(vfe_res_8250), + }; + + static const struct of_device_id camss_dt_match[] = { +diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h +index 8acad7321c0..a0c2dcc779f 100644 +--- a/drivers/media/platform/qcom/camss/camss.h ++++ b/drivers/media/platform/qcom/camss/camss.h +@@ -48,7 +48,10 @@ struct camss_subdev_resources { + u32 clock_rate[CAMSS_RES_MAX][CAMSS_RES_MAX]; + char *reg[CAMSS_RES_MAX]; + char *interrupt[CAMSS_RES_MAX]; ++ char *pd_name; + u8 line_num; ++ bool has_pd; ++ bool is_lite; + const void *ops; + }; + +@@ -83,6 +86,7 @@ enum icc_count { + + struct camss_resources { + enum camss_version version; ++ const char *pd_name; + const struct camss_subdev_resources *csiphy_res; + const struct camss_subdev_resources *csid_res; + const struct camss_subdev_resources *ispif_res; +@@ -92,7 +96,6 @@ struct camss_resources { + const unsigned int csiphy_num; + const unsigned int csid_num; + const unsigned int vfe_num; +- const unsigned int vfe_lite_num; + }; + + struct camss { +@@ -106,11 +109,10 @@ struct camss { + struct vfe_device *vfe; + atomic_t ref_count; + int genpd_num; +- struct device **genpd; +- struct device_link **genpd_link; ++ struct device *genpd; ++ struct device_link *genpd_link; + struct icc_path *icc_path[ICC_SM8250_COUNT]; + const struct camss_resources *res; +- unsigned int vfe_total_num; + }; + + struct camss_camera_interface { diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 1c6c62a7f7f..2a59d240e14 100644 --- a/drivers/misc/fastrpc.c @@ -13359,1175 +13664,6 @@ index 1c6c62a7f7f..2a59d240e14 100644 secure_dsp = !(of_property_read_bool(rdev->of_node, "qcom,non-secure-domain")); data->secure = secure_dsp; -diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c -index 614c0278419..6b73648b377 100644 ---- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c -+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c -@@ -682,10 +682,24 @@ static void xgbe_service(struct work_struct *work) - static void xgbe_service_timer(struct timer_list *t) - { - struct xgbe_prv_data *pdata = from_timer(pdata, t, service_timer); -+ struct xgbe_channel *channel; -+ unsigned int i; - - queue_work(pdata->dev_workqueue, &pdata->service_work); - - mod_timer(&pdata->service_timer, jiffies + HZ); -+ -+ if (!pdata->tx_usecs) -+ return; -+ -+ for (i = 0; i < pdata->channel_count; i++) { -+ channel = pdata->channel[i]; -+ if (!channel->tx_ring || channel->tx_timer_active) -+ break; -+ channel->tx_timer_active = 1; -+ mod_timer(&channel->tx_timer, -+ jiffies + usecs_to_jiffies(pdata->tx_usecs)); -+ } - } - - static void xgbe_init_timers(struct xgbe_prv_data *pdata) -diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c -index 6e83ff59172..32fab5e7724 100644 ---- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c -+++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c -@@ -314,10 +314,15 @@ static int xgbe_get_link_ksettings(struct net_device *netdev, - - cmd->base.phy_address = pdata->phy.address; - -- cmd->base.autoneg = pdata->phy.autoneg; -- cmd->base.speed = pdata->phy.speed; -- cmd->base.duplex = pdata->phy.duplex; -+ if (netif_carrier_ok(netdev)) { -+ cmd->base.speed = pdata->phy.speed; -+ cmd->base.duplex = pdata->phy.duplex; -+ } else { -+ cmd->base.speed = SPEED_UNKNOWN; -+ cmd->base.duplex = DUPLEX_UNKNOWN; -+ } - -+ cmd->base.autoneg = pdata->phy.autoneg; - cmd->base.port = PORT_NONE; - - XGBE_LM_COPY(cmd, supported, lks, supported); -diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c -index 32d2c6fac65..4a2dc705b52 100644 ---- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c -+++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c -@@ -1193,7 +1193,19 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata) - if (pdata->phy.duplex != DUPLEX_FULL) - return -EINVAL; - -- xgbe_set_mode(pdata, mode); -+ /* Force the mode change for SFI in Fixed PHY config. -+ * Fixed PHY configs needs PLL to be enabled while doing mode set. -+ * When the SFP module isn't connected during boot, driver assumes -+ * AN is ON and attempts autonegotiation. However, if the connected -+ * SFP comes up in Fixed PHY config, the link will not come up as -+ * PLL isn't enabled while the initial mode set command is issued. -+ * So, force the mode change for SFI in Fixed PHY configuration to -+ * fix link issues. -+ */ -+ if (mode == XGBE_MODE_SFI) -+ xgbe_change_mode(pdata, mode); -+ else -+ xgbe_set_mode(pdata, mode); - - return 0; - } -diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c -index 08d7edccfb8..3f99eb19824 100644 ---- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c -+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c -@@ -3844,7 +3844,7 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg) - struct i40e_pf *pf = vf->pf; - struct i40e_vsi *vsi = NULL; - int aq_ret = 0; -- int i, ret; -+ int i; - - if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) { - aq_ret = -EINVAL; -@@ -3868,8 +3868,10 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg) - } - - cfilter = kzalloc(sizeof(*cfilter), GFP_KERNEL); -- if (!cfilter) -- return -ENOMEM; -+ if (!cfilter) { -+ aq_ret = -ENOMEM; -+ goto err_out; -+ } - - /* parse destination mac address */ - for (i = 0; i < ETH_ALEN; i++) -@@ -3917,13 +3919,13 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg) - - /* Adding cloud filter programmed as TC filter */ - if (tcf.dst_port) -- ret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter, true); -+ aq_ret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter, true); - else -- ret = i40e_add_del_cloud_filter(vsi, cfilter, true); -- if (ret) { -+ aq_ret = i40e_add_del_cloud_filter(vsi, cfilter, true); -+ if (aq_ret) { - dev_err(&pf->pdev->dev, - "VF %d: Failed to add cloud filter, err %pe aq_err %s\n", -- vf->vf_id, ERR_PTR(ret), -+ vf->vf_id, ERR_PTR(aq_ret), - i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); - goto err_free; - } -diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c -index 6607fa6fe55..fb9c93f37e8 100644 ---- a/drivers/net/ethernet/intel/ice/ice_main.c -+++ b/drivers/net/ethernet/intel/ice/ice_main.c -@@ -7401,15 +7401,6 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) - goto err_vsi_rebuild; - } - -- /* configure PTP timestamping after VSI rebuild */ -- if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) { -- if (pf->ptp.tx_interrupt_mode == ICE_PTP_TX_INTERRUPT_SELF) -- ice_ptp_cfg_timestamp(pf, false); -- else if (pf->ptp.tx_interrupt_mode == ICE_PTP_TX_INTERRUPT_ALL) -- /* for E82x PHC owner always need to have interrupts */ -- ice_ptp_cfg_timestamp(pf, true); -- } -- - err = ice_vsi_rebuild_by_type(pf, ICE_VSI_SWITCHDEV_CTRL); - if (err) { - dev_err(dev, "Switchdev CTRL VSI rebuild failed: %d\n", err); -@@ -7461,6 +7452,9 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) - ice_plug_aux_dev(pf); - if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG)) - ice_lag_rebuild(pf); -+ -+ /* Restore timestamp mode settings after VSI rebuild */ -+ ice_ptp_restore_timestamp_mode(pf); - return; - - err_vsi_rebuild: -diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c -index 1eddcbe89b0..71f405f8a6f 100644 ---- a/drivers/net/ethernet/intel/ice/ice_ptp.c -+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c -@@ -256,48 +256,42 @@ ice_verify_pin_e810t(struct ptp_clock_info *info, unsigned int pin, - } - - /** -- * ice_ptp_configure_tx_tstamp - Enable or disable Tx timestamp interrupt -- * @pf: The PF pointer to search in -- * @on: bool value for whether timestamp interrupt is enabled or disabled -+ * ice_ptp_cfg_tx_interrupt - Configure Tx timestamp interrupt for the device -+ * @pf: Board private structure -+ * -+ * Program the device to respond appropriately to the Tx timestamp interrupt -+ * cause. - */ --static void ice_ptp_configure_tx_tstamp(struct ice_pf *pf, bool on) -+static void ice_ptp_cfg_tx_interrupt(struct ice_pf *pf) - { -+ struct ice_hw *hw = &pf->hw; -+ bool enable; - u32 val; - -+ switch (pf->ptp.tx_interrupt_mode) { -+ case ICE_PTP_TX_INTERRUPT_ALL: -+ /* React to interrupts across all quads. */ -+ wr32(hw, PFINT_TSYN_MSK + (0x4 * hw->pf_id), (u32)0x1f); -+ enable = true; -+ break; -+ case ICE_PTP_TX_INTERRUPT_NONE: -+ /* Do not react to interrupts on any quad. */ -+ wr32(hw, PFINT_TSYN_MSK + (0x4 * hw->pf_id), (u32)0x0); -+ enable = false; -+ break; -+ case ICE_PTP_TX_INTERRUPT_SELF: -+ default: -+ enable = pf->ptp.tstamp_config.tx_type == HWTSTAMP_TX_ON; -+ break; -+ } -+ - /* Configure the Tx timestamp interrupt */ -- val = rd32(&pf->hw, PFINT_OICR_ENA); -- if (on) -+ val = rd32(hw, PFINT_OICR_ENA); -+ if (enable) - val |= PFINT_OICR_TSYN_TX_M; - else - val &= ~PFINT_OICR_TSYN_TX_M; -- wr32(&pf->hw, PFINT_OICR_ENA, val); --} -- --/** -- * ice_set_tx_tstamp - Enable or disable Tx timestamping -- * @pf: The PF pointer to search in -- * @on: bool value for whether timestamps are enabled or disabled -- */ --static void ice_set_tx_tstamp(struct ice_pf *pf, bool on) --{ -- struct ice_vsi *vsi; -- u16 i; -- -- vsi = ice_get_main_vsi(pf); -- if (!vsi) -- return; -- -- /* Set the timestamp enable flag for all the Tx rings */ -- ice_for_each_txq(vsi, i) { -- if (!vsi->tx_rings[i]) -- continue; -- vsi->tx_rings[i]->ptp_tx = on; -- } -- -- if (pf->ptp.tx_interrupt_mode == ICE_PTP_TX_INTERRUPT_SELF) -- ice_ptp_configure_tx_tstamp(pf, on); -- -- pf->ptp.tstamp_config.tx_type = on ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; -+ wr32(hw, PFINT_OICR_ENA, val); - } - - /** -@@ -311,7 +305,7 @@ static void ice_set_rx_tstamp(struct ice_pf *pf, bool on) - u16 i; - - vsi = ice_get_main_vsi(pf); -- if (!vsi) -+ if (!vsi || !vsi->rx_rings) - return; - - /* Set the timestamp flag for all the Rx rings */ -@@ -320,23 +314,50 @@ static void ice_set_rx_tstamp(struct ice_pf *pf, bool on) - continue; - vsi->rx_rings[i]->ptp_rx = on; - } -+} -+ -+/** -+ * ice_ptp_disable_timestamp_mode - Disable current timestamp mode -+ * @pf: Board private structure -+ * -+ * Called during preparation for reset to temporarily disable timestamping on -+ * the device. Called during remove to disable timestamping while cleaning up -+ * driver resources. -+ */ -+static void ice_ptp_disable_timestamp_mode(struct ice_pf *pf) -+{ -+ struct ice_hw *hw = &pf->hw; -+ u32 val; -+ -+ val = rd32(hw, PFINT_OICR_ENA); -+ val &= ~PFINT_OICR_TSYN_TX_M; -+ wr32(hw, PFINT_OICR_ENA, val); - -- pf->ptp.tstamp_config.rx_filter = on ? HWTSTAMP_FILTER_ALL : -- HWTSTAMP_FILTER_NONE; -+ ice_set_rx_tstamp(pf, false); - } - - /** -- * ice_ptp_cfg_timestamp - Configure timestamp for init/deinit -+ * ice_ptp_restore_timestamp_mode - Restore timestamp configuration - * @pf: Board private structure -- * @ena: bool value to enable or disable time stamp - * -- * This function will configure timestamping during PTP initialization -- * and deinitialization -+ * Called at the end of rebuild to restore timestamp configuration after -+ * a device reset. - */ --void ice_ptp_cfg_timestamp(struct ice_pf *pf, bool ena) -+void ice_ptp_restore_timestamp_mode(struct ice_pf *pf) - { -- ice_set_tx_tstamp(pf, ena); -- ice_set_rx_tstamp(pf, ena); -+ struct ice_hw *hw = &pf->hw; -+ bool enable_rx; -+ -+ ice_ptp_cfg_tx_interrupt(pf); -+ -+ enable_rx = pf->ptp.tstamp_config.rx_filter == HWTSTAMP_FILTER_ALL; -+ ice_set_rx_tstamp(pf, enable_rx); -+ -+ /* Trigger an immediate software interrupt to ensure that timestamps -+ * which occurred during reset are handled now. -+ */ -+ wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M); -+ ice_flush(hw); - } - - /** -@@ -2037,10 +2058,10 @@ ice_ptp_set_timestamp_mode(struct ice_pf *pf, struct hwtstamp_config *config) - { - switch (config->tx_type) { - case HWTSTAMP_TX_OFF: -- ice_set_tx_tstamp(pf, false); -+ pf->ptp.tstamp_config.tx_type = HWTSTAMP_TX_OFF; - break; - case HWTSTAMP_TX_ON: -- ice_set_tx_tstamp(pf, true); -+ pf->ptp.tstamp_config.tx_type = HWTSTAMP_TX_ON; - break; - default: - return -ERANGE; -@@ -2048,7 +2069,7 @@ ice_ptp_set_timestamp_mode(struct ice_pf *pf, struct hwtstamp_config *config) - - switch (config->rx_filter) { - case HWTSTAMP_FILTER_NONE: -- ice_set_rx_tstamp(pf, false); -+ pf->ptp.tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; - break; - case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: - case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: -@@ -2064,12 +2085,15 @@ ice_ptp_set_timestamp_mode(struct ice_pf *pf, struct hwtstamp_config *config) - case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: - case HWTSTAMP_FILTER_NTP_ALL: - case HWTSTAMP_FILTER_ALL: -- ice_set_rx_tstamp(pf, true); -+ pf->ptp.tstamp_config.rx_filter = HWTSTAMP_FILTER_ALL; - break; - default: - return -ERANGE; - } - -+ /* Immediately update the device timestamping mode */ -+ ice_ptp_restore_timestamp_mode(pf); -+ - return 0; - } - -@@ -2737,7 +2761,7 @@ void ice_ptp_prepare_for_reset(struct ice_pf *pf) - clear_bit(ICE_FLAG_PTP, pf->flags); - - /* Disable timestamping for both Tx and Rx */ -- ice_ptp_cfg_timestamp(pf, false); -+ ice_ptp_disable_timestamp_mode(pf); - - kthread_cancel_delayed_work_sync(&ptp->work); - -@@ -2803,15 +2827,7 @@ static int ice_ptp_init_owner(struct ice_pf *pf) - /* Release the global hardware lock */ - ice_ptp_unlock(hw); - -- if (pf->ptp.tx_interrupt_mode == ICE_PTP_TX_INTERRUPT_ALL) { -- /* The clock owner for this device type handles the timestamp -- * interrupt for all ports. -- */ -- ice_ptp_configure_tx_tstamp(pf, true); -- -- /* React on all quads interrupts for E82x */ -- wr32(hw, PFINT_TSYN_MSK + (0x4 * hw->pf_id), (u32)0x1f); -- -+ if (!ice_is_e810(hw)) { - /* Enable quad interrupts */ - err = ice_ptp_tx_ena_intr(pf, true, itr); - if (err) -@@ -2881,13 +2897,6 @@ static int ice_ptp_init_port(struct ice_pf *pf, struct ice_ptp_port *ptp_port) - case ICE_PHY_E810: - return ice_ptp_init_tx_e810(pf, &ptp_port->tx); - case ICE_PHY_E822: -- /* Non-owner PFs don't react to any interrupts on E82x, -- * neither on own quad nor on others -- */ -- if (!ice_ptp_pf_handles_tx_interrupt(pf)) { -- ice_ptp_configure_tx_tstamp(pf, false); -- wr32(hw, PFINT_TSYN_MSK + (0x4 * hw->pf_id), (u32)0x0); -- } - kthread_init_delayed_work(&ptp_port->ov_work, - ice_ptp_wait_for_offsets); - -@@ -3032,6 +3041,9 @@ void ice_ptp_init(struct ice_pf *pf) - /* Start the PHY timestamping block */ - ice_ptp_reset_phy_timestamping(pf); - -+ /* Configure initial Tx interrupt settings */ -+ ice_ptp_cfg_tx_interrupt(pf); -+ - set_bit(ICE_FLAG_PTP, pf->flags); - err = ice_ptp_init_work(pf, ptp); - if (err) -@@ -3067,7 +3079,7 @@ void ice_ptp_release(struct ice_pf *pf) - return; - - /* Disable timestamping for both Tx and Rx */ -- ice_ptp_cfg_timestamp(pf, false); -+ ice_ptp_disable_timestamp_mode(pf); - - ice_ptp_remove_auxbus_device(pf); - -diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h -index 8f6f9439275..06a330867fc 100644 ---- a/drivers/net/ethernet/intel/ice/ice_ptp.h -+++ b/drivers/net/ethernet/intel/ice/ice_ptp.h -@@ -292,7 +292,7 @@ int ice_ptp_clock_index(struct ice_pf *pf); - struct ice_pf; - int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr); - int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr); --void ice_ptp_cfg_timestamp(struct ice_pf *pf, bool ena); -+void ice_ptp_restore_timestamp_mode(struct ice_pf *pf); - - void ice_ptp_extts_event(struct ice_pf *pf); - s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb); -@@ -317,8 +317,7 @@ static inline int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr) - return -EOPNOTSUPP; - } - --static inline void ice_ptp_cfg_timestamp(struct ice_pf *pf, bool ena) { } -- -+static inline void ice_ptp_restore_timestamp_mode(struct ice_pf *pf) { } - static inline void ice_ptp_extts_event(struct ice_pf *pf) { } - static inline s8 - ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb) -diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c -index 52d0a126eb6..9e97ea86306 100644 ---- a/drivers/net/ethernet/intel/ice/ice_txrx.c -+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c -@@ -2306,9 +2306,6 @@ ice_tstamp(struct ice_tx_ring *tx_ring, struct sk_buff *skb, - if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))) - return; - -- if (!tx_ring->ptp_tx) -- return; -- - /* Tx timestamps cannot be sampled when doing TSO */ - if (first->tx_flags & ICE_TX_FLAGS_TSO) - return; -diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h -index 166413fc33f..daf7b9dbb14 100644 ---- a/drivers/net/ethernet/intel/ice/ice_txrx.h -+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h -@@ -380,7 +380,6 @@ struct ice_tx_ring { - #define ICE_TX_FLAGS_RING_VLAN_L2TAG2 BIT(2) - u8 flags; - u8 dcb_tc; /* Traffic class of ring */ -- u8 ptp_tx; - } ____cacheline_internodealigned_in_smp; - - static inline bool ice_ring_uses_build_skb(struct ice_rx_ring *ring) -diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c -index 4762dbea64a..97a71e9b856 100644 ---- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c -+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c -@@ -1088,6 +1088,7 @@ int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc) - struct ethhdr *eth_hdr; - bool new = false; - int err = 0; -+ u64 vf_num; - u32 ring; - - if (!flow_cfg->max_flows) { -@@ -1100,7 +1101,21 @@ int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc) - if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT)) - return -ENOMEM; - -- if (ring >= pfvf->hw.rx_queues && fsp->ring_cookie != RX_CLS_FLOW_DISC) -+ /* Number of queues on a VF can be greater or less than -+ * the PF's queue. Hence no need to check for the -+ * queue count. Hence no need to check queue count if PF -+ * is installing for its VF. Below is the expected vf_num value -+ * based on the ethtool commands. -+ * -+ * e.g. -+ * 1. ethtool -U ... action -1 ==> vf_num:255 -+ * 2. ethtool -U ... action ==> vf_num:0 -+ * 3. ethtool -U ... vf queue ==> -+ * vf_num:vf_idx+1 -+ */ -+ vf_num = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie); -+ if (!is_otx2_vf(pfvf->pcifunc) && !vf_num && -+ ring >= pfvf->hw.rx_queues && fsp->ring_cookie != RX_CLS_FLOW_DISC) - return -EINVAL; - - if (fsp->location >= otx2_get_maxflows(flow_cfg)) -@@ -1182,6 +1197,9 @@ int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc) - flow_cfg->nr_flows++; - } - -+ if (flow->is_vf) -+ netdev_info(pfvf->netdev, -+ "Make sure that VF's queue number is within its queue limit\n"); - return 0; - } - -diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c -index 91b99fd7036..ba95ac91327 100644 ---- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c -+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c -@@ -1934,6 +1934,8 @@ int otx2_stop(struct net_device *netdev) - /* Clear RSS enable flag */ - rss = &pf->hw.rss_info; - rss->enable = false; -+ if (!netif_is_rxfh_configured(netdev)) -+ kfree(rss->rss_ctx[DEFAULT_RSS_CONTEXT_GROUP]); - - /* Cleanup Queue IRQ */ - vec = pci_irq_vector(pf->pdev, -diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c -index b9bb1d2f023..295366a85c6 100644 ---- a/drivers/net/ethernet/realtek/r8169_main.c -+++ b/drivers/net/ethernet/realtek/r8169_main.c -@@ -2599,9 +2599,7 @@ static void rtl_set_rx_mode(struct net_device *dev) - rx_mode &= ~AcceptMulticast; - } else if (netdev_mc_count(dev) > MC_FILTER_LIMIT || - dev->flags & IFF_ALLMULTI || -- tp->mac_version == RTL_GIGA_MAC_VER_35 || -- tp->mac_version == RTL_GIGA_MAC_VER_46 || -- tp->mac_version == RTL_GIGA_MAC_VER_48) { -+ tp->mac_version == RTL_GIGA_MAC_VER_35) { - /* accept all multicasts */ - } else if (netdev_mc_empty(dev)) { - rx_mode &= ~AcceptMulticast; -diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig -index a2b9e289aa3..85dcda51df0 100644 ---- a/drivers/net/ethernet/stmicro/stmmac/Kconfig -+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig -@@ -280,7 +280,7 @@ config DWMAC_INTEL - config DWMAC_LOONGSON - tristate "Loongson PCI DWMAC support" - default MACH_LOONGSON64 -- depends on STMMAC_ETH && PCI -+ depends on (MACH_LOONGSON64 || COMPILE_TEST) && STMMAC_ETH && PCI - depends on COMMON_CLK - help - This selects the LOONGSON PCI bus support for the stmmac driver, -diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c -index a3c5de9d547..533e912af08 100644 ---- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c -+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c -@@ -1769,10 +1769,12 @@ int wx_sw_init(struct wx *wx) - wx->subsystem_device_id = pdev->subsystem_device; - } else { - err = wx_flash_read_dword(wx, 0xfffdc, &ssid); -- if (!err) -- wx->subsystem_device_id = swab16((u16)ssid); -+ if (err < 0) { -+ wx_err(wx, "read of internal subsystem device id failed\n"); -+ return err; -+ } - -- return err; -+ wx->subsystem_device_id = swab16((u16)ssid); - } - - wx->mac_table = kcalloc(wx->mac.num_rar_entries, -diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c -index 3d43f808c86..8db804543e6 100644 ---- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c -+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c -@@ -121,10 +121,8 @@ static int ngbe_sw_init(struct wx *wx) - - /* PCI config space info */ - err = wx_sw_init(wx); -- if (err < 0) { -- wx_err(wx, "read of internal subsystem device id failed\n"); -+ if (err < 0) - return err; -- } - - /* mac type, phy type , oem type */ - ngbe_init_type_code(wx); -diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c -index 70f0b5c01da..526250102db 100644 ---- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c -+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c -@@ -364,10 +364,8 @@ static int txgbe_sw_init(struct wx *wx) - - /* PCI config space info */ - err = wx_sw_init(wx); -- if (err < 0) { -- wx_err(wx, "read of internal subsystem device id failed\n"); -+ if (err < 0) - return err; -- } - - txgbe_init_type_code(wx); - -diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c -index 82d0d44b2b0..bf6e3399049 100644 ---- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c -+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c -@@ -822,7 +822,7 @@ axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev) - if (lp->features & XAE_FEATURE_FULL_TX_CSUM) { - /* Tx Full Checksum Offload Enabled */ - cur_p->app0 |= 2; -- } else if (lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) { -+ } else if (lp->features & XAE_FEATURE_PARTIAL_TX_CSUM) { - csum_start_off = skb_transport_offset(skb); - csum_index_off = csum_start_off + skb->csum_offset; - /* Tx Partial Checksum Offload Enabled */ -diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c -index 3ba3c8fb28a..706ea5263e8 100644 ---- a/drivers/net/hyperv/netvsc_drv.c -+++ b/drivers/net/hyperv/netvsc_drv.c -@@ -2206,9 +2206,6 @@ static int netvsc_vf_join(struct net_device *vf_netdev, - goto upper_link_failed; - } - -- /* set slave flag before open to prevent IPv6 addrconf */ -- vf_netdev->flags |= IFF_SLAVE; -- - schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT); - - call_netdevice_notifiers(NETDEV_JOIN, vf_netdev); -@@ -2315,16 +2312,18 @@ static struct net_device *get_netvsc_byslot(const struct net_device *vf_netdev) - - } - -- /* Fallback path to check synthetic vf with -- * help of mac addr -+ /* Fallback path to check synthetic vf with help of mac addr. -+ * Because this function can be called before vf_netdev is -+ * initialized (NETDEV_POST_INIT) when its perm_addr has not been copied -+ * from dev_addr, also try to match to its dev_addr. -+ * Note: On Hyper-V and Azure, it's not possible to set a MAC address -+ * on a VF that matches to the MAC of a unrelated NETVSC device. - */ - list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) { - ndev = hv_get_drvdata(ndev_ctx->device_ctx); -- if (ether_addr_equal(vf_netdev->perm_addr, ndev->perm_addr)) { -- netdev_notice(vf_netdev, -- "falling back to mac addr based matching\n"); -+ if (ether_addr_equal(vf_netdev->perm_addr, ndev->perm_addr) || -+ ether_addr_equal(vf_netdev->dev_addr, ndev->perm_addr)) - return ndev; -- } - } - - netdev_notice(vf_netdev, -@@ -2332,6 +2331,19 @@ static struct net_device *get_netvsc_byslot(const struct net_device *vf_netdev) - return NULL; - } - -+static int netvsc_prepare_bonding(struct net_device *vf_netdev) -+{ -+ struct net_device *ndev; -+ -+ ndev = get_netvsc_byslot(vf_netdev); -+ if (!ndev) -+ return NOTIFY_DONE; -+ -+ /* set slave flag before open to prevent IPv6 addrconf */ -+ vf_netdev->flags |= IFF_SLAVE; -+ return NOTIFY_DONE; -+} -+ - static int netvsc_register_vf(struct net_device *vf_netdev) - { - struct net_device_context *net_device_ctx; -@@ -2531,15 +2543,6 @@ static int netvsc_probe(struct hv_device *dev, - goto devinfo_failed; - } - -- nvdev = rndis_filter_device_add(dev, device_info); -- if (IS_ERR(nvdev)) { -- ret = PTR_ERR(nvdev); -- netdev_err(net, "unable to add netvsc device (ret %d)\n", ret); -- goto rndis_failed; -- } -- -- eth_hw_addr_set(net, device_info->mac_adr); -- - /* We must get rtnl lock before scheduling nvdev->subchan_work, - * otherwise netvsc_subchan_work() can get rtnl lock first and wait - * all subchannels to show up, but that may not happen because -@@ -2547,9 +2550,23 @@ static int netvsc_probe(struct hv_device *dev, - * -> ... -> device_add() -> ... -> __device_attach() can't get - * the device lock, so all the subchannels can't be processed -- - * finally netvsc_subchan_work() hangs forever. -+ * -+ * The rtnl lock also needs to be held before rndis_filter_device_add() -+ * which advertises nvsp_2_vsc_capability / sriov bit, and triggers -+ * VF NIC offering and registering. If VF NIC finished register_netdev() -+ * earlier it may cause name based config failure. - */ - rtnl_lock(); - -+ nvdev = rndis_filter_device_add(dev, device_info); -+ if (IS_ERR(nvdev)) { -+ ret = PTR_ERR(nvdev); -+ netdev_err(net, "unable to add netvsc device (ret %d)\n", ret); -+ goto rndis_failed; -+ } -+ -+ eth_hw_addr_set(net, device_info->mac_adr); -+ - if (nvdev->num_chn > 1) - schedule_work(&nvdev->subchan_work); - -@@ -2586,9 +2603,9 @@ static int netvsc_probe(struct hv_device *dev, - return 0; - - register_failed: -- rtnl_unlock(); - rndis_filter_device_remove(dev, nvdev); - rndis_failed: -+ rtnl_unlock(); - netvsc_devinfo_put(device_info); - devinfo_failed: - free_percpu(net_device_ctx->vf_stats); -@@ -2753,6 +2770,8 @@ static int netvsc_netdev_event(struct notifier_block *this, - return NOTIFY_DONE; - - switch (event) { -+ case NETDEV_POST_INIT: -+ return netvsc_prepare_bonding(event_dev); - case NETDEV_REGISTER: - return netvsc_register_vf(event_dev); - case NETDEV_UNREGISTER: -@@ -2788,12 +2807,17 @@ static int __init netvsc_drv_init(void) - } - netvsc_ring_bytes = ring_size * PAGE_SIZE; - -+ register_netdevice_notifier(&netvsc_netdev_notifier); -+ - ret = vmbus_driver_register(&netvsc_drv); - if (ret) -- return ret; -+ goto err_vmbus_reg; - -- register_netdevice_notifier(&netvsc_netdev_notifier); - return 0; -+ -+err_vmbus_reg: -+ unregister_netdevice_notifier(&netvsc_netdev_notifier); -+ return ret; - } - - MODULE_LICENSE("GPL"); -diff --git a/drivers/net/ipa/reg/gsi_reg-v5.0.c b/drivers/net/ipa/reg/gsi_reg-v5.0.c -index d7b81a36d67..145eb0bd096 100644 ---- a/drivers/net/ipa/reg/gsi_reg-v5.0.c -+++ b/drivers/net/ipa/reg/gsi_reg-v5.0.c -@@ -78,7 +78,7 @@ REG_STRIDE_FIELDS(EV_CH_E_CNTXT_0, ev_ch_e_cntxt_0, - 0x0001c000 + 0x12000 * GSI_EE_AP, 0x80); - - static const u32 reg_ev_ch_e_cntxt_1_fmask[] = { -- [R_LENGTH] = GENMASK(19, 0), -+ [R_LENGTH] = GENMASK(23, 0), - }; - - REG_STRIDE_FIELDS(EV_CH_E_CNTXT_1, ev_ch_e_cntxt_1, -diff --git a/drivers/net/netkit.c b/drivers/net/netkit.c -index 5a0f86f38f0..97bd6705c24 100644 ---- a/drivers/net/netkit.c -+++ b/drivers/net/netkit.c -@@ -7,6 +7,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -68,6 +69,7 @@ static netdev_tx_t netkit_xmit(struct sk_buff *skb, struct net_device *dev) - netdev_tx_t ret_dev = NET_XMIT_SUCCESS; - const struct bpf_mprog_entry *entry; - struct net_device *peer; -+ int len = skb->len; - - rcu_read_lock(); - peer = rcu_dereference(nk->peer); -@@ -85,15 +87,22 @@ static netdev_tx_t netkit_xmit(struct sk_buff *skb, struct net_device *dev) - case NETKIT_PASS: - skb->protocol = eth_type_trans(skb, skb->dev); - skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); -- __netif_rx(skb); -+ if (likely(__netif_rx(skb) == NET_RX_SUCCESS)) { -+ dev_sw_netstats_tx_add(dev, 1, len); -+ dev_sw_netstats_rx_add(peer, len); -+ } else { -+ goto drop_stats; -+ } - break; - case NETKIT_REDIRECT: -+ dev_sw_netstats_tx_add(dev, 1, len); - skb_do_redirect(skb); - break; - case NETKIT_DROP: - default: - drop: - kfree_skb(skb); -+drop_stats: - dev_core_stats_tx_dropped_inc(dev); - ret_dev = NET_XMIT_DROP; - break; -@@ -169,11 +178,18 @@ static void netkit_set_headroom(struct net_device *dev, int headroom) - rcu_read_unlock(); - } - --static struct net_device *netkit_peer_dev(struct net_device *dev) -+INDIRECT_CALLABLE_SCOPE struct net_device *netkit_peer_dev(struct net_device *dev) - { - return rcu_dereference(netkit_priv(dev)->peer); - } - -+static void netkit_get_stats(struct net_device *dev, -+ struct rtnl_link_stats64 *stats) -+{ -+ dev_fetch_sw_netstats(stats, dev->tstats); -+ stats->tx_dropped = DEV_STATS_READ(dev, tx_dropped); -+} -+ - static void netkit_uninit(struct net_device *dev); - - static const struct net_device_ops netkit_netdev_ops = { -@@ -184,6 +200,7 @@ static const struct net_device_ops netkit_netdev_ops = { - .ndo_set_rx_headroom = netkit_set_headroom, - .ndo_get_iflink = netkit_get_iflink, - .ndo_get_peer_dev = netkit_peer_dev, -+ .ndo_get_stats64 = netkit_get_stats, - .ndo_uninit = netkit_uninit, - .ndo_features_check = passthru_features_check, - }; -@@ -218,6 +235,7 @@ static void netkit_setup(struct net_device *dev) - - ether_setup(dev); - dev->max_mtu = ETH_MAX_MTU; -+ dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; - - dev->flags |= IFF_NOARP; - dev->priv_flags &= ~IFF_TX_SKB_SHARING; -diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c -index a017e9de211..7b8afa589a5 100644 ---- a/drivers/net/usb/aqc111.c -+++ b/drivers/net/usb/aqc111.c -@@ -1079,17 +1079,17 @@ static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb) - u16 pkt_count = 0; - u64 desc_hdr = 0; - u16 vlan_tag = 0; -- u32 skb_len = 0; -+ u32 skb_len; - - if (!skb) - goto err; - -- if (skb->len == 0) -+ skb_len = skb->len; -+ if (skb_len < sizeof(desc_hdr)) - goto err; - -- skb_len = skb->len; - /* RX Descriptor Header */ -- skb_trim(skb, skb->len - sizeof(desc_hdr)); -+ skb_trim(skb, skb_len - sizeof(desc_hdr)); - desc_hdr = le64_to_cpup((u64 *)skb_tail_pointer(skb)); - - /* Check these packets */ -diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c -index aff39bf3161..4ea0e155bb0 100644 ---- a/drivers/net/usb/ax88179_178a.c -+++ b/drivers/net/usb/ax88179_178a.c -@@ -1583,11 +1583,11 @@ static int ax88179_reset(struct usbnet *dev) - - *tmp16 = AX_PHYPWR_RSTCTL_IPRL; - ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); -- msleep(200); -+ msleep(500); - - *tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS; - ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp); -- msleep(100); -+ msleep(200); - - /* Ethernet PHY Auto Detach*/ - ax88179_auto_detach(dev); -diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c -index 344af3c5c83..e2e181378f4 100644 ---- a/drivers/net/usb/qmi_wwan.c -+++ b/drivers/net/usb/qmi_wwan.c -@@ -1289,6 +1289,7 @@ static const struct usb_device_id products[] = { - {QMI_FIXED_INTF(0x19d2, 0x0168, 4)}, - {QMI_FIXED_INTF(0x19d2, 0x0176, 3)}, - {QMI_FIXED_INTF(0x19d2, 0x0178, 3)}, -+ {QMI_FIXED_INTF(0x19d2, 0x0189, 4)}, /* ZTE MF290 */ - {QMI_FIXED_INTF(0x19d2, 0x0191, 4)}, /* ZTE EuFi890 */ - {QMI_FIXED_INTF(0x19d2, 0x0199, 1)}, /* ZTE MF820S */ - {QMI_FIXED_INTF(0x19d2, 0x0200, 1)}, -diff --git a/drivers/net/veth.c b/drivers/net/veth.c -index 9980517ed8b..57efb3454c5 100644 ---- a/drivers/net/veth.c -+++ b/drivers/net/veth.c -@@ -236,8 +236,8 @@ static void veth_get_ethtool_stats(struct net_device *dev, - data[tx_idx + j] += *(u64 *)(base + offset); - } - } while (u64_stats_fetch_retry(&rq_stats->syncp, start)); -- pp_idx = tx_idx + VETH_TQ_STATS_LEN; - } -+ pp_idx = idx + dev->real_num_tx_queues * VETH_TQ_STATS_LEN; - - page_pool_stats: - veth_get_page_pool_stats(dev, &data[pp_idx]); -@@ -373,7 +373,7 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) - skb_tx_timestamp(skb); - if (likely(veth_forward_skb(rcv, skb, rq, use_napi) == NET_RX_SUCCESS)) { - if (!use_napi) -- dev_lstats_add(dev, length); -+ dev_sw_netstats_tx_add(dev, 1, length); - else - __veth_xdp_flush(rq); - } else { -@@ -387,14 +387,6 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) - return ret; - } - --static u64 veth_stats_tx(struct net_device *dev, u64 *packets, u64 *bytes) --{ -- struct veth_priv *priv = netdev_priv(dev); -- -- dev_lstats_read(dev, packets, bytes); -- return atomic64_read(&priv->dropped); --} -- - static void veth_stats_rx(struct veth_stats *result, struct net_device *dev) - { - struct veth_priv *priv = netdev_priv(dev); -@@ -432,24 +424,24 @@ static void veth_get_stats64(struct net_device *dev, - struct veth_priv *priv = netdev_priv(dev); - struct net_device *peer; - struct veth_stats rx; -- u64 packets, bytes; - -- tot->tx_dropped = veth_stats_tx(dev, &packets, &bytes); -- tot->tx_bytes = bytes; -- tot->tx_packets = packets; -+ tot->tx_dropped = atomic64_read(&priv->dropped); -+ dev_fetch_sw_netstats(tot, dev->tstats); - - veth_stats_rx(&rx, dev); - tot->tx_dropped += rx.xdp_tx_err; - tot->rx_dropped = rx.rx_drops + rx.peer_tq_xdp_xmit_err; -- tot->rx_bytes = rx.xdp_bytes; -- tot->rx_packets = rx.xdp_packets; -+ tot->rx_bytes += rx.xdp_bytes; -+ tot->rx_packets += rx.xdp_packets; - - rcu_read_lock(); - peer = rcu_dereference(priv->peer); - if (peer) { -- veth_stats_tx(peer, &packets, &bytes); -- tot->rx_bytes += bytes; -- tot->rx_packets += packets; -+ struct rtnl_link_stats64 tot_peer = {}; -+ -+ dev_fetch_sw_netstats(&tot_peer, peer->tstats); -+ tot->rx_bytes += tot_peer.tx_bytes; -+ tot->rx_packets += tot_peer.tx_packets; - - veth_stats_rx(&rx, peer); - tot->tx_dropped += rx.peer_tq_xdp_xmit_err; -@@ -1506,25 +1498,12 @@ static void veth_free_queues(struct net_device *dev) - - static int veth_dev_init(struct net_device *dev) - { -- int err; -- -- dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); -- if (!dev->lstats) -- return -ENOMEM; -- -- err = veth_alloc_queues(dev); -- if (err) { -- free_percpu(dev->lstats); -- return err; -- } -- -- return 0; -+ return veth_alloc_queues(dev); - } - - static void veth_dev_free(struct net_device *dev) - { - veth_free_queues(dev); -- free_percpu(dev->lstats); - } - - #ifdef CONFIG_NET_POLL_CONTROLLER -@@ -1796,6 +1775,7 @@ static void veth_setup(struct net_device *dev) - NETIF_F_HW_VLAN_STAG_RX); - dev->needs_free_netdev = true; - dev->priv_destructor = veth_dev_free; -+ dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; - dev->max_mtu = ETH_MAX_MTU; - - dev->hw_features = VETH_FEATURES; -diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c -index db766941b78..bb95ce43cd9 100644 ---- a/drivers/net/vrf.c -+++ b/drivers/net/vrf.c -@@ -121,22 +121,12 @@ struct net_vrf { - int ifindex; - }; - --struct pcpu_dstats { -- u64 tx_pkts; -- u64 tx_bytes; -- u64 tx_drps; -- u64 rx_pkts; -- u64 rx_bytes; -- u64 rx_drps; -- struct u64_stats_sync syncp; --}; -- - static void vrf_rx_stats(struct net_device *dev, int len) - { - struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats); - - u64_stats_update_begin(&dstats->syncp); -- dstats->rx_pkts++; -+ dstats->rx_packets++; - dstats->rx_bytes += len; - u64_stats_update_end(&dstats->syncp); - } -@@ -161,10 +151,10 @@ static void vrf_get_stats64(struct net_device *dev, - do { - start = u64_stats_fetch_begin(&dstats->syncp); - tbytes = dstats->tx_bytes; -- tpkts = dstats->tx_pkts; -- tdrops = dstats->tx_drps; -+ tpkts = dstats->tx_packets; -+ tdrops = dstats->tx_drops; - rbytes = dstats->rx_bytes; -- rpkts = dstats->rx_pkts; -+ rpkts = dstats->rx_packets; - } while (u64_stats_fetch_retry(&dstats->syncp, start)); - stats->tx_bytes += tbytes; - stats->tx_packets += tpkts; -@@ -421,7 +411,7 @@ static int vrf_local_xmit(struct sk_buff *skb, struct net_device *dev, - if (likely(__netif_rx(skb) == NET_RX_SUCCESS)) - vrf_rx_stats(dev, len); - else -- this_cpu_inc(dev->dstats->rx_drps); -+ this_cpu_inc(dev->dstats->rx_drops); - - return NETDEV_TX_OK; - } -@@ -616,11 +606,11 @@ static netdev_tx_t vrf_xmit(struct sk_buff *skb, struct net_device *dev) - struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats); - - u64_stats_update_begin(&dstats->syncp); -- dstats->tx_pkts++; -+ dstats->tx_packets++; - dstats->tx_bytes += len; - u64_stats_update_end(&dstats->syncp); - } else { -- this_cpu_inc(dev->dstats->tx_drps); -+ this_cpu_inc(dev->dstats->tx_drops); - } - - return ret; -@@ -1174,22 +1164,15 @@ static void vrf_dev_uninit(struct net_device *dev) - - vrf_rtable_release(dev, vrf); - vrf_rt6_release(dev, vrf); -- -- free_percpu(dev->dstats); -- dev->dstats = NULL; - } - - static int vrf_dev_init(struct net_device *dev) - { - struct net_vrf *vrf = netdev_priv(dev); - -- dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats); -- if (!dev->dstats) -- goto out_nomem; -- - /* create the default dst which points back to us */ - if (vrf_rtable_create(dev) != 0) -- goto out_stats; -+ goto out_nomem; - - if (vrf_rt6_create(dev) != 0) - goto out_rth; -@@ -1203,9 +1186,6 @@ static int vrf_dev_init(struct net_device *dev) - - out_rth: - vrf_rtable_release(dev, vrf); --out_stats: -- free_percpu(dev->dstats); -- dev->dstats = NULL; - out_nomem: - return -ENOMEM; - } -@@ -1704,6 +1684,8 @@ static void vrf_setup(struct net_device *dev) - dev->min_mtu = IPV6_MIN_MTU; - dev->max_mtu = IP6_MAX_MTU; - dev->mtu = dev->max_mtu; -+ -+ dev->pcpu_stat_type = NETDEV_PCPU_STAT_DSTATS; - } - - static int vrf_validate(struct nlattr *tb[], struct nlattr *data[], -diff --git a/drivers/net/wireguard/device.c b/drivers/net/wireguard/device.c -index 258dcc10392..deb9636b0ec 100644 ---- a/drivers/net/wireguard/device.c -+++ b/drivers/net/wireguard/device.c -@@ -210,7 +210,7 @@ static netdev_tx_t wg_xmit(struct sk_buff *skb, struct net_device *dev) - */ - while (skb_queue_len(&peer->staged_packet_queue) > MAX_STAGED_PACKETS) { - dev_kfree_skb(__skb_dequeue(&peer->staged_packet_queue)); -- ++dev->stats.tx_dropped; -+ DEV_STATS_INC(dev, tx_dropped); - } - skb_queue_splice_tail(&packets, &peer->staged_packet_queue); - spin_unlock_bh(&peer->staged_packet_queue.lock); -@@ -228,7 +228,7 @@ static netdev_tx_t wg_xmit(struct sk_buff *skb, struct net_device *dev) - else if (skb->protocol == htons(ETH_P_IPV6)) - icmpv6_ndo_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); - err: -- ++dev->stats.tx_errors; -+ DEV_STATS_INC(dev, tx_errors); - kfree_skb(skb); - return ret; - } -diff --git a/drivers/net/wireguard/receive.c b/drivers/net/wireguard/receive.c -index 0b3f0c84355..a176653c886 100644 ---- a/drivers/net/wireguard/receive.c -+++ b/drivers/net/wireguard/receive.c -@@ -416,20 +416,20 @@ static void wg_packet_consume_data_done(struct wg_peer *peer, - net_dbg_skb_ratelimited("%s: Packet has unallowed src IP (%pISc) from peer %llu (%pISpfsc)\n", - dev->name, skb, peer->internal_id, - &peer->endpoint.addr); -- ++dev->stats.rx_errors; -- ++dev->stats.rx_frame_errors; -+ DEV_STATS_INC(dev, rx_errors); -+ DEV_STATS_INC(dev, rx_frame_errors); - goto packet_processed; - dishonest_packet_type: - net_dbg_ratelimited("%s: Packet is neither ipv4 nor ipv6 from peer %llu (%pISpfsc)\n", - dev->name, peer->internal_id, &peer->endpoint.addr); -- ++dev->stats.rx_errors; -- ++dev->stats.rx_frame_errors; -+ DEV_STATS_INC(dev, rx_errors); -+ DEV_STATS_INC(dev, rx_frame_errors); - goto packet_processed; - dishonest_packet_size: - net_dbg_ratelimited("%s: Packet has incorrect size from peer %llu (%pISpfsc)\n", - dev->name, peer->internal_id, &peer->endpoint.addr); -- ++dev->stats.rx_errors; -- ++dev->stats.rx_length_errors; -+ DEV_STATS_INC(dev, rx_errors); -+ DEV_STATS_INC(dev, rx_length_errors); - goto packet_processed; - packet_processed: - dev_kfree_skb(skb); -diff --git a/drivers/net/wireguard/send.c b/drivers/net/wireguard/send.c -index 95c853b59e1..0d48e0f4a1b 100644 ---- a/drivers/net/wireguard/send.c -+++ b/drivers/net/wireguard/send.c -@@ -333,7 +333,8 @@ static void wg_packet_create_data(struct wg_peer *peer, struct sk_buff *first) - void wg_packet_purge_staged_packets(struct wg_peer *peer) - { - spin_lock_bh(&peer->staged_packet_queue.lock); -- peer->device->dev->stats.tx_dropped += peer->staged_packet_queue.qlen; -+ DEV_STATS_ADD(peer->device->dev, tx_dropped, -+ peer->staged_packet_queue.qlen); - __skb_queue_purge(&peer->staged_packet_queue); - spin_unlock_bh(&peer->staged_packet_queue.lock); - } diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 52c1a3de8da..0334be061bc 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c @@ -14585,2776 +13721,8 @@ index d4bce170769..403f35af34c 100644 }; struct clk_bulk_data; -diff --git a/drivers/nfc/virtual_ncidev.c b/drivers/nfc/virtual_ncidev.c -index b027be0b0b6..590b038e449 100644 ---- a/drivers/nfc/virtual_ncidev.c -+++ b/drivers/nfc/virtual_ncidev.c -@@ -26,10 +26,14 @@ struct virtual_nci_dev { - struct mutex mtx; - struct sk_buff *send_buff; - struct wait_queue_head wq; -+ bool running; - }; - - static int virtual_nci_open(struct nci_dev *ndev) - { -+ struct virtual_nci_dev *vdev = nci_get_drvdata(ndev); -+ -+ vdev->running = true; - return 0; - } - -@@ -40,6 +44,7 @@ static int virtual_nci_close(struct nci_dev *ndev) - mutex_lock(&vdev->mtx); - kfree_skb(vdev->send_buff); - vdev->send_buff = NULL; -+ vdev->running = false; - mutex_unlock(&vdev->mtx); - - return 0; -@@ -50,7 +55,7 @@ static int virtual_nci_send(struct nci_dev *ndev, struct sk_buff *skb) - struct virtual_nci_dev *vdev = nci_get_drvdata(ndev); - - mutex_lock(&vdev->mtx); -- if (vdev->send_buff) { -+ if (vdev->send_buff || !vdev->running) { - mutex_unlock(&vdev->mtx); - kfree_skb(skb); - return -1; -diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c -index 48328e36e93..72c0525c75f 100644 ---- a/drivers/nvme/host/auth.c -+++ b/drivers/nvme/host/auth.c -@@ -757,12 +757,11 @@ static void nvme_queue_auth_work(struct work_struct *work) - __func__, chap->qid); - mutex_lock(&ctrl->dhchap_auth_mutex); - ret = nvme_auth_dhchap_setup_host_response(ctrl, chap); -+ mutex_unlock(&ctrl->dhchap_auth_mutex); - if (ret) { -- mutex_unlock(&ctrl->dhchap_auth_mutex); - chap->error = ret; - goto fail2; - } -- mutex_unlock(&ctrl->dhchap_auth_mutex); - - /* DH-HMAC-CHAP Step 3: send reply */ - dev_dbg(ctrl->device, "%s: qid %d send reply\n", -@@ -839,6 +838,8 @@ static void nvme_queue_auth_work(struct work_struct *work) - } - - fail2: -+ if (chap->status == 0) -+ chap->status = NVME_AUTH_DHCHAP_FAILURE_FAILED; - dev_dbg(ctrl->device, "%s: qid %d send failure2, status %x\n", - __func__, chap->qid, chap->status); - tl = nvme_auth_set_dhchap_failure2_data(ctrl, chap); -diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c -index 88b54cdcbd6..46a4c9c5ea9 100644 ---- a/drivers/nvme/host/core.c -+++ b/drivers/nvme/host/core.c -@@ -482,7 +482,6 @@ EXPORT_SYMBOL_GPL(nvme_cancel_tagset); - - void nvme_cancel_admin_tagset(struct nvme_ctrl *ctrl) - { -- nvme_stop_keep_alive(ctrl); - if (ctrl->admin_tagset) { - blk_mq_tagset_busy_iter(ctrl->admin_tagset, - nvme_cancel_request, ctrl); -@@ -1814,16 +1813,18 @@ static int nvme_init_ms(struct nvme_ns *ns, struct nvme_id_ns *id) - return ret; - } - --static void nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id) -+static int nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id) - { - struct nvme_ctrl *ctrl = ns->ctrl; -+ int ret; - -- if (nvme_init_ms(ns, id)) -- return; -+ ret = nvme_init_ms(ns, id); -+ if (ret) -+ return ret; - - ns->features &= ~(NVME_NS_METADATA_SUPPORTED | NVME_NS_EXT_LBAS); - if (!ns->ms || !(ctrl->ops->flags & NVME_F_METADATA_SUPPORTED)) -- return; -+ return 0; - - if (ctrl->ops->flags & NVME_F_FABRICS) { - /* -@@ -1832,7 +1833,7 @@ static void nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id) - * remap the separate metadata buffer from the block layer. - */ - if (WARN_ON_ONCE(!(id->flbas & NVME_NS_FLBAS_META_EXT))) -- return; -+ return 0; - - ns->features |= NVME_NS_EXT_LBAS; - -@@ -1859,6 +1860,7 @@ static void nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id) - else - ns->features |= NVME_NS_METADATA_SUPPORTED; - } -+ return 0; - } - - static void nvme_set_queue_limits(struct nvme_ctrl *ctrl, -@@ -2032,7 +2034,11 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns, - ns->lba_shift = id->lbaf[lbaf].ds; - nvme_set_queue_limits(ns->ctrl, ns->queue); - -- nvme_configure_metadata(ns, id); -+ ret = nvme_configure_metadata(ns, id); -+ if (ret < 0) { -+ blk_mq_unfreeze_queue(ns->disk->queue); -+ goto out; -+ } - nvme_set_chunk_sectors(ns, id); - nvme_update_disk_info(ns->disk, ns, id); - -@@ -4348,6 +4354,7 @@ void nvme_stop_ctrl(struct nvme_ctrl *ctrl) - { - nvme_mpath_stop(ctrl); - nvme_auth_stop(ctrl); -+ nvme_stop_keep_alive(ctrl); - nvme_stop_failfast_work(ctrl); - flush_work(&ctrl->async_event_work); - cancel_work_sync(&ctrl->fw_act_work); -diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c -index 4673ead69c5..aa88606a44c 100644 ---- a/drivers/nvme/host/fabrics.c -+++ b/drivers/nvme/host/fabrics.c -@@ -667,8 +667,10 @@ static const match_table_t opt_tokens = { - #endif - { NVMF_OPT_FAIL_FAST_TMO, "fast_io_fail_tmo=%d" }, - { NVMF_OPT_DISCOVERY, "discovery" }, -+#ifdef CONFIG_NVME_HOST_AUTH - { NVMF_OPT_DHCHAP_SECRET, "dhchap_secret=%s" }, - { NVMF_OPT_DHCHAP_CTRL_SECRET, "dhchap_ctrl_secret=%s" }, -+#endif - #ifdef CONFIG_NVME_TCP_TLS - { NVMF_OPT_TLS, "tls" }, - #endif -diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c -index 49c3e46eaa1..9f9a3b35dc6 100644 ---- a/drivers/nvme/host/fc.c -+++ b/drivers/nvme/host/fc.c -@@ -2530,12 +2530,6 @@ __nvme_fc_abort_outstanding_ios(struct nvme_fc_ctrl *ctrl, bool start_queues) - * clean up the admin queue. Same thing as above. - */ - nvme_quiesce_admin_queue(&ctrl->ctrl); -- -- /* -- * Open-coding nvme_cancel_admin_tagset() as fc -- * is not using nvme_cancel_request(). -- */ -- nvme_stop_keep_alive(&ctrl->ctrl); - blk_sync_queue(ctrl->ctrl.admin_q); - blk_mq_tagset_busy_iter(&ctrl->admin_tag_set, - nvme_fc_terminate_exchange, &ctrl->ctrl); -@@ -3138,11 +3132,12 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) - nvme_unquiesce_admin_queue(&ctrl->ctrl); - - ret = nvme_init_ctrl_finish(&ctrl->ctrl, false); -- if (!ret && test_bit(ASSOC_FAILED, &ctrl->flags)) -- ret = -EIO; - if (ret) - goto out_disconnect_admin_queue; -- -+ if (test_bit(ASSOC_FAILED, &ctrl->flags)) { -+ ret = -EIO; -+ goto out_stop_keep_alive; -+ } - /* sanity checks */ - - /* FC-NVME does not have other data in the capsule */ -@@ -3150,7 +3145,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) - dev_err(ctrl->ctrl.device, "icdoff %d is not supported!\n", - ctrl->ctrl.icdoff); - ret = NVME_SC_INVALID_FIELD | NVME_SC_DNR; -- goto out_disconnect_admin_queue; -+ goto out_stop_keep_alive; - } - - /* FC-NVME supports normal SGL Data Block Descriptors */ -@@ -3158,7 +3153,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) - dev_err(ctrl->ctrl.device, - "Mandatory sgls are not supported!\n"); - ret = NVME_SC_INVALID_FIELD | NVME_SC_DNR; -- goto out_disconnect_admin_queue; -+ goto out_stop_keep_alive; - } - - if (opts->queue_size > ctrl->ctrl.maxcmd) { -@@ -3205,6 +3200,8 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) - - out_term_aen_ops: - nvme_fc_term_aen_ops(ctrl); -+out_stop_keep_alive: -+ nvme_stop_keep_alive(&ctrl->ctrl); - out_disconnect_admin_queue: - dev_warn(ctrl->ctrl.device, - "NVME-FC{%d}: create_assoc failed, assoc_id %llx ret %d\n", -diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c -index a7fea4cbacd..6d178d55592 100644 ---- a/drivers/nvme/host/rdma.c -+++ b/drivers/nvme/host/rdma.c -@@ -1080,6 +1080,7 @@ static int nvme_rdma_setup_ctrl(struct nvme_rdma_ctrl *ctrl, bool new) - nvme_rdma_free_io_queues(ctrl); - } - destroy_admin: -+ nvme_stop_keep_alive(&ctrl->ctrl); - nvme_quiesce_admin_queue(&ctrl->ctrl); - blk_sync_queue(ctrl->ctrl.admin_q); - nvme_rdma_stop_queue(&ctrl->queues[0]); -diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c -index 89661a9cf85..d79811cfa0c 100644 ---- a/drivers/nvme/host/tcp.c -+++ b/drivers/nvme/host/tcp.c -@@ -36,11 +36,11 @@ static int so_priority; - module_param(so_priority, int, 0644); - MODULE_PARM_DESC(so_priority, "nvme tcp socket optimize priority"); - --#ifdef CONFIG_NVME_TCP_TLS - /* - * TLS handshake timeout - */ - static int tls_handshake_timeout = 10; -+#ifdef CONFIG_NVME_TCP_TLS - module_param(tls_handshake_timeout, int, 0644); - MODULE_PARM_DESC(tls_handshake_timeout, - "nvme TLS handshake timeout in seconds (default 10)"); -@@ -161,10 +161,8 @@ struct nvme_tcp_queue { - struct ahash_request *snd_hash; - __le32 exp_ddgst; - __le32 recv_ddgst; --#ifdef CONFIG_NVME_TCP_TLS - struct completion tls_complete; - int tls_err; --#endif - struct page_frag_cache pf_cache; - - void (*state_change)(struct sock *); -@@ -207,6 +205,14 @@ static inline int nvme_tcp_queue_id(struct nvme_tcp_queue *queue) - return queue - queue->ctrl->queues; - } - -+static inline bool nvme_tcp_tls(struct nvme_ctrl *ctrl) -+{ -+ if (!IS_ENABLED(CONFIG_NVME_TCP_TLS)) -+ return 0; -+ -+ return ctrl->opts->tls; -+} -+ - static inline struct blk_mq_tags *nvme_tcp_tagset(struct nvme_tcp_queue *queue) - { - u32 queue_idx = nvme_tcp_queue_id(queue); -@@ -1412,7 +1418,7 @@ static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue) - memset(&msg, 0, sizeof(msg)); - iov.iov_base = icresp; - iov.iov_len = sizeof(*icresp); -- if (queue->ctrl->ctrl.opts->tls) { -+ if (nvme_tcp_tls(&queue->ctrl->ctrl)) { - msg.msg_control = cbuf; - msg.msg_controllen = sizeof(cbuf); - } -@@ -1424,7 +1430,7 @@ static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue) - goto free_icresp; - } - ret = -ENOTCONN; -- if (queue->ctrl->ctrl.opts->tls) { -+ if (nvme_tcp_tls(&queue->ctrl->ctrl)) { - ctype = tls_get_record_type(queue->sock->sk, - (struct cmsghdr *)cbuf); - if (ctype != TLS_RECORD_TYPE_DATA) { -@@ -1548,7 +1554,6 @@ static void nvme_tcp_set_queue_io_cpu(struct nvme_tcp_queue *queue) - queue->io_cpu = cpumask_next_wrap(n - 1, cpu_online_mask, -1, false); - } - --#ifdef CONFIG_NVME_TCP_TLS - static void nvme_tcp_tls_done(void *data, int status, key_serial_t pskid) - { - struct nvme_tcp_queue *queue = data; -@@ -1625,14 +1630,6 @@ static int nvme_tcp_start_tls(struct nvme_ctrl *nctrl, - } - return ret; - } --#else --static int nvme_tcp_start_tls(struct nvme_ctrl *nctrl, -- struct nvme_tcp_queue *queue, -- key_serial_t pskid) --{ -- return -EPROTONOSUPPORT; --} --#endif - - static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid, - key_serial_t pskid) -@@ -1759,7 +1756,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid, - } - - /* If PSKs are configured try to start TLS */ -- if (pskid) { -+ if (IS_ENABLED(CONFIG_NVME_TCP_TLS) && pskid) { - ret = nvme_tcp_start_tls(nctrl, queue, pskid); - if (ret) - goto err_init_connect; -@@ -1916,7 +1913,7 @@ static int nvme_tcp_alloc_admin_queue(struct nvme_ctrl *ctrl) - int ret; - key_serial_t pskid = 0; - -- if (ctrl->opts->tls) { -+ if (nvme_tcp_tls(ctrl)) { - if (ctrl->opts->tls_key) - pskid = key_serial(ctrl->opts->tls_key); - else -@@ -1949,7 +1946,7 @@ static int __nvme_tcp_alloc_io_queues(struct nvme_ctrl *ctrl) - { - int i, ret; - -- if (ctrl->opts->tls && !ctrl->tls_key) { -+ if (nvme_tcp_tls(ctrl) && !ctrl->tls_key) { - dev_err(ctrl->device, "no PSK negotiated\n"); - return -ENOKEY; - } -@@ -2237,6 +2234,7 @@ static int nvme_tcp_setup_ctrl(struct nvme_ctrl *ctrl, bool new) - nvme_tcp_destroy_io_queues(ctrl, new); - } - destroy_admin: -+ nvme_stop_keep_alive(ctrl); - nvme_tcp_teardown_admin_queue(ctrl, false); - return ret; - } -diff --git a/drivers/nvme/target/Kconfig b/drivers/nvme/target/Kconfig -index 31633da9427..e1ebc73f3e5 100644 ---- a/drivers/nvme/target/Kconfig -+++ b/drivers/nvme/target/Kconfig -@@ -4,6 +4,8 @@ config NVME_TARGET - tristate "NVMe Target support" - depends on BLOCK - depends on CONFIGFS_FS -+ select NVME_KEYRING if NVME_TARGET_TCP_TLS -+ select KEYS if NVME_TARGET_TCP_TLS - select BLK_DEV_INTEGRITY_T10 if BLK_DEV_INTEGRITY - select SGL_ALLOC - help -@@ -87,9 +89,7 @@ config NVME_TARGET_TCP - config NVME_TARGET_TCP_TLS - bool "NVMe over Fabrics TCP target TLS encryption support" - depends on NVME_TARGET_TCP -- select NVME_KEYRING - select NET_HANDSHAKE -- select KEYS - help - Enables TLS encryption for the NVMe TCP target using the netlink handshake API. - -diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c -index 9eed6e6765e..e307a044b1a 100644 ---- a/drivers/nvme/target/configfs.c -+++ b/drivers/nvme/target/configfs.c -@@ -1893,7 +1893,7 @@ static struct config_group *nvmet_ports_make(struct config_group *group, - return ERR_PTR(-ENOMEM); - } - -- if (nvme_keyring_id()) { -+ if (IS_ENABLED(CONFIG_NVME_TARGET_TCP_TLS) && nvme_keyring_id()) { - port->keyring = key_lookup(nvme_keyring_id()); - if (IS_ERR(port->keyring)) { - pr_warn("NVMe keyring not available, disabling TLS\n"); -diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c -index 43b5bd8bb6a..d8da840a1c0 100644 ---- a/drivers/nvme/target/fabrics-cmd.c -+++ b/drivers/nvme/target/fabrics-cmd.c -@@ -244,6 +244,8 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req) - goto out; - } - -+ d->subsysnqn[NVMF_NQN_FIELD_LEN - 1] = '\0'; -+ d->hostnqn[NVMF_NQN_FIELD_LEN - 1] = '\0'; - status = nvmet_alloc_ctrl(d->subsysnqn, d->hostnqn, req, - le32_to_cpu(c->kato), &ctrl); - if (status) -@@ -313,6 +315,8 @@ static void nvmet_execute_io_connect(struct nvmet_req *req) - goto out; - } - -+ d->subsysnqn[NVMF_NQN_FIELD_LEN - 1] = '\0'; -+ d->hostnqn[NVMF_NQN_FIELD_LEN - 1] = '\0'; - ctrl = nvmet_ctrl_find_get(d->subsysnqn, d->hostnqn, - le16_to_cpu(d->cntlid), req); - if (!ctrl) { -diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c -index 92b74d0b868..4cc27856aa8 100644 ---- a/drivers/nvme/target/tcp.c -+++ b/drivers/nvme/target/tcp.c -@@ -1854,6 +1854,8 @@ static int nvmet_tcp_tls_handshake(struct nvmet_tcp_queue *queue) - } - return ret; - } -+#else -+static void nvmet_tcp_tls_handshake_timeout(struct work_struct *w) {} - #endif - - static void nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port, -@@ -1911,9 +1913,9 @@ static void nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port, - list_add_tail(&queue->queue_list, &nvmet_tcp_queue_list); - mutex_unlock(&nvmet_tcp_queue_mutex); - --#ifdef CONFIG_NVME_TARGET_TCP_TLS - INIT_DELAYED_WORK(&queue->tls_handshake_tmo_work, - nvmet_tcp_tls_handshake_timeout); -+#ifdef CONFIG_NVME_TARGET_TCP_TLS - if (queue->state == NVMET_TCP_Q_TLS_HANDSHAKE) { - struct sock *sk = queue->sock->sk; - -diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig -index 787354b849c..4cef568231b 100644 ---- a/drivers/phy/Kconfig -+++ b/drivers/phy/Kconfig -@@ -87,7 +87,6 @@ source "drivers/phy/motorola/Kconfig" - source "drivers/phy/mscc/Kconfig" - source "drivers/phy/qualcomm/Kconfig" - source "drivers/phy/ralink/Kconfig" --source "drivers/phy/realtek/Kconfig" - source "drivers/phy/renesas/Kconfig" - source "drivers/phy/rockchip/Kconfig" - source "drivers/phy/samsung/Kconfig" -diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile -index 868a220ed0f..fb3dc9de611 100644 ---- a/drivers/phy/Makefile -+++ b/drivers/phy/Makefile -@@ -26,7 +26,6 @@ obj-y += allwinner/ \ - mscc/ \ - qualcomm/ \ - ralink/ \ -- realtek/ \ - renesas/ \ - rockchip/ \ - samsung/ \ -diff --git a/drivers/phy/realtek/Kconfig b/drivers/phy/realtek/Kconfig -deleted file mode 100644 -index 75ac7e7c31a..00000000000 ---- a/drivers/phy/realtek/Kconfig -+++ /dev/null -@@ -1,32 +0,0 @@ --# SPDX-License-Identifier: GPL-2.0 --# --# Phy drivers for Realtek platforms --# -- --if ARCH_REALTEK || COMPILE_TEST -- --config PHY_RTK_RTD_USB2PHY -- tristate "Realtek RTD USB2 PHY Transceiver Driver" -- depends on USB_SUPPORT -- select GENERIC_PHY -- select USB_PHY -- select USB_COMMON -- help -- Enable this to support Realtek SoC USB2 phy transceiver. -- The DHC (digital home center) RTD series SoCs used the Synopsys -- DWC3 USB IP. This driver will do the PHY initialization -- of the parameters. -- --config PHY_RTK_RTD_USB3PHY -- tristate "Realtek RTD USB3 PHY Transceiver Driver" -- depends on USB_SUPPORT -- select GENERIC_PHY -- select USB_PHY -- select USB_COMMON -- help -- Enable this to support Realtek SoC USB3 phy transceiver. -- The DHC (digital home center) RTD series SoCs used the Synopsys -- DWC3 USB IP. This driver will do the PHY initialization -- of the parameters. -- --endif # ARCH_REALTEK || COMPILE_TEST -diff --git a/drivers/phy/realtek/Makefile b/drivers/phy/realtek/Makefile -deleted file mode 100644 -index ed7b47ff8a2..00000000000 ---- a/drivers/phy/realtek/Makefile -+++ /dev/null -@@ -1,3 +0,0 @@ --# SPDX-License-Identifier: GPL-2.0 --obj-$(CONFIG_PHY_RTK_RTD_USB2PHY) += phy-rtk-usb2.o --obj-$(CONFIG_PHY_RTK_RTD_USB3PHY) += phy-rtk-usb3.o -diff --git a/drivers/phy/realtek/phy-rtk-usb2.c b/drivers/phy/realtek/phy-rtk-usb2.c -deleted file mode 100644 -index 0a6426285c6..00000000000 ---- a/drivers/phy/realtek/phy-rtk-usb2.c -+++ /dev/null -@@ -1,1325 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/* -- * phy-rtk-usb2.c RTK usb2.0 PHY driver -- * -- * Copyright (C) 2023 Realtek Semiconductor Corporation -- * -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --/* GUSB2PHYACCn register */ --#define PHY_NEW_REG_REQ BIT(25) --#define PHY_VSTS_BUSY BIT(23) --#define PHY_VCTRL_SHIFT 8 --#define PHY_REG_DATA_MASK 0xff -- --#define GET_LOW_NIBBLE(addr) ((addr) & 0x0f) --#define GET_HIGH_NIBBLE(addr) (((addr) & 0xf0) >> 4) -- --#define EFUS_USB_DC_CAL_RATE 2 --#define EFUS_USB_DC_CAL_MAX 7 -- --#define EFUS_USB_DC_DIS_RATE 1 --#define EFUS_USB_DC_DIS_MAX 7 -- --#define MAX_PHY_DATA_SIZE 20 --#define OFFEST_PHY_READ 0x20 -- --#define MAX_USB_PHY_NUM 4 --#define MAX_USB_PHY_PAGE0_DATA_SIZE 16 --#define MAX_USB_PHY_PAGE1_DATA_SIZE 16 --#define MAX_USB_PHY_PAGE2_DATA_SIZE 8 -- --#define SET_PAGE_OFFSET 0xf4 --#define SET_PAGE_0 0x9b --#define SET_PAGE_1 0xbb --#define SET_PAGE_2 0xdb -- --#define PAGE_START 0xe0 --#define PAGE0_0XE4 0xe4 --#define PAGE0_0XE6 0xe6 --#define PAGE0_0XE7 0xe7 --#define PAGE1_0XE0 0xe0 --#define PAGE1_0XE2 0xe2 -- --#define SENSITIVITY_CTRL (BIT(4) | BIT(5) | BIT(6)) --#define ENABLE_AUTO_SENSITIVITY_CALIBRATION BIT(2) --#define DEFAULT_DC_DRIVING_VALUE (0x8) --#define DEFAULT_DC_DISCONNECTION_VALUE (0x6) --#define HS_CLK_SELECT BIT(6) -- --struct phy_reg { -- void __iomem *reg_wrap_vstatus; -- void __iomem *reg_gusb2phyacc0; -- int vstatus_index; --}; -- --struct phy_data { -- u8 addr; -- u8 data; --}; -- --struct phy_cfg { -- int page0_size; -- struct phy_data page0[MAX_USB_PHY_PAGE0_DATA_SIZE]; -- int page1_size; -- struct phy_data page1[MAX_USB_PHY_PAGE1_DATA_SIZE]; -- int page2_size; -- struct phy_data page2[MAX_USB_PHY_PAGE2_DATA_SIZE]; -- -- int num_phy; -- -- bool check_efuse; -- int check_efuse_version; --#define CHECK_EFUSE_V1 1 --#define CHECK_EFUSE_V2 2 -- int efuse_dc_driving_rate; -- int efuse_dc_disconnect_rate; -- int dc_driving_mask; -- int dc_disconnect_mask; -- bool usb_dc_disconnect_at_page0; -- int driving_updated_for_dev_dis; -- -- bool do_toggle; -- bool do_toggle_driving; -- bool use_default_parameter; -- bool is_double_sensitivity_mode; --}; -- --struct phy_parameter { -- struct phy_reg phy_reg; -- -- /* Get from efuse */ -- s8 efuse_usb_dc_cal; -- s8 efuse_usb_dc_dis; -- -- /* Get from dts */ -- bool inverse_hstx_sync_clock; -- u32 driving_level; -- s32 driving_level_compensate; -- s32 disconnection_compensate; --}; -- --struct rtk_phy { -- struct usb_phy phy; -- struct device *dev; -- -- struct phy_cfg *phy_cfg; -- int num_phy; -- struct phy_parameter *phy_parameter; -- -- struct dentry *debug_dir; --}; -- --/* mapping 0xE0 to 0 ... 0xE7 to 7, 0xF0 to 8 ,,, 0xF7 to 15 */ --static inline int page_addr_to_array_index(u8 addr) --{ -- return (int)((((addr) - PAGE_START) & 0x7) + -- ((((addr) - PAGE_START) & 0x10) >> 1)); --} -- --static inline u8 array_index_to_page_addr(int index) --{ -- return ((((index) + PAGE_START) & 0x7) + -- ((((index) & 0x8) << 1) + PAGE_START)); --} -- --#define PHY_IO_TIMEOUT_USEC (50000) --#define PHY_IO_DELAY_US (100) -- --static inline int utmi_wait_register(void __iomem *reg, u32 mask, u32 result) --{ -- int ret; -- unsigned int val; -- -- ret = read_poll_timeout(readl, val, ((val & mask) == result), -- PHY_IO_DELAY_US, PHY_IO_TIMEOUT_USEC, false, reg); -- if (ret) { -- pr_err("%s can't program USB phy\n", __func__); -- return -ETIMEDOUT; -- } -- -- return 0; --} -- --static char rtk_phy_read(struct phy_reg *phy_reg, char addr) --{ -- void __iomem *reg_gusb2phyacc0 = phy_reg->reg_gusb2phyacc0; -- unsigned int val; -- int ret = 0; -- -- addr -= OFFEST_PHY_READ; -- -- /* polling until VBusy == 0 */ -- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0); -- if (ret) -- return (char)ret; -- -- /* VCtrl = low nibble of addr, and set PHY_NEW_REG_REQ */ -- val = PHY_NEW_REG_REQ | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT); -- writel(val, reg_gusb2phyacc0); -- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0); -- if (ret) -- return (char)ret; -- -- /* VCtrl = high nibble of addr, and set PHY_NEW_REG_REQ */ -- val = PHY_NEW_REG_REQ | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT); -- writel(val, reg_gusb2phyacc0); -- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0); -- if (ret) -- return (char)ret; -- -- val = readl(reg_gusb2phyacc0); -- -- return (char)(val & PHY_REG_DATA_MASK); --} -- --static int rtk_phy_write(struct phy_reg *phy_reg, char addr, char data) --{ -- unsigned int val; -- void __iomem *reg_wrap_vstatus = phy_reg->reg_wrap_vstatus; -- void __iomem *reg_gusb2phyacc0 = phy_reg->reg_gusb2phyacc0; -- int shift_bits = phy_reg->vstatus_index * 8; -- int ret = 0; -- -- /* write data to VStatusOut2 (data output to phy) */ -- writel((u32)data << shift_bits, reg_wrap_vstatus); -- -- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0); -- if (ret) -- return ret; -- -- /* VCtrl = low nibble of addr, set PHY_NEW_REG_REQ */ -- val = PHY_NEW_REG_REQ | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT); -- -- writel(val, reg_gusb2phyacc0); -- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0); -- if (ret) -- return ret; -- -- /* VCtrl = high nibble of addr, set PHY_NEW_REG_REQ */ -- val = PHY_NEW_REG_REQ | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT); -- -- writel(val, reg_gusb2phyacc0); -- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0); -- if (ret) -- return ret; -- -- return 0; --} -- --static int rtk_phy_set_page(struct phy_reg *phy_reg, int page) --{ -- switch (page) { -- case 0: -- return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_0); -- case 1: -- return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_1); -- case 2: -- return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_2); -- default: -- pr_err("%s error page=%d\n", __func__, page); -- } -- -- return -EINVAL; --} -- --static u8 __updated_dc_disconnect_level_page0_0xe4(struct phy_cfg *phy_cfg, -- struct phy_parameter *phy_parameter, u8 data) --{ -- u8 ret; -- s32 val; -- s32 dc_disconnect_mask = phy_cfg->dc_disconnect_mask; -- int offset = 4; -- -- val = (s32)((data >> offset) & dc_disconnect_mask) -- + phy_parameter->efuse_usb_dc_dis -- + phy_parameter->disconnection_compensate; -- -- if (val > dc_disconnect_mask) -- val = dc_disconnect_mask; -- else if (val < 0) -- val = 0; -- -- ret = (data & (~(dc_disconnect_mask << offset))) | -- (val & dc_disconnect_mask) << offset; -- -- return ret; --} -- --/* updated disconnect level at page0 */ --static void update_dc_disconnect_level_at_page0(struct rtk_phy *rtk_phy, -- struct phy_parameter *phy_parameter, bool update) --{ -- struct phy_cfg *phy_cfg; -- struct phy_reg *phy_reg; -- struct phy_data *phy_data_page; -- struct phy_data *phy_data; -- u8 addr, data; -- int offset = 4; -- s32 dc_disconnect_mask; -- int i; -- -- phy_cfg = rtk_phy->phy_cfg; -- phy_reg = &phy_parameter->phy_reg; -- -- /* Set page 0 */ -- phy_data_page = phy_cfg->page0; -- rtk_phy_set_page(phy_reg, 0); -- -- i = page_addr_to_array_index(PAGE0_0XE4); -- phy_data = phy_data_page + i; -- if (!phy_data->addr) { -- phy_data->addr = PAGE0_0XE4; -- phy_data->data = rtk_phy_read(phy_reg, PAGE0_0XE4); -- } -- -- addr = phy_data->addr; -- data = phy_data->data; -- dc_disconnect_mask = phy_cfg->dc_disconnect_mask; -- -- if (update) -- data = __updated_dc_disconnect_level_page0_0xe4(phy_cfg, phy_parameter, data); -- else -- data = (data & ~(dc_disconnect_mask << offset)) | -- (DEFAULT_DC_DISCONNECTION_VALUE << offset); -- -- if (rtk_phy_write(phy_reg, addr, data)) -- dev_err(rtk_phy->dev, -- "%s: Error to set page1 parameter addr=0x%x value=0x%x\n", -- __func__, addr, data); --} -- --static u8 __updated_dc_disconnect_level_page1_0xe2(struct phy_cfg *phy_cfg, -- struct phy_parameter *phy_parameter, u8 data) --{ -- u8 ret; -- s32 val; -- s32 dc_disconnect_mask = phy_cfg->dc_disconnect_mask; -- -- if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) { -- val = (s32)(data & dc_disconnect_mask) -- + phy_parameter->efuse_usb_dc_dis -- + phy_parameter->disconnection_compensate; -- } else { /* for CHECK_EFUSE_V2 or no efuse */ -- if (phy_parameter->efuse_usb_dc_dis) -- val = (s32)(phy_parameter->efuse_usb_dc_dis + -- phy_parameter->disconnection_compensate); -- else -- val = (s32)((data & dc_disconnect_mask) + -- phy_parameter->disconnection_compensate); -- } -- -- if (val > dc_disconnect_mask) -- val = dc_disconnect_mask; -- else if (val < 0) -- val = 0; -- -- ret = (data & (~dc_disconnect_mask)) | (val & dc_disconnect_mask); -- -- return ret; --} -- --/* updated disconnect level at page1 */ --static void update_dc_disconnect_level_at_page1(struct rtk_phy *rtk_phy, -- struct phy_parameter *phy_parameter, bool update) --{ -- struct phy_cfg *phy_cfg; -- struct phy_data *phy_data_page; -- struct phy_data *phy_data; -- struct phy_reg *phy_reg; -- u8 addr, data; -- s32 dc_disconnect_mask; -- int i; -- -- phy_cfg = rtk_phy->phy_cfg; -- phy_reg = &phy_parameter->phy_reg; -- -- /* Set page 1 */ -- phy_data_page = phy_cfg->page1; -- rtk_phy_set_page(phy_reg, 1); -- -- i = page_addr_to_array_index(PAGE1_0XE2); -- phy_data = phy_data_page + i; -- if (!phy_data->addr) { -- phy_data->addr = PAGE1_0XE2; -- phy_data->data = rtk_phy_read(phy_reg, PAGE1_0XE2); -- } -- -- addr = phy_data->addr; -- data = phy_data->data; -- dc_disconnect_mask = phy_cfg->dc_disconnect_mask; -- -- if (update) -- data = __updated_dc_disconnect_level_page1_0xe2(phy_cfg, phy_parameter, data); -- else -- data = (data & ~dc_disconnect_mask) | DEFAULT_DC_DISCONNECTION_VALUE; -- -- if (rtk_phy_write(phy_reg, addr, data)) -- dev_err(rtk_phy->dev, -- "%s: Error to set page1 parameter addr=0x%x value=0x%x\n", -- __func__, addr, data); --} -- --static void update_dc_disconnect_level(struct rtk_phy *rtk_phy, -- struct phy_parameter *phy_parameter, bool update) --{ -- struct phy_cfg *phy_cfg = rtk_phy->phy_cfg; -- -- if (phy_cfg->usb_dc_disconnect_at_page0) -- update_dc_disconnect_level_at_page0(rtk_phy, phy_parameter, update); -- else -- update_dc_disconnect_level_at_page1(rtk_phy, phy_parameter, update); --} -- --static u8 __update_dc_driving_page0_0xe4(struct phy_cfg *phy_cfg, -- struct phy_parameter *phy_parameter, u8 data) --{ -- s32 driving_level_compensate = phy_parameter->driving_level_compensate; -- s32 dc_driving_mask = phy_cfg->dc_driving_mask; -- s32 val; -- u8 ret; -- -- if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) { -- val = (s32)(data & dc_driving_mask) + driving_level_compensate -- + phy_parameter->efuse_usb_dc_cal; -- } else { /* for CHECK_EFUSE_V2 or no efuse */ -- if (phy_parameter->efuse_usb_dc_cal) -- val = (s32)((phy_parameter->efuse_usb_dc_cal & dc_driving_mask) -- + driving_level_compensate); -- else -- val = (s32)(data & dc_driving_mask); -- } -- -- if (val > dc_driving_mask) -- val = dc_driving_mask; -- else if (val < 0) -- val = 0; -- -- ret = (data & (~dc_driving_mask)) | (val & dc_driving_mask); -- -- return ret; --} -- --static void update_dc_driving_level(struct rtk_phy *rtk_phy, -- struct phy_parameter *phy_parameter) --{ -- struct phy_cfg *phy_cfg; -- struct phy_reg *phy_reg; -- -- phy_reg = &phy_parameter->phy_reg; -- phy_cfg = rtk_phy->phy_cfg; -- if (!phy_cfg->page0[4].addr) { -- rtk_phy_set_page(phy_reg, 0); -- phy_cfg->page0[4].addr = PAGE0_0XE4; -- phy_cfg->page0[4].data = rtk_phy_read(phy_reg, PAGE0_0XE4); -- } -- -- if (phy_parameter->driving_level != DEFAULT_DC_DRIVING_VALUE) { -- u32 dc_driving_mask; -- u8 driving_level; -- u8 data; -- -- data = phy_cfg->page0[4].data; -- dc_driving_mask = phy_cfg->dc_driving_mask; -- driving_level = data & dc_driving_mask; -- -- dev_dbg(rtk_phy->dev, "%s driving_level=%d => dts driving_level=%d\n", -- __func__, driving_level, phy_parameter->driving_level); -- -- phy_cfg->page0[4].data = (data & (~dc_driving_mask)) | -- (phy_parameter->driving_level & dc_driving_mask); -- } -- -- phy_cfg->page0[4].data = __update_dc_driving_page0_0xe4(phy_cfg, -- phy_parameter, -- phy_cfg->page0[4].data); --} -- --static void update_hs_clk_select(struct rtk_phy *rtk_phy, -- struct phy_parameter *phy_parameter) --{ -- struct phy_cfg *phy_cfg; -- struct phy_reg *phy_reg; -- -- phy_cfg = rtk_phy->phy_cfg; -- phy_reg = &phy_parameter->phy_reg; -- -- if (phy_parameter->inverse_hstx_sync_clock) { -- if (!phy_cfg->page0[6].addr) { -- rtk_phy_set_page(phy_reg, 0); -- phy_cfg->page0[6].addr = PAGE0_0XE6; -- phy_cfg->page0[6].data = rtk_phy_read(phy_reg, PAGE0_0XE6); -- } -- -- phy_cfg->page0[6].data = phy_cfg->page0[6].data | HS_CLK_SELECT; -- } --} -- --static void do_rtk_phy_toggle(struct rtk_phy *rtk_phy, -- int index, bool connect) --{ -- struct phy_parameter *phy_parameter; -- struct phy_cfg *phy_cfg; -- struct phy_reg *phy_reg; -- struct phy_data *phy_data_page; -- u8 addr, data; -- int i; -- -- phy_cfg = rtk_phy->phy_cfg; -- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; -- phy_reg = &phy_parameter->phy_reg; -- -- if (!phy_cfg->do_toggle) -- goto out; -- -- if (phy_cfg->is_double_sensitivity_mode) -- goto do_toggle_driving; -- -- /* Set page 0 */ -- rtk_phy_set_page(phy_reg, 0); -- -- addr = PAGE0_0XE7; -- data = rtk_phy_read(phy_reg, addr); -- -- if (connect) -- rtk_phy_write(phy_reg, addr, data & (~SENSITIVITY_CTRL)); -- else -- rtk_phy_write(phy_reg, addr, data | (SENSITIVITY_CTRL)); -- --do_toggle_driving: -- -- if (!phy_cfg->do_toggle_driving) -- goto do_toggle; -- -- /* Page 0 addr 0xE4 driving capability */ -- -- /* Set page 0 */ -- phy_data_page = phy_cfg->page0; -- rtk_phy_set_page(phy_reg, 0); -- -- i = page_addr_to_array_index(PAGE0_0XE4); -- addr = phy_data_page[i].addr; -- data = phy_data_page[i].data; -- -- if (connect) { -- rtk_phy_write(phy_reg, addr, data); -- } else { -- u8 value; -- s32 tmp; -- s32 driving_updated = -- phy_cfg->driving_updated_for_dev_dis; -- s32 dc_driving_mask = phy_cfg->dc_driving_mask; -- -- tmp = (s32)(data & dc_driving_mask) + driving_updated; -- -- if (tmp > dc_driving_mask) -- tmp = dc_driving_mask; -- else if (tmp < 0) -- tmp = 0; -- -- value = (data & (~dc_driving_mask)) | (tmp & dc_driving_mask); -- -- rtk_phy_write(phy_reg, addr, value); -- } -- --do_toggle: -- /* restore dc disconnect level before toggle */ -- update_dc_disconnect_level(rtk_phy, phy_parameter, false); -- -- /* Set page 1 */ -- rtk_phy_set_page(phy_reg, 1); -- -- addr = PAGE1_0XE0; -- data = rtk_phy_read(phy_reg, addr); -- -- rtk_phy_write(phy_reg, addr, data & -- (~ENABLE_AUTO_SENSITIVITY_CALIBRATION)); -- mdelay(1); -- rtk_phy_write(phy_reg, addr, data | -- (ENABLE_AUTO_SENSITIVITY_CALIBRATION)); -- -- /* update dc disconnect level after toggle */ -- update_dc_disconnect_level(rtk_phy, phy_parameter, true); -- --out: -- return; --} -- --static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index) --{ -- struct phy_parameter *phy_parameter; -- struct phy_cfg *phy_cfg; -- struct phy_data *phy_data_page; -- struct phy_reg *phy_reg; -- int i; -- -- phy_cfg = rtk_phy->phy_cfg; -- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; -- phy_reg = &phy_parameter->phy_reg; -- -- if (phy_cfg->use_default_parameter) { -- dev_dbg(rtk_phy->dev, "%s phy#%d use default parameter\n", -- __func__, index); -- goto do_toggle; -- } -- -- /* Set page 0 */ -- phy_data_page = phy_cfg->page0; -- rtk_phy_set_page(phy_reg, 0); -- -- for (i = 0; i < phy_cfg->page0_size; i++) { -- struct phy_data *phy_data = phy_data_page + i; -- u8 addr = phy_data->addr; -- u8 data = phy_data->data; -- -- if (!addr) -- continue; -- -- if (rtk_phy_write(phy_reg, addr, data)) { -- dev_err(rtk_phy->dev, -- "%s: Error to set page0 parameter addr=0x%x value=0x%x\n", -- __func__, addr, data); -- return -EINVAL; -- } -- } -- -- /* Set page 1 */ -- phy_data_page = phy_cfg->page1; -- rtk_phy_set_page(phy_reg, 1); -- -- for (i = 0; i < phy_cfg->page1_size; i++) { -- struct phy_data *phy_data = phy_data_page + i; -- u8 addr = phy_data->addr; -- u8 data = phy_data->data; -- -- if (!addr) -- continue; -- -- if (rtk_phy_write(phy_reg, addr, data)) { -- dev_err(rtk_phy->dev, -- "%s: Error to set page1 parameter addr=0x%x value=0x%x\n", -- __func__, addr, data); -- return -EINVAL; -- } -- } -- -- if (phy_cfg->page2_size == 0) -- goto do_toggle; -- -- /* Set page 2 */ -- phy_data_page = phy_cfg->page2; -- rtk_phy_set_page(phy_reg, 2); -- -- for (i = 0; i < phy_cfg->page2_size; i++) { -- struct phy_data *phy_data = phy_data_page + i; -- u8 addr = phy_data->addr; -- u8 data = phy_data->data; -- -- if (!addr) -- continue; -- -- if (rtk_phy_write(phy_reg, addr, data)) { -- dev_err(rtk_phy->dev, -- "%s: Error to set page2 parameter addr=0x%x value=0x%x\n", -- __func__, addr, data); -- return -EINVAL; -- } -- } -- --do_toggle: -- do_rtk_phy_toggle(rtk_phy, index, false); -- -- return 0; --} -- --static int rtk_phy_init(struct phy *phy) --{ -- struct rtk_phy *rtk_phy = phy_get_drvdata(phy); -- unsigned long phy_init_time = jiffies; -- int i, ret = 0; -- -- if (!rtk_phy) -- return -EINVAL; -- -- for (i = 0; i < rtk_phy->num_phy; i++) -- ret = do_rtk_phy_init(rtk_phy, i); -- -- dev_dbg(rtk_phy->dev, "Initialized RTK USB 2.0 PHY (take %dms)\n", -- jiffies_to_msecs(jiffies - phy_init_time)); -- return ret; --} -- --static int rtk_phy_exit(struct phy *phy) --{ -- return 0; --} -- --static const struct phy_ops ops = { -- .init = rtk_phy_init, -- .exit = rtk_phy_exit, -- .owner = THIS_MODULE, --}; -- --static void rtk_phy_toggle(struct usb_phy *usb2_phy, bool connect, int port) --{ -- int index = port; -- struct rtk_phy *rtk_phy = NULL; -- -- rtk_phy = dev_get_drvdata(usb2_phy->dev); -- -- if (index > rtk_phy->num_phy) { -- dev_err(rtk_phy->dev, "%s: The port=%d is not in usb phy (num_phy=%d)\n", -- __func__, index, rtk_phy->num_phy); -- return; -- } -- -- do_rtk_phy_toggle(rtk_phy, index, connect); --} -- --static int rtk_phy_notify_port_status(struct usb_phy *x, int port, -- u16 portstatus, u16 portchange) --{ -- bool connect = false; -- -- pr_debug("%s port=%d portstatus=0x%x portchange=0x%x\n", -- __func__, port, (int)portstatus, (int)portchange); -- if (portstatus & USB_PORT_STAT_CONNECTION) -- connect = true; -- -- if (portchange & USB_PORT_STAT_C_CONNECTION) -- rtk_phy_toggle(x, connect, port); -- -- return 0; --} -- --#ifdef CONFIG_DEBUG_FS --static struct dentry *create_phy_debug_root(void) --{ -- struct dentry *phy_debug_root; -- -- phy_debug_root = debugfs_lookup("phy", usb_debug_root); -- if (!phy_debug_root) -- phy_debug_root = debugfs_create_dir("phy", usb_debug_root); -- -- return phy_debug_root; --} -- --static int rtk_usb2_parameter_show(struct seq_file *s, void *unused) --{ -- struct rtk_phy *rtk_phy = s->private; -- struct phy_cfg *phy_cfg; -- int i, index; -- -- phy_cfg = rtk_phy->phy_cfg; -- -- seq_puts(s, "Property:\n"); -- seq_printf(s, " check_efuse: %s\n", -- phy_cfg->check_efuse ? "Enable" : "Disable"); -- seq_printf(s, " check_efuse_version: %d\n", -- phy_cfg->check_efuse_version); -- seq_printf(s, " efuse_dc_driving_rate: %d\n", -- phy_cfg->efuse_dc_driving_rate); -- seq_printf(s, " dc_driving_mask: 0x%x\n", -- phy_cfg->dc_driving_mask); -- seq_printf(s, " efuse_dc_disconnect_rate: %d\n", -- phy_cfg->efuse_dc_disconnect_rate); -- seq_printf(s, " dc_disconnect_mask: 0x%x\n", -- phy_cfg->dc_disconnect_mask); -- seq_printf(s, " usb_dc_disconnect_at_page0: %s\n", -- phy_cfg->usb_dc_disconnect_at_page0 ? "true" : "false"); -- seq_printf(s, " do_toggle: %s\n", -- phy_cfg->do_toggle ? "Enable" : "Disable"); -- seq_printf(s, " do_toggle_driving: %s\n", -- phy_cfg->do_toggle_driving ? "Enable" : "Disable"); -- seq_printf(s, " driving_updated_for_dev_dis: 0x%x\n", -- phy_cfg->driving_updated_for_dev_dis); -- seq_printf(s, " use_default_parameter: %s\n", -- phy_cfg->use_default_parameter ? "Enable" : "Disable"); -- seq_printf(s, " is_double_sensitivity_mode: %s\n", -- phy_cfg->is_double_sensitivity_mode ? "Enable" : "Disable"); -- -- for (index = 0; index < rtk_phy->num_phy; index++) { -- struct phy_parameter *phy_parameter; -- struct phy_reg *phy_reg; -- struct phy_data *phy_data_page; -- -- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; -- phy_reg = &phy_parameter->phy_reg; -- -- seq_printf(s, "PHY %d:\n", index); -- -- seq_puts(s, "Page 0:\n"); -- /* Set page 0 */ -- phy_data_page = phy_cfg->page0; -- rtk_phy_set_page(phy_reg, 0); -- -- for (i = 0; i < phy_cfg->page0_size; i++) { -- struct phy_data *phy_data = phy_data_page + i; -- u8 addr = array_index_to_page_addr(i); -- u8 data = phy_data->data; -- u8 value = rtk_phy_read(phy_reg, addr); -- -- if (phy_data->addr) -- seq_printf(s, " Page 0: addr=0x%x data=0x%02x ==> read value=0x%02x\n", -- addr, data, value); -- else -- seq_printf(s, " Page 0: addr=0x%x data=none ==> read value=0x%02x\n", -- addr, value); -- } -- -- seq_puts(s, "Page 1:\n"); -- /* Set page 1 */ -- phy_data_page = phy_cfg->page1; -- rtk_phy_set_page(phy_reg, 1); -- -- for (i = 0; i < phy_cfg->page1_size; i++) { -- struct phy_data *phy_data = phy_data_page + i; -- u8 addr = array_index_to_page_addr(i); -- u8 data = phy_data->data; -- u8 value = rtk_phy_read(phy_reg, addr); -- -- if (phy_data->addr) -- seq_printf(s, " Page 1: addr=0x%x data=0x%02x ==> read value=0x%02x\n", -- addr, data, value); -- else -- seq_printf(s, " Page 1: addr=0x%x data=none ==> read value=0x%02x\n", -- addr, value); -- } -- -- if (phy_cfg->page2_size == 0) -- goto out; -- -- seq_puts(s, "Page 2:\n"); -- /* Set page 2 */ -- phy_data_page = phy_cfg->page2; -- rtk_phy_set_page(phy_reg, 2); -- -- for (i = 0; i < phy_cfg->page2_size; i++) { -- struct phy_data *phy_data = phy_data_page + i; -- u8 addr = array_index_to_page_addr(i); -- u8 data = phy_data->data; -- u8 value = rtk_phy_read(phy_reg, addr); -- -- if (phy_data->addr) -- seq_printf(s, " Page 2: addr=0x%x data=0x%02x ==> read value=0x%02x\n", -- addr, data, value); -- else -- seq_printf(s, " Page 2: addr=0x%x data=none ==> read value=0x%02x\n", -- addr, value); -- } -- --out: -- seq_puts(s, "PHY Property:\n"); -- seq_printf(s, " efuse_usb_dc_cal: %d\n", -- (int)phy_parameter->efuse_usb_dc_cal); -- seq_printf(s, " efuse_usb_dc_dis: %d\n", -- (int)phy_parameter->efuse_usb_dc_dis); -- seq_printf(s, " inverse_hstx_sync_clock: %s\n", -- phy_parameter->inverse_hstx_sync_clock ? "Enable" : "Disable"); -- seq_printf(s, " driving_level: %d\n", -- phy_parameter->driving_level); -- seq_printf(s, " driving_level_compensate: %d\n", -- phy_parameter->driving_level_compensate); -- seq_printf(s, " disconnection_compensate: %d\n", -- phy_parameter->disconnection_compensate); -- } -- -- return 0; --} --DEFINE_SHOW_ATTRIBUTE(rtk_usb2_parameter); -- --static inline void create_debug_files(struct rtk_phy *rtk_phy) --{ -- struct dentry *phy_debug_root = NULL; -- -- phy_debug_root = create_phy_debug_root(); -- if (!phy_debug_root) -- return; -- -- rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev), -- phy_debug_root); -- -- debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy, -- &rtk_usb2_parameter_fops); -- -- return; --} -- --static inline void remove_debug_files(struct rtk_phy *rtk_phy) --{ -- debugfs_remove_recursive(rtk_phy->debug_dir); --} --#else --static inline void create_debug_files(struct rtk_phy *rtk_phy) { } --static inline void remove_debug_files(struct rtk_phy *rtk_phy) { } --#endif /* CONFIG_DEBUG_FS */ -- --static int get_phy_data_by_efuse(struct rtk_phy *rtk_phy, -- struct phy_parameter *phy_parameter, int index) --{ -- struct phy_cfg *phy_cfg = rtk_phy->phy_cfg; -- u8 value = 0; -- struct nvmem_cell *cell; -- struct soc_device_attribute rtk_soc_groot[] = { -- { .family = "Realtek Groot",}, -- { /* empty */ } }; -- -- if (!phy_cfg->check_efuse) -- goto out; -- -- /* Read efuse for usb dc cal */ -- cell = nvmem_cell_get(rtk_phy->dev, "usb-dc-cal"); -- if (IS_ERR(cell)) { -- dev_dbg(rtk_phy->dev, "%s no usb-dc-cal: %ld\n", -- __func__, PTR_ERR(cell)); -- } else { -- unsigned char *buf; -- size_t buf_size; -- -- buf = nvmem_cell_read(cell, &buf_size); -- if (!IS_ERR(buf)) { -- value = buf[0] & phy_cfg->dc_driving_mask; -- kfree(buf); -- } -- nvmem_cell_put(cell); -- } -- -- if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) { -- int rate = phy_cfg->efuse_dc_driving_rate; -- -- if (value <= EFUS_USB_DC_CAL_MAX) -- phy_parameter->efuse_usb_dc_cal = (int8_t)(value * rate); -- else -- phy_parameter->efuse_usb_dc_cal = -(int8_t) -- ((EFUS_USB_DC_CAL_MAX & value) * rate); -- -- if (soc_device_match(rtk_soc_groot)) { -- dev_dbg(rtk_phy->dev, "For groot IC we need a workaround to adjust efuse_usb_dc_cal\n"); -- -- /* We don't multiple dc_cal_rate=2 for positive dc cal compensate */ -- if (value <= EFUS_USB_DC_CAL_MAX) -- phy_parameter->efuse_usb_dc_cal = (int8_t)(value); -- -- /* We set max dc cal compensate is 0x8 if otp is 0x7 */ -- if (value == 0x7) -- phy_parameter->efuse_usb_dc_cal = (int8_t)(value + 1); -- } -- } else { /* for CHECK_EFUSE_V2 */ -- phy_parameter->efuse_usb_dc_cal = value & phy_cfg->dc_driving_mask; -- } -- -- /* Read efuse for usb dc disconnect level */ -- value = 0; -- cell = nvmem_cell_get(rtk_phy->dev, "usb-dc-dis"); -- if (IS_ERR(cell)) { -- dev_dbg(rtk_phy->dev, "%s no usb-dc-dis: %ld\n", -- __func__, PTR_ERR(cell)); -- } else { -- unsigned char *buf; -- size_t buf_size; -- -- buf = nvmem_cell_read(cell, &buf_size); -- if (!IS_ERR(buf)) { -- value = buf[0] & phy_cfg->dc_disconnect_mask; -- kfree(buf); -- } -- nvmem_cell_put(cell); -- } -- -- if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) { -- int rate = phy_cfg->efuse_dc_disconnect_rate; -- -- if (value <= EFUS_USB_DC_DIS_MAX) -- phy_parameter->efuse_usb_dc_dis = (int8_t)(value * rate); -- else -- phy_parameter->efuse_usb_dc_dis = -(int8_t) -- ((EFUS_USB_DC_DIS_MAX & value) * rate); -- } else { /* for CHECK_EFUSE_V2 */ -- phy_parameter->efuse_usb_dc_dis = value & phy_cfg->dc_disconnect_mask; -- } -- --out: -- return 0; --} -- --static int parse_phy_data(struct rtk_phy *rtk_phy) --{ -- struct device *dev = rtk_phy->dev; -- struct device_node *np = dev->of_node; -- struct phy_parameter *phy_parameter; -- int ret = 0; -- int index; -- -- rtk_phy->phy_parameter = devm_kzalloc(dev, sizeof(struct phy_parameter) * -- rtk_phy->num_phy, GFP_KERNEL); -- if (!rtk_phy->phy_parameter) -- return -ENOMEM; -- -- for (index = 0; index < rtk_phy->num_phy; index++) { -- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; -- -- phy_parameter->phy_reg.reg_wrap_vstatus = of_iomap(np, 0); -- phy_parameter->phy_reg.reg_gusb2phyacc0 = of_iomap(np, 1) + index; -- phy_parameter->phy_reg.vstatus_index = index; -- -- if (of_property_read_bool(np, "realtek,inverse-hstx-sync-clock")) -- phy_parameter->inverse_hstx_sync_clock = true; -- else -- phy_parameter->inverse_hstx_sync_clock = false; -- -- if (of_property_read_u32_index(np, "realtek,driving-level", -- index, &phy_parameter->driving_level)) -- phy_parameter->driving_level = DEFAULT_DC_DRIVING_VALUE; -- -- if (of_property_read_u32_index(np, "realtek,driving-level-compensate", -- index, &phy_parameter->driving_level_compensate)) -- phy_parameter->driving_level_compensate = 0; -- -- if (of_property_read_u32_index(np, "realtek,disconnection-compensate", -- index, &phy_parameter->disconnection_compensate)) -- phy_parameter->disconnection_compensate = 0; -- -- get_phy_data_by_efuse(rtk_phy, phy_parameter, index); -- -- update_dc_driving_level(rtk_phy, phy_parameter); -- -- update_hs_clk_select(rtk_phy, phy_parameter); -- } -- -- return ret; --} -- --static int rtk_usb2phy_probe(struct platform_device *pdev) --{ -- struct rtk_phy *rtk_phy; -- struct device *dev = &pdev->dev; -- struct phy *generic_phy; -- struct phy_provider *phy_provider; -- const struct phy_cfg *phy_cfg; -- int ret = 0; -- -- phy_cfg = of_device_get_match_data(dev); -- if (!phy_cfg) { -- dev_err(dev, "phy config are not assigned!\n"); -- return -EINVAL; -- } -- -- rtk_phy = devm_kzalloc(dev, sizeof(*rtk_phy), GFP_KERNEL); -- if (!rtk_phy) -- return -ENOMEM; -- -- rtk_phy->dev = &pdev->dev; -- rtk_phy->phy.dev = rtk_phy->dev; -- rtk_phy->phy.label = "rtk-usb2phy"; -- rtk_phy->phy.notify_port_status = rtk_phy_notify_port_status; -- -- rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL); -- -- memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg)); -- -- rtk_phy->num_phy = phy_cfg->num_phy; -- -- ret = parse_phy_data(rtk_phy); -- if (ret) -- goto err; -- -- platform_set_drvdata(pdev, rtk_phy); -- -- generic_phy = devm_phy_create(rtk_phy->dev, NULL, &ops); -- if (IS_ERR(generic_phy)) -- return PTR_ERR(generic_phy); -- -- phy_set_drvdata(generic_phy, rtk_phy); -- -- phy_provider = devm_of_phy_provider_register(rtk_phy->dev, -- of_phy_simple_xlate); -- if (IS_ERR(phy_provider)) -- return PTR_ERR(phy_provider); -- -- ret = usb_add_phy_dev(&rtk_phy->phy); -- if (ret) -- goto err; -- -- create_debug_files(rtk_phy); -- --err: -- return ret; --} -- --static void rtk_usb2phy_remove(struct platform_device *pdev) --{ -- struct rtk_phy *rtk_phy = platform_get_drvdata(pdev); -- -- remove_debug_files(rtk_phy); -- -- usb_remove_phy(&rtk_phy->phy); --} -- --static const struct phy_cfg rtd1295_phy_cfg = { -- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, -- .page0 = { [0] = {0xe0, 0x90}, -- [3] = {0xe3, 0x3a}, -- [4] = {0xe4, 0x68}, -- [6] = {0xe6, 0x91}, -- [13] = {0xf5, 0x81}, -- [15] = {0xf7, 0x02}, }, -- .page1_size = 8, -- .page1 = { /* default parameter */ }, -- .page2_size = 0, -- .page2 = { /* no parameter */ }, -- .num_phy = 1, -- .check_efuse = false, -- .check_efuse_version = CHECK_EFUSE_V1, -- .efuse_dc_driving_rate = 1, -- .dc_driving_mask = 0xf, -- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, -- .dc_disconnect_mask = 0xf, -- .usb_dc_disconnect_at_page0 = true, -- .do_toggle = true, -- .do_toggle_driving = false, -- .driving_updated_for_dev_dis = 0xf, -- .use_default_parameter = false, -- .is_double_sensitivity_mode = false, --}; -- --static const struct phy_cfg rtd1395_phy_cfg = { -- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, -- .page0 = { [4] = {0xe4, 0xac}, -- [13] = {0xf5, 0x00}, -- [15] = {0xf7, 0x02}, }, -- .page1_size = 8, -- .page1 = { /* default parameter */ }, -- .page2_size = 0, -- .page2 = { /* no parameter */ }, -- .num_phy = 1, -- .check_efuse = false, -- .check_efuse_version = CHECK_EFUSE_V1, -- .efuse_dc_driving_rate = 1, -- .dc_driving_mask = 0xf, -- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, -- .dc_disconnect_mask = 0xf, -- .usb_dc_disconnect_at_page0 = true, -- .do_toggle = true, -- .do_toggle_driving = false, -- .driving_updated_for_dev_dis = 0xf, -- .use_default_parameter = false, -- .is_double_sensitivity_mode = false, --}; -- --static const struct phy_cfg rtd1395_phy_cfg_2port = { -- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, -- .page0 = { [4] = {0xe4, 0xac}, -- [13] = {0xf5, 0x00}, -- [15] = {0xf7, 0x02}, }, -- .page1_size = 8, -- .page1 = { /* default parameter */ }, -- .page2_size = 0, -- .page2 = { /* no parameter */ }, -- .num_phy = 2, -- .check_efuse = false, -- .check_efuse_version = CHECK_EFUSE_V1, -- .efuse_dc_driving_rate = 1, -- .dc_driving_mask = 0xf, -- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, -- .dc_disconnect_mask = 0xf, -- .usb_dc_disconnect_at_page0 = true, -- .do_toggle = true, -- .do_toggle_driving = false, -- .driving_updated_for_dev_dis = 0xf, -- .use_default_parameter = false, -- .is_double_sensitivity_mode = false, --}; -- --static const struct phy_cfg rtd1619_phy_cfg = { -- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, -- .page0 = { [4] = {0xe4, 0x68}, }, -- .page1_size = 8, -- .page1 = { /* default parameter */ }, -- .page2_size = 0, -- .page2 = { /* no parameter */ }, -- .num_phy = 1, -- .check_efuse = true, -- .check_efuse_version = CHECK_EFUSE_V1, -- .efuse_dc_driving_rate = 1, -- .dc_driving_mask = 0xf, -- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, -- .dc_disconnect_mask = 0xf, -- .usb_dc_disconnect_at_page0 = true, -- .do_toggle = true, -- .do_toggle_driving = false, -- .driving_updated_for_dev_dis = 0xf, -- .use_default_parameter = false, -- .is_double_sensitivity_mode = false, --}; -- --static const struct phy_cfg rtd1319_phy_cfg = { -- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, -- .page0 = { [0] = {0xe0, 0x18}, -- [4] = {0xe4, 0x6a}, -- [7] = {0xe7, 0x71}, -- [13] = {0xf5, 0x15}, -- [15] = {0xf7, 0x32}, }, -- .page1_size = 8, -- .page1 = { [3] = {0xe3, 0x44}, }, -- .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE, -- .page2 = { [0] = {0xe0, 0x01}, }, -- .num_phy = 1, -- .check_efuse = true, -- .check_efuse_version = CHECK_EFUSE_V1, -- .efuse_dc_driving_rate = 1, -- .dc_driving_mask = 0xf, -- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, -- .dc_disconnect_mask = 0xf, -- .usb_dc_disconnect_at_page0 = true, -- .do_toggle = true, -- .do_toggle_driving = true, -- .driving_updated_for_dev_dis = 0xf, -- .use_default_parameter = false, -- .is_double_sensitivity_mode = true, --}; -- --static const struct phy_cfg rtd1312c_phy_cfg = { -- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, -- .page0 = { [0] = {0xe0, 0x14}, -- [4] = {0xe4, 0x67}, -- [5] = {0xe5, 0x55}, }, -- .page1_size = 8, -- .page1 = { [3] = {0xe3, 0x23}, -- [6] = {0xe6, 0x58}, }, -- .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE, -- .page2 = { /* default parameter */ }, -- .num_phy = 1, -- .check_efuse = true, -- .check_efuse_version = CHECK_EFUSE_V1, -- .efuse_dc_driving_rate = 1, -- .dc_driving_mask = 0xf, -- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, -- .dc_disconnect_mask = 0xf, -- .usb_dc_disconnect_at_page0 = true, -- .do_toggle = true, -- .do_toggle_driving = true, -- .driving_updated_for_dev_dis = 0xf, -- .use_default_parameter = false, -- .is_double_sensitivity_mode = true, --}; -- --static const struct phy_cfg rtd1619b_phy_cfg = { -- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, -- .page0 = { [0] = {0xe0, 0xa3}, -- [4] = {0xe4, 0x88}, -- [5] = {0xe5, 0x4f}, -- [6] = {0xe6, 0x02}, }, -- .page1_size = 8, -- .page1 = { [3] = {0xe3, 0x64}, }, -- .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE, -- .page2 = { [7] = {0xe7, 0x45}, }, -- .num_phy = 1, -- .check_efuse = true, -- .check_efuse_version = CHECK_EFUSE_V1, -- .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE, -- .dc_driving_mask = 0x1f, -- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, -- .dc_disconnect_mask = 0xf, -- .usb_dc_disconnect_at_page0 = false, -- .do_toggle = true, -- .do_toggle_driving = true, -- .driving_updated_for_dev_dis = 0x8, -- .use_default_parameter = false, -- .is_double_sensitivity_mode = true, --}; -- --static const struct phy_cfg rtd1319d_phy_cfg = { -- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, -- .page0 = { [0] = {0xe0, 0xa3}, -- [4] = {0xe4, 0x8e}, -- [5] = {0xe5, 0x4f}, -- [6] = {0xe6, 0x02}, }, -- .page1_size = MAX_USB_PHY_PAGE1_DATA_SIZE, -- .page1 = { [14] = {0xf5, 0x1}, }, -- .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE, -- .page2 = { [7] = {0xe7, 0x44}, }, -- .check_efuse = true, -- .num_phy = 1, -- .check_efuse_version = CHECK_EFUSE_V1, -- .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE, -- .dc_driving_mask = 0x1f, -- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, -- .dc_disconnect_mask = 0xf, -- .usb_dc_disconnect_at_page0 = false, -- .do_toggle = true, -- .do_toggle_driving = false, -- .driving_updated_for_dev_dis = 0x8, -- .use_default_parameter = false, -- .is_double_sensitivity_mode = true, --}; -- --static const struct phy_cfg rtd1315e_phy_cfg = { -- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, -- .page0 = { [0] = {0xe0, 0xa3}, -- [4] = {0xe4, 0x8c}, -- [5] = {0xe5, 0x4f}, -- [6] = {0xe6, 0x02}, }, -- .page1_size = MAX_USB_PHY_PAGE1_DATA_SIZE, -- .page1 = { [3] = {0xe3, 0x7f}, -- [14] = {0xf5, 0x01}, }, -- .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE, -- .page2 = { [7] = {0xe7, 0x44}, }, -- .num_phy = 1, -- .check_efuse = true, -- .check_efuse_version = CHECK_EFUSE_V2, -- .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE, -- .dc_driving_mask = 0x1f, -- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, -- .dc_disconnect_mask = 0xf, -- .usb_dc_disconnect_at_page0 = false, -- .do_toggle = true, -- .do_toggle_driving = false, -- .driving_updated_for_dev_dis = 0x8, -- .use_default_parameter = false, -- .is_double_sensitivity_mode = true, --}; -- --static const struct of_device_id usbphy_rtk_dt_match[] = { -- { .compatible = "realtek,rtd1295-usb2phy", .data = &rtd1295_phy_cfg }, -- { .compatible = "realtek,rtd1312c-usb2phy", .data = &rtd1312c_phy_cfg }, -- { .compatible = "realtek,rtd1315e-usb2phy", .data = &rtd1315e_phy_cfg }, -- { .compatible = "realtek,rtd1319-usb2phy", .data = &rtd1319_phy_cfg }, -- { .compatible = "realtek,rtd1319d-usb2phy", .data = &rtd1319d_phy_cfg }, -- { .compatible = "realtek,rtd1395-usb2phy", .data = &rtd1395_phy_cfg }, -- { .compatible = "realtek,rtd1395-usb2phy-2port", .data = &rtd1395_phy_cfg_2port }, -- { .compatible = "realtek,rtd1619-usb2phy", .data = &rtd1619_phy_cfg }, -- { .compatible = "realtek,rtd1619b-usb2phy", .data = &rtd1619b_phy_cfg }, -- {}, --}; --MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match); -- --static struct platform_driver rtk_usb2phy_driver = { -- .probe = rtk_usb2phy_probe, -- .remove_new = rtk_usb2phy_remove, -- .driver = { -- .name = "rtk-usb2phy", -- .of_match_table = usbphy_rtk_dt_match, -- }, --}; -- --module_platform_driver(rtk_usb2phy_driver); -- --MODULE_LICENSE("GPL"); --MODULE_ALIAS("platform: rtk-usb2phy"); --MODULE_AUTHOR("Stanley Chang "); --MODULE_DESCRIPTION("Realtek usb 2.0 phy driver"); -diff --git a/drivers/phy/realtek/phy-rtk-usb3.c b/drivers/phy/realtek/phy-rtk-usb3.c -deleted file mode 100644 -index 67446a85e96..00000000000 ---- a/drivers/phy/realtek/phy-rtk-usb3.c -+++ /dev/null -@@ -1,761 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/* -- * phy-rtk-usb3.c RTK usb3.0 phy driver -- * -- * copyright (c) 2023 realtek semiconductor corporation -- * -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#define USB_MDIO_CTRL_PHY_BUSY BIT(7) --#define USB_MDIO_CTRL_PHY_WRITE BIT(0) --#define USB_MDIO_CTRL_PHY_ADDR_SHIFT 8 --#define USB_MDIO_CTRL_PHY_DATA_SHIFT 16 -- --#define MAX_USB_PHY_DATA_SIZE 0x30 --#define PHY_ADDR_0X09 0x09 --#define PHY_ADDR_0X0B 0x0b --#define PHY_ADDR_0X0D 0x0d --#define PHY_ADDR_0X10 0x10 --#define PHY_ADDR_0X1F 0x1f --#define PHY_ADDR_0X20 0x20 --#define PHY_ADDR_0X21 0x21 --#define PHY_ADDR_0X30 0x30 -- --#define REG_0X09_FORCE_CALIBRATION BIT(9) --#define REG_0X0B_RX_OFFSET_RANGE_MASK 0xc --#define REG_0X0D_RX_DEBUG_TEST_EN BIT(6) --#define REG_0X10_DEBUG_MODE_SETTING 0x3c0 --#define REG_0X10_DEBUG_MODE_SETTING_MASK 0x3f8 --#define REG_0X1F_RX_OFFSET_CODE_MASK 0x1e -- --#define USB_U3_TX_LFPS_SWING_TRIM_SHIFT 4 --#define USB_U3_TX_LFPS_SWING_TRIM_MASK 0xf --#define AMPLITUDE_CONTROL_COARSE_MASK 0xff --#define AMPLITUDE_CONTROL_FINE_MASK 0xffff --#define AMPLITUDE_CONTROL_COARSE_DEFAULT 0xff --#define AMPLITUDE_CONTROL_FINE_DEFAULT 0xffff -- --#define PHY_ADDR_MAP_ARRAY_INDEX(addr) (addr) --#define ARRAY_INDEX_MAP_PHY_ADDR(index) (index) -- --struct phy_reg { -- void __iomem *reg_mdio_ctl; --}; -- --struct phy_data { -- u8 addr; -- u16 data; --}; -- --struct phy_cfg { -- int param_size; -- struct phy_data param[MAX_USB_PHY_DATA_SIZE]; -- -- bool check_efuse; -- bool do_toggle; -- bool do_toggle_once; -- bool use_default_parameter; -- bool check_rx_front_end_offset; --}; -- --struct phy_parameter { -- struct phy_reg phy_reg; -- -- /* Get from efuse */ -- u8 efuse_usb_u3_tx_lfps_swing_trim; -- -- /* Get from dts */ -- u32 amplitude_control_coarse; -- u32 amplitude_control_fine; --}; -- --struct rtk_phy { -- struct usb_phy phy; -- struct device *dev; -- -- struct phy_cfg *phy_cfg; -- int num_phy; -- struct phy_parameter *phy_parameter; -- -- struct dentry *debug_dir; --}; -- --#define PHY_IO_TIMEOUT_USEC (50000) --#define PHY_IO_DELAY_US (100) -- --static inline int utmi_wait_register(void __iomem *reg, u32 mask, u32 result) --{ -- int ret; -- unsigned int val; -- -- ret = read_poll_timeout(readl, val, ((val & mask) == result), -- PHY_IO_DELAY_US, PHY_IO_TIMEOUT_USEC, false, reg); -- if (ret) { -- pr_err("%s can't program USB phy\n", __func__); -- return -ETIMEDOUT; -- } -- -- return 0; --} -- --static int rtk_phy3_wait_vbusy(struct phy_reg *phy_reg) --{ -- return utmi_wait_register(phy_reg->reg_mdio_ctl, USB_MDIO_CTRL_PHY_BUSY, 0); --} -- --static u16 rtk_phy_read(struct phy_reg *phy_reg, char addr) --{ -- unsigned int tmp; -- u32 value; -- -- tmp = (addr << USB_MDIO_CTRL_PHY_ADDR_SHIFT); -- -- writel(tmp, phy_reg->reg_mdio_ctl); -- -- rtk_phy3_wait_vbusy(phy_reg); -- -- value = readl(phy_reg->reg_mdio_ctl); -- value = value >> USB_MDIO_CTRL_PHY_DATA_SHIFT; -- -- return (u16)value; --} -- --static int rtk_phy_write(struct phy_reg *phy_reg, char addr, u16 data) --{ -- unsigned int val; -- -- val = USB_MDIO_CTRL_PHY_WRITE | -- (addr << USB_MDIO_CTRL_PHY_ADDR_SHIFT) | -- (data << USB_MDIO_CTRL_PHY_DATA_SHIFT); -- -- writel(val, phy_reg->reg_mdio_ctl); -- -- rtk_phy3_wait_vbusy(phy_reg); -- -- return 0; --} -- --static void do_rtk_usb3_phy_toggle(struct rtk_phy *rtk_phy, int index, bool connect) --{ -- struct phy_cfg *phy_cfg = rtk_phy->phy_cfg; -- struct phy_reg *phy_reg; -- struct phy_parameter *phy_parameter; -- struct phy_data *phy_data; -- u8 addr; -- u16 data; -- int i; -- -- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; -- phy_reg = &phy_parameter->phy_reg; -- -- if (!phy_cfg->do_toggle) -- return; -- -- i = PHY_ADDR_MAP_ARRAY_INDEX(PHY_ADDR_0X09); -- phy_data = phy_cfg->param + i; -- addr = phy_data->addr; -- data = phy_data->data; -- -- if (!addr && !data) { -- addr = PHY_ADDR_0X09; -- data = rtk_phy_read(phy_reg, addr); -- phy_data->addr = addr; -- phy_data->data = data; -- } -- -- rtk_phy_write(phy_reg, addr, data & (~REG_0X09_FORCE_CALIBRATION)); -- mdelay(1); -- rtk_phy_write(phy_reg, addr, data | REG_0X09_FORCE_CALIBRATION); --} -- --static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index) --{ -- struct phy_cfg *phy_cfg; -- struct phy_reg *phy_reg; -- struct phy_parameter *phy_parameter; -- int i = 0; -- -- phy_cfg = rtk_phy->phy_cfg; -- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; -- phy_reg = &phy_parameter->phy_reg; -- -- if (phy_cfg->use_default_parameter) -- goto do_toggle; -- -- for (i = 0; i < phy_cfg->param_size; i++) { -- struct phy_data *phy_data = phy_cfg->param + i; -- u8 addr = phy_data->addr; -- u16 data = phy_data->data; -- -- if (!addr && !data) -- continue; -- -- rtk_phy_write(phy_reg, addr, data); -- } -- --do_toggle: -- if (phy_cfg->do_toggle_once) -- phy_cfg->do_toggle = true; -- -- do_rtk_usb3_phy_toggle(rtk_phy, index, false); -- -- if (phy_cfg->do_toggle_once) { -- u16 check_value = 0; -- int count = 10; -- u16 value_0x0d, value_0x10; -- -- /* Enable Debug mode by set 0x0D and 0x10 */ -- value_0x0d = rtk_phy_read(phy_reg, PHY_ADDR_0X0D); -- value_0x10 = rtk_phy_read(phy_reg, PHY_ADDR_0X10); -- -- rtk_phy_write(phy_reg, PHY_ADDR_0X0D, -- value_0x0d | REG_0X0D_RX_DEBUG_TEST_EN); -- rtk_phy_write(phy_reg, PHY_ADDR_0X10, -- (value_0x10 & ~REG_0X10_DEBUG_MODE_SETTING_MASK) | -- REG_0X10_DEBUG_MODE_SETTING); -- -- check_value = rtk_phy_read(phy_reg, PHY_ADDR_0X30); -- -- while (!(check_value & BIT(15))) { -- check_value = rtk_phy_read(phy_reg, PHY_ADDR_0X30); -- mdelay(1); -- if (count-- < 0) -- break; -- } -- -- if (!(check_value & BIT(15))) -- dev_info(rtk_phy->dev, "toggle fail addr=0x%02x, data=0x%04x\n", -- PHY_ADDR_0X30, check_value); -- -- /* Disable Debug mode by set 0x0D and 0x10 to default*/ -- rtk_phy_write(phy_reg, PHY_ADDR_0X0D, value_0x0d); -- rtk_phy_write(phy_reg, PHY_ADDR_0X10, value_0x10); -- -- phy_cfg->do_toggle = false; -- } -- -- if (phy_cfg->check_rx_front_end_offset) { -- u16 rx_offset_code, rx_offset_range; -- u16 code_mask = REG_0X1F_RX_OFFSET_CODE_MASK; -- u16 range_mask = REG_0X0B_RX_OFFSET_RANGE_MASK; -- bool do_update = false; -- -- rx_offset_code = rtk_phy_read(phy_reg, PHY_ADDR_0X1F); -- if (((rx_offset_code & code_mask) == 0x0) || -- ((rx_offset_code & code_mask) == code_mask)) -- do_update = true; -- -- rx_offset_range = rtk_phy_read(phy_reg, PHY_ADDR_0X0B); -- if (((rx_offset_range & range_mask) == range_mask) && do_update) { -- dev_warn(rtk_phy->dev, "Don't update rx_offset_range (rx_offset_code=0x%x, rx_offset_range=0x%x)\n", -- rx_offset_code, rx_offset_range); -- do_update = false; -- } -- -- if (do_update) { -- u16 tmp1, tmp2; -- -- tmp1 = rx_offset_range & (~range_mask); -- tmp2 = rx_offset_range & range_mask; -- tmp2 += (1 << 2); -- rx_offset_range = tmp1 | (tmp2 & range_mask); -- rtk_phy_write(phy_reg, PHY_ADDR_0X0B, rx_offset_range); -- goto do_toggle; -- } -- } -- -- return 0; --} -- --static int rtk_phy_init(struct phy *phy) --{ -- struct rtk_phy *rtk_phy = phy_get_drvdata(phy); -- int ret = 0; -- int i; -- unsigned long phy_init_time = jiffies; -- -- for (i = 0; i < rtk_phy->num_phy; i++) -- ret = do_rtk_phy_init(rtk_phy, i); -- -- dev_dbg(rtk_phy->dev, "Initialized RTK USB 3.0 PHY (take %dms)\n", -- jiffies_to_msecs(jiffies - phy_init_time)); -- -- return ret; --} -- --static int rtk_phy_exit(struct phy *phy) --{ -- return 0; --} -- --static const struct phy_ops ops = { -- .init = rtk_phy_init, -- .exit = rtk_phy_exit, -- .owner = THIS_MODULE, --}; -- --static void rtk_phy_toggle(struct usb_phy *usb3_phy, bool connect, int port) --{ -- int index = port; -- struct rtk_phy *rtk_phy = NULL; -- -- rtk_phy = dev_get_drvdata(usb3_phy->dev); -- -- if (index > rtk_phy->num_phy) { -- dev_err(rtk_phy->dev, "%s: The port=%d is not in usb phy (num_phy=%d)\n", -- __func__, index, rtk_phy->num_phy); -- return; -- } -- -- do_rtk_usb3_phy_toggle(rtk_phy, index, connect); --} -- --static int rtk_phy_notify_port_status(struct usb_phy *x, int port, -- u16 portstatus, u16 portchange) --{ -- bool connect = false; -- -- pr_debug("%s port=%d portstatus=0x%x portchange=0x%x\n", -- __func__, port, (int)portstatus, (int)portchange); -- if (portstatus & USB_PORT_STAT_CONNECTION) -- connect = true; -- -- if (portchange & USB_PORT_STAT_C_CONNECTION) -- rtk_phy_toggle(x, connect, port); -- -- return 0; --} -- --#ifdef CONFIG_DEBUG_FS --static struct dentry *create_phy_debug_root(void) --{ -- struct dentry *phy_debug_root; -- -- phy_debug_root = debugfs_lookup("phy", usb_debug_root); -- if (!phy_debug_root) -- phy_debug_root = debugfs_create_dir("phy", usb_debug_root); -- -- return phy_debug_root; --} -- --static int rtk_usb3_parameter_show(struct seq_file *s, void *unused) --{ -- struct rtk_phy *rtk_phy = s->private; -- struct phy_cfg *phy_cfg; -- int i, index; -- -- phy_cfg = rtk_phy->phy_cfg; -- -- seq_puts(s, "Property:\n"); -- seq_printf(s, " check_efuse: %s\n", -- phy_cfg->check_efuse ? "Enable" : "Disable"); -- seq_printf(s, " do_toggle: %s\n", -- phy_cfg->do_toggle ? "Enable" : "Disable"); -- seq_printf(s, " do_toggle_once: %s\n", -- phy_cfg->do_toggle_once ? "Enable" : "Disable"); -- seq_printf(s, " use_default_parameter: %s\n", -- phy_cfg->use_default_parameter ? "Enable" : "Disable"); -- -- for (index = 0; index < rtk_phy->num_phy; index++) { -- struct phy_reg *phy_reg; -- struct phy_parameter *phy_parameter; -- -- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; -- phy_reg = &phy_parameter->phy_reg; -- -- seq_printf(s, "PHY %d:\n", index); -- -- for (i = 0; i < phy_cfg->param_size; i++) { -- struct phy_data *phy_data = phy_cfg->param + i; -- u8 addr = ARRAY_INDEX_MAP_PHY_ADDR(i); -- u16 data = phy_data->data; -- -- if (!phy_data->addr && !data) -- seq_printf(s, " addr = 0x%02x, data = none ==> read value = 0x%04x\n", -- addr, rtk_phy_read(phy_reg, addr)); -- else -- seq_printf(s, " addr = 0x%02x, data = 0x%04x ==> read value = 0x%04x\n", -- addr, data, rtk_phy_read(phy_reg, addr)); -- } -- -- seq_puts(s, "PHY Property:\n"); -- seq_printf(s, " efuse_usb_u3_tx_lfps_swing_trim: 0x%x\n", -- (int)phy_parameter->efuse_usb_u3_tx_lfps_swing_trim); -- seq_printf(s, " amplitude_control_coarse: 0x%x\n", -- (int)phy_parameter->amplitude_control_coarse); -- seq_printf(s, " amplitude_control_fine: 0x%x\n", -- (int)phy_parameter->amplitude_control_fine); -- } -- -- return 0; --} --DEFINE_SHOW_ATTRIBUTE(rtk_usb3_parameter); -- --static inline void create_debug_files(struct rtk_phy *rtk_phy) --{ -- struct dentry *phy_debug_root = NULL; -- -- phy_debug_root = create_phy_debug_root(); -- -- if (!phy_debug_root) -- return; -- -- rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev), phy_debug_root); -- -- debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy, -- &rtk_usb3_parameter_fops); -- -- return; --} -- --static inline void remove_debug_files(struct rtk_phy *rtk_phy) --{ -- debugfs_remove_recursive(rtk_phy->debug_dir); --} --#else --static inline void create_debug_files(struct rtk_phy *rtk_phy) { } --static inline void remove_debug_files(struct rtk_phy *rtk_phy) { } --#endif /* CONFIG_DEBUG_FS */ -- --static int get_phy_data_by_efuse(struct rtk_phy *rtk_phy, -- struct phy_parameter *phy_parameter, int index) --{ -- struct phy_cfg *phy_cfg = rtk_phy->phy_cfg; -- u8 value = 0; -- struct nvmem_cell *cell; -- -- if (!phy_cfg->check_efuse) -- goto out; -- -- cell = nvmem_cell_get(rtk_phy->dev, "usb_u3_tx_lfps_swing_trim"); -- if (IS_ERR(cell)) { -- dev_dbg(rtk_phy->dev, "%s no usb_u3_tx_lfps_swing_trim: %ld\n", -- __func__, PTR_ERR(cell)); -- } else { -- unsigned char *buf; -- size_t buf_size; -- -- buf = nvmem_cell_read(cell, &buf_size); -- if (!IS_ERR(buf)) { -- value = buf[0] & USB_U3_TX_LFPS_SWING_TRIM_MASK; -- kfree(buf); -- } -- nvmem_cell_put(cell); -- } -- -- if (value > 0 && value < 0x8) -- phy_parameter->efuse_usb_u3_tx_lfps_swing_trim = 0x8; -- else -- phy_parameter->efuse_usb_u3_tx_lfps_swing_trim = (u8)value; -- --out: -- return 0; --} -- --static void update_amplitude_control_value(struct rtk_phy *rtk_phy, -- struct phy_parameter *phy_parameter) --{ -- struct phy_cfg *phy_cfg; -- struct phy_reg *phy_reg; -- -- phy_reg = &phy_parameter->phy_reg; -- phy_cfg = rtk_phy->phy_cfg; -- -- if (phy_parameter->amplitude_control_coarse != AMPLITUDE_CONTROL_COARSE_DEFAULT) { -- u16 val_mask = AMPLITUDE_CONTROL_COARSE_MASK; -- u16 data; -- -- if (!phy_cfg->param[PHY_ADDR_0X20].addr && !phy_cfg->param[PHY_ADDR_0X20].data) { -- phy_cfg->param[PHY_ADDR_0X20].addr = PHY_ADDR_0X20; -- data = rtk_phy_read(phy_reg, PHY_ADDR_0X20); -- } else { -- data = phy_cfg->param[PHY_ADDR_0X20].data; -- } -- -- data &= (~val_mask); -- data |= (phy_parameter->amplitude_control_coarse & val_mask); -- -- phy_cfg->param[PHY_ADDR_0X20].data = data; -- } -- -- if (phy_parameter->efuse_usb_u3_tx_lfps_swing_trim) { -- u8 efuse_val = phy_parameter->efuse_usb_u3_tx_lfps_swing_trim; -- u16 val_mask = USB_U3_TX_LFPS_SWING_TRIM_MASK; -- int val_shift = USB_U3_TX_LFPS_SWING_TRIM_SHIFT; -- u16 data; -- -- if (!phy_cfg->param[PHY_ADDR_0X20].addr && !phy_cfg->param[PHY_ADDR_0X20].data) { -- phy_cfg->param[PHY_ADDR_0X20].addr = PHY_ADDR_0X20; -- data = rtk_phy_read(phy_reg, PHY_ADDR_0X20); -- } else { -- data = phy_cfg->param[PHY_ADDR_0X20].data; -- } -- -- data &= ~(val_mask << val_shift); -- data |= ((efuse_val & val_mask) << val_shift); -- -- phy_cfg->param[PHY_ADDR_0X20].data = data; -- } -- -- if (phy_parameter->amplitude_control_fine != AMPLITUDE_CONTROL_FINE_DEFAULT) { -- u16 val_mask = AMPLITUDE_CONTROL_FINE_MASK; -- -- if (!phy_cfg->param[PHY_ADDR_0X21].addr && !phy_cfg->param[PHY_ADDR_0X21].data) -- phy_cfg->param[PHY_ADDR_0X21].addr = PHY_ADDR_0X21; -- -- phy_cfg->param[PHY_ADDR_0X21].data = -- phy_parameter->amplitude_control_fine & val_mask; -- } --} -- --static int parse_phy_data(struct rtk_phy *rtk_phy) --{ -- struct device *dev = rtk_phy->dev; -- struct phy_parameter *phy_parameter; -- int ret = 0; -- int index; -- -- rtk_phy->phy_parameter = devm_kzalloc(dev, sizeof(struct phy_parameter) * -- rtk_phy->num_phy, GFP_KERNEL); -- if (!rtk_phy->phy_parameter) -- return -ENOMEM; -- -- for (index = 0; index < rtk_phy->num_phy; index++) { -- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; -- -- phy_parameter->phy_reg.reg_mdio_ctl = of_iomap(dev->of_node, 0) + index; -- -- /* Amplitude control address 0x20 bit 0 to bit 7 */ -- if (of_property_read_u32(dev->of_node, "realtek,amplitude-control-coarse-tuning", -- &phy_parameter->amplitude_control_coarse)) -- phy_parameter->amplitude_control_coarse = AMPLITUDE_CONTROL_COARSE_DEFAULT; -- -- /* Amplitude control address 0x21 bit 0 to bit 16 */ -- if (of_property_read_u32(dev->of_node, "realtek,amplitude-control-fine-tuning", -- &phy_parameter->amplitude_control_fine)) -- phy_parameter->amplitude_control_fine = AMPLITUDE_CONTROL_FINE_DEFAULT; -- -- get_phy_data_by_efuse(rtk_phy, phy_parameter, index); -- -- update_amplitude_control_value(rtk_phy, phy_parameter); -- } -- -- return ret; --} -- --static int rtk_usb3phy_probe(struct platform_device *pdev) --{ -- struct rtk_phy *rtk_phy; -- struct device *dev = &pdev->dev; -- struct phy *generic_phy; -- struct phy_provider *phy_provider; -- const struct phy_cfg *phy_cfg; -- int ret; -- -- phy_cfg = of_device_get_match_data(dev); -- if (!phy_cfg) { -- dev_err(dev, "phy config are not assigned!\n"); -- return -EINVAL; -- } -- -- rtk_phy = devm_kzalloc(dev, sizeof(*rtk_phy), GFP_KERNEL); -- if (!rtk_phy) -- return -ENOMEM; -- -- rtk_phy->dev = &pdev->dev; -- rtk_phy->phy.dev = rtk_phy->dev; -- rtk_phy->phy.label = "rtk-usb3phy"; -- rtk_phy->phy.notify_port_status = rtk_phy_notify_port_status; -- -- rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL); -- -- memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg)); -- -- rtk_phy->num_phy = 1; -- -- ret = parse_phy_data(rtk_phy); -- if (ret) -- goto err; -- -- platform_set_drvdata(pdev, rtk_phy); -- -- generic_phy = devm_phy_create(rtk_phy->dev, NULL, &ops); -- if (IS_ERR(generic_phy)) -- return PTR_ERR(generic_phy); -- -- phy_set_drvdata(generic_phy, rtk_phy); -- -- phy_provider = devm_of_phy_provider_register(rtk_phy->dev, of_phy_simple_xlate); -- if (IS_ERR(phy_provider)) -- return PTR_ERR(phy_provider); -- -- ret = usb_add_phy_dev(&rtk_phy->phy); -- if (ret) -- goto err; -- -- create_debug_files(rtk_phy); -- --err: -- return ret; --} -- --static void rtk_usb3phy_remove(struct platform_device *pdev) --{ -- struct rtk_phy *rtk_phy = platform_get_drvdata(pdev); -- -- remove_debug_files(rtk_phy); -- -- usb_remove_phy(&rtk_phy->phy); --} -- --static const struct phy_cfg rtd1295_phy_cfg = { -- .param_size = MAX_USB_PHY_DATA_SIZE, -- .param = { [0] = {0x01, 0x4008}, [1] = {0x01, 0xe046}, -- [2] = {0x02, 0x6046}, [3] = {0x03, 0x2779}, -- [4] = {0x04, 0x72f5}, [5] = {0x05, 0x2ad3}, -- [6] = {0x06, 0x000e}, [7] = {0x07, 0x2e00}, -- [8] = {0x08, 0x3591}, [9] = {0x09, 0x525c}, -- [10] = {0x0a, 0xa600}, [11] = {0x0b, 0xa904}, -- [12] = {0x0c, 0xc000}, [13] = {0x0d, 0xef1c}, -- [14] = {0x0e, 0x2000}, [15] = {0x0f, 0x0000}, -- [16] = {0x10, 0x000c}, [17] = {0x11, 0x4c00}, -- [18] = {0x12, 0xfc00}, [19] = {0x13, 0x0c81}, -- [20] = {0x14, 0xde01}, [21] = {0x15, 0x0000}, -- [22] = {0x16, 0x0000}, [23] = {0x17, 0x0000}, -- [24] = {0x18, 0x0000}, [25] = {0x19, 0x4004}, -- [26] = {0x1a, 0x1260}, [27] = {0x1b, 0xff00}, -- [28] = {0x1c, 0xcb00}, [29] = {0x1d, 0xa03f}, -- [30] = {0x1e, 0xc2e0}, [31] = {0x1f, 0x2807}, -- [32] = {0x20, 0x947a}, [33] = {0x21, 0x88aa}, -- [34] = {0x22, 0x0057}, [35] = {0x23, 0xab66}, -- [36] = {0x24, 0x0800}, [37] = {0x25, 0x0000}, -- [38] = {0x26, 0x040a}, [39] = {0x27, 0x01d6}, -- [40] = {0x28, 0xf8c2}, [41] = {0x29, 0x3080}, -- [42] = {0x2a, 0x3082}, [43] = {0x2b, 0x2078}, -- [44] = {0x2c, 0xffff}, [45] = {0x2d, 0xffff}, -- [46] = {0x2e, 0x0000}, [47] = {0x2f, 0x0040}, }, -- .check_efuse = false, -- .do_toggle = true, -- .do_toggle_once = false, -- .use_default_parameter = false, -- .check_rx_front_end_offset = false, --}; -- --static const struct phy_cfg rtd1619_phy_cfg = { -- .param_size = MAX_USB_PHY_DATA_SIZE, -- .param = { [8] = {0x08, 0x3591}, -- [38] = {0x26, 0x840b}, -- [40] = {0x28, 0xf842}, }, -- .check_efuse = false, -- .do_toggle = true, -- .do_toggle_once = false, -- .use_default_parameter = false, -- .check_rx_front_end_offset = false, --}; -- --static const struct phy_cfg rtd1319_phy_cfg = { -- .param_size = MAX_USB_PHY_DATA_SIZE, -- .param = { [1] = {0x01, 0xac86}, -- [6] = {0x06, 0x0003}, -- [9] = {0x09, 0x924c}, -- [10] = {0x0a, 0xa608}, -- [11] = {0x0b, 0xb905}, -- [14] = {0x0e, 0x2010}, -- [32] = {0x20, 0x705a}, -- [33] = {0x21, 0xf645}, -- [34] = {0x22, 0x0013}, -- [35] = {0x23, 0xcb66}, -- [41] = {0x29, 0xff00}, }, -- .check_efuse = true, -- .do_toggle = true, -- .do_toggle_once = false, -- .use_default_parameter = false, -- .check_rx_front_end_offset = false, --}; -- --static const struct phy_cfg rtd1619b_phy_cfg = { -- .param_size = MAX_USB_PHY_DATA_SIZE, -- .param = { [1] = {0x01, 0xac8c}, -- [6] = {0x06, 0x0017}, -- [9] = {0x09, 0x724c}, -- [10] = {0x0a, 0xb610}, -- [11] = {0x0b, 0xb90d}, -- [13] = {0x0d, 0xef2a}, -- [15] = {0x0f, 0x9050}, -- [16] = {0x10, 0x000c}, -- [32] = {0x20, 0x70ff}, -- [34] = {0x22, 0x0013}, -- [35] = {0x23, 0xdb66}, -- [38] = {0x26, 0x8609}, -- [41] = {0x29, 0xff13}, -- [42] = {0x2a, 0x3070}, }, -- .check_efuse = true, -- .do_toggle = false, -- .do_toggle_once = true, -- .use_default_parameter = false, -- .check_rx_front_end_offset = false, --}; -- --static const struct phy_cfg rtd1319d_phy_cfg = { -- .param_size = MAX_USB_PHY_DATA_SIZE, -- .param = { [1] = {0x01, 0xac89}, -- [4] = {0x04, 0xf2f5}, -- [6] = {0x06, 0x0017}, -- [9] = {0x09, 0x424c}, -- [10] = {0x0a, 0x9610}, -- [11] = {0x0b, 0x9901}, -- [12] = {0x0c, 0xf000}, -- [13] = {0x0d, 0xef2a}, -- [14] = {0x0e, 0x1000}, -- [15] = {0x0f, 0x9050}, -- [32] = {0x20, 0x7077}, -- [35] = {0x23, 0x0b62}, -- [37] = {0x25, 0x10ec}, -- [42] = {0x2a, 0x3070}, }, -- .check_efuse = true, -- .do_toggle = false, -- .do_toggle_once = true, -- .use_default_parameter = false, -- .check_rx_front_end_offset = true, --}; -- --static const struct of_device_id usbphy_rtk_dt_match[] = { -- { .compatible = "realtek,rtd1295-usb3phy", .data = &rtd1295_phy_cfg }, -- { .compatible = "realtek,rtd1319-usb3phy", .data = &rtd1319_phy_cfg }, -- { .compatible = "realtek,rtd1319d-usb3phy", .data = &rtd1319d_phy_cfg }, -- { .compatible = "realtek,rtd1619-usb3phy", .data = &rtd1619_phy_cfg }, -- { .compatible = "realtek,rtd1619b-usb3phy", .data = &rtd1619b_phy_cfg }, -- {}, --}; --MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match); -- --static struct platform_driver rtk_usb3phy_driver = { -- .probe = rtk_usb3phy_probe, -- .remove_new = rtk_usb3phy_remove, -- .driver = { -- .name = "rtk-usb3phy", -- .of_match_table = usbphy_rtk_dt_match, -- }, --}; -- --module_platform_driver(rtk_usb3phy_driver); -- --MODULE_LICENSE("GPL"); --MODULE_ALIAS("platform: rtk-usb3phy"); --MODULE_AUTHOR("Stanley Chang "); --MODULE_DESCRIPTION("Realtek usb 3.0 phy driver"); -diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c -index cd6ac04c146..c3104714b48 100644 ---- a/drivers/platform/x86/amd/pmc/pmc.c -+++ b/drivers/platform/x86/amd/pmc/pmc.c -@@ -964,33 +964,6 @@ static const struct pci_device_id pmc_pci_ids[] = { - { } - }; - --static int amd_pmc_get_dram_size(struct amd_pmc_dev *dev) --{ -- int ret; -- -- switch (dev->cpu_id) { -- case AMD_CPU_ID_YC: -- if (!(dev->major > 90 || (dev->major == 90 && dev->minor > 39))) { -- ret = -EINVAL; -- goto err_dram_size; -- } -- break; -- default: -- ret = -EINVAL; -- goto err_dram_size; -- } -- -- ret = amd_pmc_send_cmd(dev, S2D_DRAM_SIZE, &dev->dram_size, dev->s2d_msg_id, true); -- if (ret || !dev->dram_size) -- goto err_dram_size; -- -- return 0; -- --err_dram_size: -- dev_err(dev->dev, "DRAM size command not supported for this platform\n"); -- return ret; --} -- - static int amd_pmc_s2d_init(struct amd_pmc_dev *dev) - { - u32 phys_addr_low, phys_addr_hi; -@@ -1009,8 +982,8 @@ static int amd_pmc_s2d_init(struct amd_pmc_dev *dev) - return -EIO; - - /* Get DRAM size */ -- ret = amd_pmc_get_dram_size(dev); -- if (ret) -+ ret = amd_pmc_send_cmd(dev, S2D_DRAM_SIZE, &dev->dram_size, dev->s2d_msg_id, true); -+ if (ret || !dev->dram_size) - dev->dram_size = S2D_TELEMETRY_DRAMBYTES_MAX; - - /* Get STB DRAM address */ -diff --git a/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c b/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c -index 5798b49ddab..8c9f4f3227f 100644 ---- a/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c -+++ b/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c -@@ -588,17 +588,14 @@ static void release_attributes_data(void) - static int hp_add_other_attributes(int attr_type) - { - struct kobject *attr_name_kobj; -- union acpi_object *obj = NULL; - int ret; - char *attr_name; - -- mutex_lock(&bioscfg_drv.mutex); -- - attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL); -- if (!attr_name_kobj) { -- ret = -ENOMEM; -- goto err_other_attr_init; -- } -+ if (!attr_name_kobj) -+ return -ENOMEM; -+ -+ mutex_lock(&bioscfg_drv.mutex); - - /* Check if attribute type is supported */ - switch (attr_type) { -@@ -615,14 +612,14 @@ static int hp_add_other_attributes(int attr_type) - default: - pr_err("Error: Unknown attr_type: %d\n", attr_type); - ret = -EINVAL; -- goto err_other_attr_init; -+ kfree(attr_name_kobj); -+ goto unlock_drv_mutex; - } - - ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype, - NULL, "%s", attr_name); - if (ret) { - pr_err("Error encountered [%d]\n", ret); -- kobject_put(attr_name_kobj); - goto err_other_attr_init; - } - -@@ -630,27 +627,26 @@ static int hp_add_other_attributes(int attr_type) - switch (attr_type) { - case HPWMI_SECURE_PLATFORM_TYPE: - ret = hp_populate_secure_platform_data(attr_name_kobj); -- if (ret) -- goto err_other_attr_init; - break; - - case HPWMI_SURE_START_TYPE: - ret = hp_populate_sure_start_data(attr_name_kobj); -- if (ret) -- goto err_other_attr_init; - break; - - default: - ret = -EINVAL; -- goto err_other_attr_init; - } - -+ if (ret) -+ goto err_other_attr_init; -+ - mutex_unlock(&bioscfg_drv.mutex); - return 0; - - err_other_attr_init: -+ kobject_put(attr_name_kobj); -+unlock_drv_mutex: - mutex_unlock(&bioscfg_drv.mutex); -- kfree(obj); - return ret; - } - -diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c -index ac037540acf..88eefccb6ed 100644 ---- a/drivers/platform/x86/ideapad-laptop.c -+++ b/drivers/platform/x86/ideapad-laptop.c -@@ -1425,18 +1425,17 @@ static int ideapad_kbd_bl_init(struct ideapad_private *priv) - if (WARN_ON(priv->kbd_bl.initialized)) - return -EEXIST; - -- brightness = ideapad_kbd_bl_brightness_get(priv); -- if (brightness < 0) -- return brightness; -- -- priv->kbd_bl.last_brightness = brightness; -- - if (ideapad_kbd_bl_check_tristate(priv->kbd_bl.type)) { - priv->kbd_bl.led.max_brightness = 2; - } else { - priv->kbd_bl.led.max_brightness = 1; - } - -+ brightness = ideapad_kbd_bl_brightness_get(priv); -+ if (brightness < 0) -+ return brightness; -+ -+ priv->kbd_bl.last_brightness = brightness; - priv->kbd_bl.led.name = "platform::" LED_FUNCTION_KBD_BACKLIGHT; - priv->kbd_bl.led.brightness_get = ideapad_kbd_bl_led_cdev_brightness_get; - priv->kbd_bl.led.brightness_set_blocking = ideapad_kbd_bl_led_cdev_brightness_set; -diff --git a/drivers/platform/x86/intel/telemetry/core.c b/drivers/platform/x86/intel/telemetry/core.c -index fdf55b5d694..e4be40f73ee 100644 ---- a/drivers/platform/x86/intel/telemetry/core.c -+++ b/drivers/platform/x86/intel/telemetry/core.c -@@ -102,7 +102,7 @@ static const struct telemetry_core_ops telm_defpltops = { - /** - * telemetry_update_events() - Update telemetry Configuration - * @pss_evtconfig: PSS related config. No change if num_evts = 0. -- * @pss_evtconfig: IOSS related config. No change if num_evts = 0. -+ * @ioss_evtconfig: IOSS related config. No change if num_evts = 0. - * - * This API updates the IOSS & PSS Telemetry configuration. Old config - * is overwritten. Call telemetry_reset_events when logging is over -@@ -176,7 +176,7 @@ EXPORT_SYMBOL_GPL(telemetry_reset_events); - /** - * telemetry_get_eventconfig() - Returns the pss and ioss events enabled - * @pss_evtconfig: Pointer to PSS related configuration. -- * @pss_evtconfig: Pointer to IOSS related configuration. -+ * @ioss_evtconfig: Pointer to IOSS related configuration. - * @pss_len: Number of u32 elements allocated for pss_evtconfig array - * @ioss_len: Number of u32 elements allocated for ioss_evtconfig array - * diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig -index f21cb05815e..bccf431f462 100644 +index f21cb05815e..c37d3f10da1 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -966,6 +966,14 @@ config BATTERY_UG3105 @@ -17372,18 +13740,21 @@ index f21cb05815e..bccf431f462 100644 config CHARGER_QCOM_SMB2 tristate "Qualcomm PMI8998 PMIC charger driver" depends on MFD_SPMI_PMIC -@@ -984,4 +992,15 @@ config FUEL_GAUGE_MM8013 +@@ -984,4 +992,18 @@ config FUEL_GAUGE_MM8013 the state of charge, temperature, cycle count, actual and design capacity, etc. +config LENOVO_YOGA_C630_EC + tristate "Lenovo Yoga C630 EC battery driver" -+ depends on DRM + depends on I2C + help + Driver for the Embedded Controller in the Qualcomm Snapdragon-based -+ Lenovo Yoga C630, which provides battery information and USB Type-C -+ altmode notifications. ++ Lenovo Yoga C630, which provides battery and power adapter ++ information. ++ ++ This driver provides battery and AC status support for the mentioned ++ laptop where this information is not properly exposed via the ++ standard ACPI devices. + + Say M or Y here to include this support. + @@ -18728,23 +15099,21 @@ index 00000000000..f8dd93aa23c +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/supply/yoga-c630-ec.c b/drivers/power/supply/yoga-c630-ec.c new file mode 100644 -index 00000000000..1fa0b5844e0 +index 00000000000..f070e56dc87 --- /dev/null +++ b/drivers/power/supply/yoga-c630-ec.c -@@ -0,0 +1,547 @@ +@@ -0,0 +1,470 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (c) 2022 Linaro Ltd. ++ * Copyright (c) 2022-2023 Linaro Ltd. + */ +#include ++#include +#include +#include +#include +#include +#include -+#include -+ -+#include + +#define LENOVO_EC_CACHE_TIME (10 * HZ) + @@ -18785,8 +15154,6 @@ index 00000000000..1fa0b5844e0 + struct power_supply *adp_psy; + struct power_supply *bat_psy; + -+ struct typec_switch *typec_switch; -+ + unsigned long last_status_update; + + bool adapter_online; @@ -18806,9 +15173,6 @@ index 00000000000..1fa0b5844e0 + unsigned int voltage_now; + + int rate_now; -+ -+ bool bridge_configured; -+ struct drm_bridge bridge; +}; + +static int yoga_c630_ec_request(struct yoga_c630_ec *ec, u8 *req, size_t req_len, @@ -19030,9 +15394,6 @@ index 00000000000..1fa0b5844e0 + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = "Compal"; + break; -+ case POWER_SUPPLY_PROP_SERIAL_NUMBER: -+ val->strval = "05072018"; -+ break; + default: + rc = -EINVAL; + break; @@ -19053,7 +15414,6 @@ index 00000000000..1fa0b5844e0 + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, -+ POWER_SUPPLY_PROP_SERIAL_NUMBER, +}; + +static const struct power_supply_desc yoga_c630_ec_bat_psy_desc = { @@ -19097,21 +15457,9 @@ index 00000000000..1fa0b5844e0 + .get_property = yoga_c630_ec_adpt_get_property, +}; + -+static int yoga_c630_ec_attach(struct drm_bridge *bridge, -+ enum drm_bridge_attach_flags flags) -+{ -+ return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL; -+} -+ -+static const struct drm_bridge_funcs yoga_c630_ec_bridge_funcs = { -+ .attach = yoga_c630_ec_attach, -+}; -+ +static int yoga_c630_ec_query_usb_event(struct yoga_c630_ec *ec) +{ + struct device *dev = &ec->client->dev; -+ enum typec_orientation orientation; -+ enum drm_connector_status status; + int event; + + mutex_lock(&ec->lock); @@ -19122,19 +15470,7 @@ index 00000000000..1fa0b5844e0 + return event; + } + -+ if (FIELD_GET(LENOVO_EC_USB_EVENT_MUX, event)) -+ status = connector_status_connected; -+ else -+ status = connector_status_disconnected; -+ -+ if (FIELD_GET(LENOVO_EC_USB_EVENT_ORIENTATION, event)) -+ orientation = TYPEC_ORIENTATION_REVERSE; -+ else -+ orientation = TYPEC_ORIENTATION_NORMAL; -+ -+ typec_switch_set(ec->typec_switch, orientation); -+ if (ec->bridge_configured) -+ drm_bridge_hpd_notify(&ec->bridge, status); ++ /* FIXME: handle the returned event to set the Type-C properties */ + + return 0; +} @@ -19171,20 +15507,12 @@ index 00000000000..1fa0b5844e0 + return IRQ_HANDLED; +} + -+static void yoga_c630_ec_put_switch(void *data) -+{ -+ typec_switch_put(data); -+} -+ -+static int yoga_c630_ec_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) ++static int yoga_c630_ec_probe(struct i2c_client *client) +{ + struct power_supply_config adp_cfg = {}; + struct power_supply_config bat_cfg = {}; -+ struct fwnode_handle *fwnode; + struct yoga_c630_ec *ec; + struct device *dev = &client->dev; -+ u32 port; + int ret; + + ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL); @@ -19210,40 +15538,6 @@ index 00000000000..1fa0b5844e0 + return PTR_ERR(ec->bat_psy); + } + -+ device_for_each_child_node(dev, fwnode) { -+ ret = fwnode_property_read_u32(fwnode, "reg", &port); -+ if (ret < 0) -+ continue; -+ -+ /* Got multiple ports, but altmode is only possible on port 1 */ -+ if (port != 1) -+ continue; -+ -+ ec->bridge.funcs = &yoga_c630_ec_bridge_funcs; -+ ec->bridge.of_node = to_of_node(fwnode); -+ ec->bridge.ops = DRM_BRIDGE_OP_HPD; -+ ec->bridge.type = DRM_MODE_CONNECTOR_USB; -+ -+ ret = devm_drm_bridge_add(dev, &ec->bridge); -+ if (ret) { -+ dev_err(dev, "failed to register drm bridge\n"); -+ fwnode_handle_put(fwnode); -+ return ret; -+ } -+ -+ ec->bridge_configured = true; -+ -+ ec->typec_switch = fwnode_typec_switch_get(fwnode); -+ if (IS_ERR(ec->typec_switch)) -+ return dev_err_probe(dev, PTR_ERR(ec->typec_switch), -+ "failed to acquire orientation-switch for port 1\n"); -+ -+ ret = devm_add_action_or_reset(dev, yoga_c630_ec_put_switch, -+ ec->typec_switch); -+ if (ret) -+ return ret; -+ } -+ + ret = devm_request_threaded_irq(dev, client->irq, + NULL, yoga_c630_ec_intr, + IRQF_ONESHOT, "yoga_c630_ec", ec); @@ -19942,659 +16236,11 @@ index 82d460ff477..a01671fb621 100644 channel->rpdev = rpdev; } -diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c -index d440319a794..833cfab7d87 100644 ---- a/drivers/s390/block/dasd.c -+++ b/drivers/s390/block/dasd.c -@@ -676,18 +676,20 @@ static void dasd_profile_start(struct dasd_block *block, - * we count each request only once. - */ - device = cqr->startdev; -- if (device->profile.data) { -- counter = 1; /* request is not yet queued on the start device */ -- list_for_each(l, &device->ccw_queue) -- if (++counter >= 31) -- break; -- } -+ if (!device->profile.data) -+ return; -+ -+ spin_lock(get_ccwdev_lock(device->cdev)); -+ counter = 1; /* request is not yet queued on the start device */ -+ list_for_each(l, &device->ccw_queue) -+ if (++counter >= 31) -+ break; -+ spin_unlock(get_ccwdev_lock(device->cdev)); -+ - spin_lock(&device->profile.lock); -- if (device->profile.data) { -- device->profile.data->dasd_io_nr_req[counter]++; -- if (rq_data_dir(req) == READ) -- device->profile.data->dasd_read_nr_req[counter]++; -- } -+ device->profile.data->dasd_io_nr_req[counter]++; -+ if (rq_data_dir(req) == READ) -+ device->profile.data->dasd_read_nr_req[counter]++; - spin_unlock(&device->profile.lock); - } - -diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h -index 2e663131ada..1b1b8a41c4d 100644 ---- a/drivers/s390/block/dasd_int.h -+++ b/drivers/s390/block/dasd_int.h -@@ -283,7 +283,7 @@ struct dasd_pprc_dev_info { - __u8 secondary; /* 7 Secondary device address */ - __u16 pprc_id; /* 8-9 Peer-to-Peer Remote Copy ID */ - __u8 reserved2[12]; /* 10-21 reserved */ -- __u16 prim_cu_ssid; /* 22-23 Pimary Control Unit SSID */ -+ __u16 prim_cu_ssid; /* 22-23 Primary Control Unit SSID */ - __u8 reserved3[12]; /* 24-35 reserved */ - __u16 sec_cu_ssid; /* 36-37 Secondary Control Unit SSID */ - __u8 reserved4[90]; /* 38-127 reserved */ -diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig -index 4902d45e929..c61e6427384 100644 ---- a/drivers/s390/net/Kconfig -+++ b/drivers/s390/net/Kconfig -@@ -103,10 +103,11 @@ config CCWGROUP - config ISM - tristate "Support for ISM vPCI Adapter" - depends on PCI -+ imply SMC - default n - help - Select this option if you want to use the Internal Shared Memory -- vPCI Adapter. -+ vPCI Adapter. The adapter can be used with the SMC network protocol. - - To compile as a module choose M. The module name is ism. - If unsure, choose N. -diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c -index 6df7f377d2f..81aabbfbbe2 100644 ---- a/drivers/s390/net/ism_drv.c -+++ b/drivers/s390/net/ism_drv.c -@@ -30,7 +30,6 @@ static const struct pci_device_id ism_device_table[] = { - MODULE_DEVICE_TABLE(pci, ism_device_table); - - static debug_info_t *ism_debug_info; --static const struct smcd_ops ism_ops; - - #define NO_CLIENT 0xff /* must be >= MAX_CLIENTS */ - static struct ism_client *clients[MAX_CLIENTS]; /* use an array rather than */ -@@ -289,22 +288,6 @@ static int ism_read_local_gid(struct ism_dev *ism) - return ret; - } - --static int ism_query_rgid(struct ism_dev *ism, u64 rgid, u32 vid_valid, -- u32 vid) --{ -- union ism_query_rgid cmd; -- -- memset(&cmd, 0, sizeof(cmd)); -- cmd.request.hdr.cmd = ISM_QUERY_RGID; -- cmd.request.hdr.len = sizeof(cmd.request); -- -- cmd.request.rgid = rgid; -- cmd.request.vlan_valid = vid_valid; -- cmd.request.vlan_id = vid; -- -- return ism_cmd(ism, &cmd); --} -- - static void ism_free_dmb(struct ism_dev *ism, struct ism_dmb *dmb) - { - clear_bit(dmb->sba_idx, ism->sba_bitmap); -@@ -429,23 +412,6 @@ static int ism_del_vlan_id(struct ism_dev *ism, u64 vlan_id) - return ism_cmd(ism, &cmd); - } - --static int ism_signal_ieq(struct ism_dev *ism, u64 rgid, u32 trigger_irq, -- u32 event_code, u64 info) --{ -- union ism_sig_ieq cmd; -- -- memset(&cmd, 0, sizeof(cmd)); -- cmd.request.hdr.cmd = ISM_SIGNAL_IEQ; -- cmd.request.hdr.len = sizeof(cmd.request); -- -- cmd.request.rgid = rgid; -- cmd.request.trigger_irq = trigger_irq; -- cmd.request.event_code = event_code; -- cmd.request.info = info; -- -- return ism_cmd(ism, &cmd); --} -- - static unsigned int max_bytes(unsigned int start, unsigned int len, - unsigned int boundary) - { -@@ -503,14 +469,6 @@ u8 *ism_get_seid(void) - } - EXPORT_SYMBOL_GPL(ism_get_seid); - --static u16 ism_get_chid(struct ism_dev *ism) --{ -- if (!ism || !ism->pdev) -- return 0; -- -- return to_zpci(ism->pdev)->pchid; --} -- - static void ism_handle_event(struct ism_dev *ism) - { - struct ism_event *entry; -@@ -569,11 +527,6 @@ static irqreturn_t ism_handle_irq(int irq, void *data) - return IRQ_HANDLED; - } - --static u64 ism_get_local_gid(struct ism_dev *ism) --{ -- return ism->local_gid; --} -- - static int ism_dev_init(struct ism_dev *ism) - { - struct pci_dev *pdev = ism->pdev; -@@ -774,6 +727,22 @@ module_exit(ism_exit); - /*************************** SMC-D Implementation *****************************/ - - #if IS_ENABLED(CONFIG_SMC) -+static int ism_query_rgid(struct ism_dev *ism, u64 rgid, u32 vid_valid, -+ u32 vid) -+{ -+ union ism_query_rgid cmd; -+ -+ memset(&cmd, 0, sizeof(cmd)); -+ cmd.request.hdr.cmd = ISM_QUERY_RGID; -+ cmd.request.hdr.len = sizeof(cmd.request); -+ -+ cmd.request.rgid = rgid; -+ cmd.request.vlan_valid = vid_valid; -+ cmd.request.vlan_id = vid; -+ -+ return ism_cmd(ism, &cmd); -+} -+ - static int smcd_query_rgid(struct smcd_dev *smcd, u64 rgid, u32 vid_valid, - u32 vid) - { -@@ -811,6 +780,23 @@ static int smcd_reset_vlan_required(struct smcd_dev *smcd) - return ism_cmd_simple(smcd->priv, ISM_RESET_VLAN); - } - -+static int ism_signal_ieq(struct ism_dev *ism, u64 rgid, u32 trigger_irq, -+ u32 event_code, u64 info) -+{ -+ union ism_sig_ieq cmd; -+ -+ memset(&cmd, 0, sizeof(cmd)); -+ cmd.request.hdr.cmd = ISM_SIGNAL_IEQ; -+ cmd.request.hdr.len = sizeof(cmd.request); -+ -+ cmd.request.rgid = rgid; -+ cmd.request.trigger_irq = trigger_irq; -+ cmd.request.event_code = event_code; -+ cmd.request.info = info; -+ -+ return ism_cmd(ism, &cmd); -+} -+ - static int smcd_signal_ieq(struct smcd_dev *smcd, u64 rgid, u32 trigger_irq, - u32 event_code, u64 info) - { -@@ -830,11 +816,24 @@ static int smcd_supports_v2(void) - SYSTEM_EID.type[0] != '0'; - } - -+static u64 ism_get_local_gid(struct ism_dev *ism) -+{ -+ return ism->local_gid; -+} -+ - static u64 smcd_get_local_gid(struct smcd_dev *smcd) - { - return ism_get_local_gid(smcd->priv); - } - -+static u16 ism_get_chid(struct ism_dev *ism) -+{ -+ if (!ism || !ism->pdev) -+ return 0; -+ -+ return to_zpci(ism->pdev)->pchid; -+} -+ - static u16 smcd_get_chid(struct smcd_dev *smcd) - { - return ism_get_chid(smcd->priv); -diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c -index 1e15ffa7929..44e9b09de47 100644 ---- a/drivers/thunderbolt/switch.c -+++ b/drivers/thunderbolt/switch.c -@@ -1143,7 +1143,7 @@ int tb_port_lane_bonding_enable(struct tb_port *port) - * Only set bonding if the link was not already bonded. This - * avoids the lane adapter to re-enter bonding state. - */ -- if (width == TB_LINK_WIDTH_SINGLE) { -+ if (width == TB_LINK_WIDTH_SINGLE && !tb_is_upstream_port(port)) { - ret = tb_port_set_lane_bonding(port, true); - if (ret) - goto err_lane1; -@@ -2880,6 +2880,7 @@ static int tb_switch_lane_bonding_disable(struct tb_switch *sw) - return tb_port_wait_for_link_width(down, TB_LINK_WIDTH_SINGLE, 100); - } - -+/* Note updating sw->link_width done in tb_switch_update_link_attributes() */ - static int tb_switch_asym_enable(struct tb_switch *sw, enum tb_link_width width) - { - struct tb_port *up, *down, *port; -@@ -2919,10 +2920,10 @@ static int tb_switch_asym_enable(struct tb_switch *sw, enum tb_link_width width) - return ret; - } - -- sw->link_width = width; - return 0; - } - -+/* Note updating sw->link_width done in tb_switch_update_link_attributes() */ - static int tb_switch_asym_disable(struct tb_switch *sw) - { - struct tb_port *up, *down; -@@ -2957,7 +2958,6 @@ static int tb_switch_asym_disable(struct tb_switch *sw) - return ret; - } - -- sw->link_width = TB_LINK_WIDTH_DUAL; - return 0; - } - -diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c -index 5acdeb76686..fd49f86e035 100644 ---- a/drivers/thunderbolt/tb.c -+++ b/drivers/thunderbolt/tb.c -@@ -213,7 +213,17 @@ static void tb_add_dp_resources(struct tb_switch *sw) - if (!tb_switch_query_dp_resource(sw, port)) - continue; - -- list_add(&port->list, &tcm->dp_resources); -+ /* -+ * If DP IN on device router exist, position it at the -+ * beginning of the DP resources list, so that it is used -+ * before DP IN of the host router. This way external GPU(s) -+ * will be prioritized when pairing DP IN to a DP OUT. -+ */ -+ if (tb_route(sw)) -+ list_add(&port->list, &tcm->dp_resources); -+ else -+ list_add_tail(&port->list, &tcm->dp_resources); -+ - tb_port_dbg(port, "DP IN resource available\n"); - } - } -diff --git a/drivers/usb/cdns3/cdnsp-ring.c b/drivers/usb/cdns3/cdnsp-ring.c -index af981778382..02f297f5637 100644 ---- a/drivers/usb/cdns3/cdnsp-ring.c -+++ b/drivers/usb/cdns3/cdnsp-ring.c -@@ -1529,6 +1529,7 @@ irqreturn_t cdnsp_thread_irq_handler(int irq, void *data) - unsigned long flags; - int counter = 0; - -+ local_bh_disable(); - spin_lock_irqsave(&pdev->lock, flags); - - if (pdev->cdnsp_state & (CDNSP_STATE_HALTED | CDNSP_STATE_DYING)) { -@@ -1541,6 +1542,7 @@ irqreturn_t cdnsp_thread_irq_handler(int irq, void *data) - cdnsp_died(pdev); - - spin_unlock_irqrestore(&pdev->lock, flags); -+ local_bh_enable(); - return IRQ_HANDLED; - } - -@@ -1557,6 +1559,7 @@ irqreturn_t cdnsp_thread_irq_handler(int irq, void *data) - cdnsp_update_erst_dequeue(pdev, event_ring_deq, 1); - - spin_unlock_irqrestore(&pdev->lock, flags); -+ local_bh_enable(); - - return IRQ_HANDLED; - } -diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c -index b19e38d5fd1..7f8d33f92dd 100644 ---- a/drivers/usb/core/config.c -+++ b/drivers/usb/core/config.c -@@ -1047,7 +1047,7 @@ int usb_get_bos_descriptor(struct usb_device *dev) - - if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) { - dev_notice(ddev, "descriptor type invalid, skip\n"); -- continue; -+ goto skip_to_next_descriptor; - } - - switch (cap_type) { -@@ -1078,6 +1078,7 @@ int usb_get_bos_descriptor(struct usb_device *dev) - break; - } - -+skip_to_next_descriptor: - total_len -= length; - buffer += length; - } -diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index b4584a0cd48..87480a6e6d9 100644 ---- a/drivers/usb/core/hub.c -+++ b/drivers/usb/core/hub.c -@@ -622,29 +622,6 @@ static int hub_ext_port_status(struct usb_hub *hub, int port1, int type, - ret = 0; - } - mutex_unlock(&hub->status_mutex); -- -- /* -- * There is no need to lock status_mutex here, because status_mutex -- * protects hub->status, and the phy driver only checks the port -- * status without changing the status. -- */ -- if (!ret) { -- struct usb_device *hdev = hub->hdev; -- -- /* -- * Only roothub will be notified of port state changes, -- * since the USB PHY only cares about changes at the next -- * level. -- */ -- if (is_root_hub(hdev)) { -- struct usb_hcd *hcd = bus_to_hcd(hdev->bus); -- -- if (hcd->usb_phy) -- usb_phy_notify_port_status(hcd->usb_phy, -- port1 - 1, *status, *change); -- } -- } -- - return ret; - } - -diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c -index 0144ca8350c..5c7538d498d 100644 ---- a/drivers/usb/dwc2/hcd_intr.c -+++ b/drivers/usb/dwc2/hcd_intr.c -@@ -2015,15 +2015,17 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) - { - struct dwc2_qtd *qtd; - struct dwc2_host_chan *chan; -- u32 hcint, hcintmsk; -+ u32 hcint, hcintraw, hcintmsk; - - chan = hsotg->hc_ptr_array[chnum]; - -- hcint = dwc2_readl(hsotg, HCINT(chnum)); -+ hcintraw = dwc2_readl(hsotg, HCINT(chnum)); - hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum)); -+ hcint = hcintraw & hcintmsk; -+ dwc2_writel(hsotg, hcint, HCINT(chnum)); -+ - if (!chan) { - dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n"); -- dwc2_writel(hsotg, hcint, HCINT(chnum)); - return; - } - -@@ -2032,11 +2034,9 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) - chnum); - dev_vdbg(hsotg->dev, - " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", -- hcint, hcintmsk, hcint & hcintmsk); -+ hcintraw, hcintmsk, hcint); - } - -- dwc2_writel(hsotg, hcint, HCINT(chnum)); -- - /* - * If we got an interrupt after someone called - * dwc2_hcd_endpoint_disable() we don't want to crash below -@@ -2046,8 +2046,7 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) - return; - } - -- chan->hcint = hcint; -- hcint &= hcintmsk; -+ chan->hcint = hcintraw; - - /* - * If the channel was halted due to a dequeue, the qtd list might -diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c -index 0328c86ef80..b101dbf8c5d 100644 ---- a/drivers/usb/dwc3/core.c -+++ b/drivers/usb/dwc3/core.c -@@ -2034,6 +2034,8 @@ static int dwc3_probe(struct platform_device *pdev) - - pm_runtime_put(dev); - -+ dma_set_max_seg_size(dev, UINT_MAX); -+ - return 0; - - err_exit_debugfs: -diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c -index 039bf241769..57ddd2e4302 100644 ---- a/drivers/usb/dwc3/drd.c -+++ b/drivers/usb/dwc3/drd.c -@@ -505,6 +505,7 @@ static int dwc3_setup_role_switch(struct dwc3 *dwc) - dwc->role_switch_default_mode = USB_DR_MODE_PERIPHERAL; - mode = DWC3_GCTL_PRTCAP_DEVICE; - } -+ dwc3_set_mode(dwc, mode); - - dwc3_role_switch.fwnode = dev_fwnode(dwc->dev); - dwc3_role_switch.set = dwc3_usb_role_switch_set; -@@ -526,7 +527,6 @@ static int dwc3_setup_role_switch(struct dwc3 *dwc) - } - } - -- dwc3_set_mode(dwc, mode); - return 0; - } - #else -diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c -index 3de43df6bbe..fdf6d5d3c2a 100644 ---- a/drivers/usb/dwc3/dwc3-qcom.c -+++ b/drivers/usb/dwc3/dwc3-qcom.c -@@ -546,10 +546,9 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev) - pdata ? pdata->hs_phy_irq_index : -1); - if (irq > 0) { - /* Keep wakeup interrupts disabled until suspend */ -- irq_set_status_flags(irq, IRQ_NOAUTOEN); - ret = devm_request_threaded_irq(qcom->dev, irq, NULL, - qcom_dwc3_resume_irq, -- IRQF_TRIGGER_HIGH | IRQF_ONESHOT, -+ IRQF_ONESHOT | IRQF_NO_AUTOEN, - "qcom_dwc3 HS", qcom); - if (ret) { - dev_err(qcom->dev, "hs_phy_irq failed: %d\n", ret); -@@ -561,10 +560,9 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev) - irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq", - pdata ? pdata->dp_hs_phy_irq_index : -1); - if (irq > 0) { -- irq_set_status_flags(irq, IRQ_NOAUTOEN); - ret = devm_request_threaded_irq(qcom->dev, irq, NULL, - qcom_dwc3_resume_irq, -- IRQF_TRIGGER_HIGH | IRQF_ONESHOT, -+ IRQF_ONESHOT | IRQF_NO_AUTOEN, - "qcom_dwc3 DP_HS", qcom); - if (ret) { - dev_err(qcom->dev, "dp_hs_phy_irq failed: %d\n", ret); -@@ -576,10 +574,9 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev) - irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq", - pdata ? pdata->dm_hs_phy_irq_index : -1); - if (irq > 0) { -- irq_set_status_flags(irq, IRQ_NOAUTOEN); - ret = devm_request_threaded_irq(qcom->dev, irq, NULL, - qcom_dwc3_resume_irq, -- IRQF_TRIGGER_HIGH | IRQF_ONESHOT, -+ IRQF_ONESHOT | IRQF_NO_AUTOEN, - "qcom_dwc3 DM_HS", qcom); - if (ret) { - dev_err(qcom->dev, "dm_hs_phy_irq failed: %d\n", ret); -@@ -591,10 +588,9 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev) - irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq", - pdata ? pdata->ss_phy_irq_index : -1); - if (irq > 0) { -- irq_set_status_flags(irq, IRQ_NOAUTOEN); - ret = devm_request_threaded_irq(qcom->dev, irq, NULL, - qcom_dwc3_resume_irq, -- IRQF_TRIGGER_HIGH | IRQF_ONESHOT, -+ IRQF_ONESHOT | IRQF_NO_AUTOEN, - "qcom_dwc3 SS", qcom); - if (ret) { - dev_err(qcom->dev, "ss_phy_irq failed: %d\n", ret); -@@ -758,6 +754,7 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev) - if (!qcom->dwc3) { - ret = -ENODEV; - dev_err(dev, "failed to get dwc3 platform device\n"); -+ of_platform_depopulate(dev); - } - - node_put: -@@ -766,9 +763,9 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev) - return ret; - } - --static struct platform_device * --dwc3_qcom_create_urs_usb_platdev(struct device *dev) -+static struct platform_device *dwc3_qcom_create_urs_usb_platdev(struct device *dev) - { -+ struct platform_device *urs_usb = NULL; - struct fwnode_handle *fwh; - struct acpi_device *adev; - char name[8]; -@@ -788,9 +785,26 @@ dwc3_qcom_create_urs_usb_platdev(struct device *dev) - - adev = to_acpi_device_node(fwh); - if (!adev) -- return NULL; -+ goto err_put_handle; -+ -+ urs_usb = acpi_create_platform_device(adev, NULL); -+ if (IS_ERR_OR_NULL(urs_usb)) -+ goto err_put_handle; -+ -+ return urs_usb; -+ -+err_put_handle: -+ fwnode_handle_put(fwh); -+ -+ return urs_usb; -+} - -- return acpi_create_platform_device(adev, NULL); -+static void dwc3_qcom_destroy_urs_usb_platdev(struct platform_device *urs_usb) -+{ -+ struct fwnode_handle *fwh = urs_usb->dev.fwnode; -+ -+ platform_device_unregister(urs_usb); -+ fwnode_handle_put(fwh); - } - - static int dwc3_qcom_probe(struct platform_device *pdev) -@@ -874,13 +888,13 @@ static int dwc3_qcom_probe(struct platform_device *pdev) - qcom->qscratch_base = devm_ioremap_resource(dev, parent_res); - if (IS_ERR(qcom->qscratch_base)) { - ret = PTR_ERR(qcom->qscratch_base); -- goto clk_disable; -+ goto free_urs; - } - - ret = dwc3_qcom_setup_irq(pdev); - if (ret) { - dev_err(dev, "failed to setup IRQs, err=%d\n", ret); -- goto clk_disable; -+ goto free_urs; - } - - /* -@@ -899,7 +913,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev) - - if (ret) { - dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret); -- goto depopulate; -+ goto free_urs; - } - - ret = dwc3_qcom_interconnect_init(qcom); -@@ -931,10 +945,16 @@ static int dwc3_qcom_probe(struct platform_device *pdev) - interconnect_exit: - dwc3_qcom_interconnect_exit(qcom); - depopulate: -- if (np) -+ if (np) { - of_platform_depopulate(&pdev->dev); -- else -- platform_device_put(pdev); -+ } else { -+ device_remove_software_node(&qcom->dwc3->dev); -+ platform_device_del(qcom->dwc3); -+ } -+ platform_device_put(qcom->dwc3); -+free_urs: -+ if (qcom->urs_usb) -+ dwc3_qcom_destroy_urs_usb_platdev(qcom->urs_usb); - clk_disable: - for (i = qcom->num_clocks - 1; i >= 0; i--) { - clk_disable_unprepare(qcom->clks[i]); -@@ -953,11 +973,16 @@ static void dwc3_qcom_remove(struct platform_device *pdev) - struct device *dev = &pdev->dev; - int i; - -- device_remove_software_node(&qcom->dwc3->dev); -- if (np) -+ if (np) { - of_platform_depopulate(&pdev->dev); -- else -- platform_device_put(pdev); -+ } else { -+ device_remove_software_node(&qcom->dwc3->dev); -+ platform_device_del(qcom->dwc3); -+ } -+ platform_device_put(qcom->dwc3); -+ -+ if (qcom->urs_usb) -+ dwc3_qcom_destroy_urs_usb_platdev(qcom->urs_usb); - - for (i = qcom->num_clocks - 1; i >= 0; i--) { - clk_disable_unprepare(qcom->clks[i]); -diff --git a/drivers/usb/dwc3/dwc3-rtk.c b/drivers/usb/dwc3/dwc3-rtk.c -index 590028e8fdc..3cd6b184551 100644 ---- a/drivers/usb/dwc3/dwc3-rtk.c -+++ b/drivers/usb/dwc3/dwc3-rtk.c -@@ -183,10 +183,13 @@ static enum usb_device_speed __get_dwc3_maximum_speed(struct device_node *np) - - ret = of_property_read_string(dwc3_np, "maximum-speed", &maximum_speed); - if (ret < 0) -- return USB_SPEED_UNKNOWN; -+ goto out; - - ret = match_string(speed_names, ARRAY_SIZE(speed_names), maximum_speed); - -+out: -+ of_node_put(dwc3_np); -+ - return (ret < 0) ? USB_SPEED_UNKNOWN : ret; - } - -@@ -339,6 +342,9 @@ static int dwc3_rtk_probe_dwc3_core(struct dwc3_rtk *rtk) - - switch_usb2_role(rtk, rtk->cur_role); - -+ platform_device_put(dwc3_pdev); -+ of_node_put(dwc3_node); -+ - return 0; - - err_pdev_put: diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c -index 9d1c40c152d..4bb0553da65 100644 +index 3c5a6f6ac34..0f79e888cd6 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c -@@ -1200,7 +1200,7 @@ void gether_disconnect(struct gether *link) +@@ -1202,7 +1202,7 @@ void gether_disconnect(struct gether *link) DBG(dev, "%s\n", __func__); @@ -20603,349 +16249,6 @@ index 9d1c40c152d..4bb0553da65 100644 netif_carrier_off(dev->net); /* disable endpoints, forcing (synchronous) completion -diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c -index 5b3cd455ade..61f3f8bbdce 100644 ---- a/drivers/usb/host/xhci-mtk-sch.c -+++ b/drivers/usb/host/xhci-mtk-sch.c -@@ -650,9 +650,8 @@ static int check_isoc_ss_overlap(struct mu3h_sch_ep_info *sch_ep, u32 offset) - - if (sch_ep->ep_type == ISOC_OUT_EP) { - for (j = 0; j < sch_ep->num_budget_microframes; j++) { -- k = XHCI_MTK_BW_INDEX(base + j + CS_OFFSET); -- /* use cs to indicate existence of in-ss @(base+j) */ -- if (tt->fs_bus_bw_in[k]) -+ k = XHCI_MTK_BW_INDEX(base + j); -+ if (tt->in_ss_cnt[k]) - return -ESCH_SS_OVERLAP; - } - } else if (sch_ep->ep_type == ISOC_IN_EP || sch_ep->ep_type == INT_IN_EP) { -@@ -769,6 +768,14 @@ static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used) - tt->fs_frame_bw[f] -= (u16)sch_ep->bw_budget_table[j]; - } - } -+ -+ if (sch_ep->ep_type == ISOC_IN_EP || sch_ep->ep_type == INT_IN_EP) { -+ k = XHCI_MTK_BW_INDEX(base); -+ if (used) -+ tt->in_ss_cnt[k]++; -+ else -+ tt->in_ss_cnt[k]--; -+ } - } - - if (used) -diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h -index 865b55e23b1..39f7ae7d308 100644 ---- a/drivers/usb/host/xhci-mtk.h -+++ b/drivers/usb/host/xhci-mtk.h -@@ -38,6 +38,7 @@ - * @fs_bus_bw_in: save bandwidth used by FS/LS IN eps in each uframes - * @ls_bus_bw: save bandwidth used by LS eps in each uframes - * @fs_frame_bw: save bandwidth used by FS/LS eps in each FS frames -+ * @in_ss_cnt: the count of Start-Split for IN eps - * @ep_list: Endpoints using this TT - */ - struct mu3h_sch_tt { -@@ -45,6 +46,7 @@ struct mu3h_sch_tt { - u16 fs_bus_bw_in[XHCI_MTK_MAX_ESIT]; - u8 ls_bus_bw[XHCI_MTK_MAX_ESIT]; - u16 fs_frame_bw[XHCI_MTK_FRAMES_CNT]; -+ u8 in_ss_cnt[XHCI_MTK_MAX_ESIT]; - struct list_head ep_list; - }; - -diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c -index b9316137429..732cdeb7392 100644 ---- a/drivers/usb/host/xhci-plat.c -+++ b/drivers/usb/host/xhci-plat.c -@@ -13,6 +13,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -148,7 +149,7 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s - int ret; - int irq; - struct xhci_plat_priv *priv = NULL; -- -+ bool of_match; - - if (usb_disabled()) - return -ENODEV; -@@ -253,16 +254,23 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s - &xhci->imod_interval); - } - -- hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0); -- if (IS_ERR(hcd->usb_phy)) { -- ret = PTR_ERR(hcd->usb_phy); -- if (ret == -EPROBE_DEFER) -- goto disable_clk; -- hcd->usb_phy = NULL; -- } else { -- ret = usb_phy_init(hcd->usb_phy); -- if (ret) -- goto disable_clk; -+ /* -+ * Drivers such as dwc3 manages PHYs themself (and rely on driver name -+ * matching for the xhci platform device). -+ */ -+ of_match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); -+ if (of_match) { -+ hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0); -+ if (IS_ERR(hcd->usb_phy)) { -+ ret = PTR_ERR(hcd->usb_phy); -+ if (ret == -EPROBE_DEFER) -+ goto disable_clk; -+ hcd->usb_phy = NULL; -+ } else { -+ ret = usb_phy_init(hcd->usb_phy); -+ if (ret) -+ goto disable_clk; -+ } - } - - hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); -@@ -285,15 +293,17 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s - goto dealloc_usb2_hcd; - } - -- xhci->shared_hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, -- "usb-phy", 1); -- if (IS_ERR(xhci->shared_hcd->usb_phy)) { -- xhci->shared_hcd->usb_phy = NULL; -- } else { -- ret = usb_phy_init(xhci->shared_hcd->usb_phy); -- if (ret) -- dev_err(sysdev, "%s init usb3phy fail (ret=%d)\n", -- __func__, ret); -+ if (of_match) { -+ xhci->shared_hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, -+ "usb-phy", 1); -+ if (IS_ERR(xhci->shared_hcd->usb_phy)) { -+ xhci->shared_hcd->usb_phy = NULL; -+ } else { -+ ret = usb_phy_init(xhci->shared_hcd->usb_phy); -+ if (ret) -+ dev_err(sysdev, "%s init usb3phy fail (ret=%d)\n", -+ __func__, ret); -+ } - } - - xhci->shared_hcd->tpl_support = hcd->tpl_support; -diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c -index a341b2fbb7b..2b45404e973 100644 ---- a/drivers/usb/misc/onboard_usb_hub.c -+++ b/drivers/usb/misc/onboard_usb_hub.c -@@ -432,6 +432,8 @@ static const struct usb_device_id onboard_hub_id_table[] = { - { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2412) }, /* USB2412 USB 2.0 */ - { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2514) }, /* USB2514B USB 2.0 */ - { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2517) }, /* USB2517 USB 2.0 */ -+ { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2744) }, /* USB5744 USB 2.0 */ -+ { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x5744) }, /* USB5744 USB 3.0 */ - { USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 */ - { USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 */ - { USB_DEVICE(VENDOR_ID_REALTEK, 0x0414) }, /* RTS5414 USB 3.2 */ -diff --git a/drivers/usb/misc/onboard_usb_hub.h b/drivers/usb/misc/onboard_usb_hub.h -index c4e24a7b929..292110e64a1 100644 ---- a/drivers/usb/misc/onboard_usb_hub.h -+++ b/drivers/usb/misc/onboard_usb_hub.h -@@ -16,6 +16,11 @@ static const struct onboard_hub_pdata microchip_usb424_data = { - .num_supplies = 1, - }; - -+static const struct onboard_hub_pdata microchip_usb5744_data = { -+ .reset_us = 0, -+ .num_supplies = 2, -+}; -+ - static const struct onboard_hub_pdata realtek_rts5411_data = { - .reset_us = 0, - .num_supplies = 1, -@@ -50,6 +55,8 @@ static const struct of_device_id onboard_hub_match[] = { - { .compatible = "usb424,2412", .data = µchip_usb424_data, }, - { .compatible = "usb424,2514", .data = µchip_usb424_data, }, - { .compatible = "usb424,2517", .data = µchip_usb424_data, }, -+ { .compatible = "usb424,2744", .data = µchip_usb5744_data, }, -+ { .compatible = "usb424,5744", .data = µchip_usb5744_data, }, - { .compatible = "usb451,8140", .data = &ti_tusb8041_data, }, - { .compatible = "usb451,8142", .data = &ti_tusb8041_data, }, - { .compatible = "usb4b4,6504", .data = &cypress_hx3_data, }, -diff --git a/drivers/usb/misc/usb-ljca.c b/drivers/usb/misc/usb-ljca.c -index c9decd0396d..35770e608c6 100644 ---- a/drivers/usb/misc/usb-ljca.c -+++ b/drivers/usb/misc/usb-ljca.c -@@ -457,8 +457,8 @@ static void ljca_auxdev_acpi_bind(struct ljca_adapter *adap, - u64 adr, u8 id) - { - struct ljca_match_ids_walk_data wd = { 0 }; -- struct acpi_device *parent, *adev; - struct device *dev = adap->dev; -+ struct acpi_device *parent; - char uid[4]; - - parent = ACPI_COMPANION(dev); -@@ -466,17 +466,7 @@ static void ljca_auxdev_acpi_bind(struct ljca_adapter *adap, - return; - - /* -- * get auxdev ACPI handle from the ACPI device directly -- * under the parent that matches _ADR. -- */ -- adev = acpi_find_child_device(parent, adr, false); -- if (adev) { -- ACPI_COMPANION_SET(&auxdev->dev, adev); -- return; -- } -- -- /* -- * _ADR is a grey area in the ACPI specification, some -+ * Currently LJCA hw doesn't use _ADR instead the shipped - * platforms use _HID to distinguish children devices. - */ - switch (adr) { -@@ -656,10 +646,11 @@ static int ljca_enumerate_spi(struct ljca_adapter *adap) - unsigned int i; - int ret; - -+ /* Not all LJCA chips implement SPI, a timeout reading the descriptors is normal */ - ret = ljca_send(adap, LJCA_CLIENT_MNG, LJCA_MNG_ENUM_SPI, NULL, 0, buf, - sizeof(buf), true, LJCA_ENUM_CLIENT_TIMEOUT_MS); - if (ret < 0) -- return ret; -+ return (ret == -ETIMEDOUT) ? 0 : ret; - - /* check firmware response */ - desc = (struct ljca_spi_descriptor *)buf; -diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c -index 45dcfaadaf9..4dffcfefd62 100644 ---- a/drivers/usb/serial/option.c -+++ b/drivers/usb/serial/option.c -@@ -203,8 +203,8 @@ static void option_instat_callback(struct urb *urb); - #define DELL_PRODUCT_5829E_ESIM 0x81e4 - #define DELL_PRODUCT_5829E 0x81e6 - --#define DELL_PRODUCT_FM101R 0x8213 --#define DELL_PRODUCT_FM101R_ESIM 0x8215 -+#define DELL_PRODUCT_FM101R_ESIM 0x8213 -+#define DELL_PRODUCT_FM101R 0x8215 - - #define KYOCERA_VENDOR_ID 0x0c88 - #define KYOCERA_PRODUCT_KPC650 0x17da -@@ -609,6 +609,8 @@ static void option_instat_callback(struct urb *urb); - #define UNISOC_VENDOR_ID 0x1782 - /* TOZED LT70-C based on UNISOC SL8563 uses UNISOC's vendor ID */ - #define TOZED_PRODUCT_LT70C 0x4055 -+/* Luat Air72*U series based on UNISOC UIS8910 uses UNISOC's vendor ID */ -+#define LUAT_PRODUCT_AIR720U 0x4e00 - - /* Device flags */ - -@@ -1546,7 +1548,8 @@ static const struct usb_device_id option_ids[] = { - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff), - .driver_info = RSVD(4) }, -- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0189, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0189, 0xff, 0xff, 0xff), -+ .driver_info = RSVD(4) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0191, 0xff, 0xff, 0xff), /* ZTE EuFi890 */ - .driver_info = RSVD(4) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0196, 0xff, 0xff, 0xff) }, -@@ -2249,6 +2252,7 @@ static const struct usb_device_id option_ids[] = { - .driver_info = RSVD(4) | RSVD(5) | RSVD(6) }, - { USB_DEVICE(0x1782, 0x4d10) }, /* Fibocom L610 (AT mode) */ - { USB_DEVICE_INTERFACE_CLASS(0x1782, 0x4d11, 0xff) }, /* Fibocom L610 (ECM/RNDIS mode) */ -+ { USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x0001, 0xff, 0xff, 0xff) }, /* Fibocom L716-EU (ECM/RNDIS mode) */ - { USB_DEVICE(0x2cb7, 0x0104), /* Fibocom NL678 series */ - .driver_info = RSVD(4) | RSVD(5) }, - { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0105, 0xff), /* Fibocom NL678 series */ -@@ -2271,6 +2275,7 @@ static const struct usb_device_id option_ids[] = { - { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x40) }, - { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, LUAT_PRODUCT_AIR720U, 0xff, 0, 0) }, - { } /* Terminating entry */ - }; - MODULE_DEVICE_TABLE(usb, option_ids); -diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c -index 058d5b853b5..bfb6f9481e8 100644 ---- a/drivers/usb/typec/tcpm/tcpm.c -+++ b/drivers/usb/typec/tcpm/tcpm.c -@@ -4273,7 +4273,8 @@ static void run_state_machine(struct tcpm_port *port) - current_lim = PD_P_SNK_STDBY_MW / 5; - tcpm_set_current_limit(port, current_lim, 5000); - /* Not sink vbus if operational current is 0mA */ -- tcpm_set_charge(port, !!pdo_max_current(port->snk_pdo[0])); -+ tcpm_set_charge(port, !port->pd_supported || -+ pdo_max_current(port->snk_pdo[0])); - - if (!port->pd_supported) - tcpm_set_state(port, SNK_READY, 0); -@@ -5391,6 +5392,15 @@ static void _tcpm_pd_hard_reset(struct tcpm_port *port) - if (port->bist_request == BDO_MODE_TESTDATA && port->tcpc->set_bist_data) - port->tcpc->set_bist_data(port->tcpc, false); - -+ switch (port->state) { -+ case ERROR_RECOVERY: -+ case PORT_RESET: -+ case PORT_RESET_WAIT_OFF: -+ return; -+ default: -+ break; -+ } -+ - if (port->ams != NONE_AMS) - port->ams = NONE_AMS; - if (port->hard_reset_count < PD_N_HARD_RESET_COUNT) -diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c -index 0e867f531d3..196535ad996 100644 ---- a/drivers/usb/typec/tipd/core.c -+++ b/drivers/usb/typec/tipd/core.c -@@ -968,16 +968,17 @@ static int tps25750_start_patch_burst_mode(struct tps6598x *tps) - ret = of_property_match_string(np, "reg-names", "patch-address"); - if (ret < 0) { - dev_err(tps->dev, "failed to get patch-address %d\n", ret); -- return ret; -+ goto release_fw; - } - - ret = of_property_read_u32_index(np, "reg", ret, &addr); - if (ret) -- return ret; -+ goto release_fw; - - if (addr == 0 || (addr >= 0x20 && addr <= 0x23)) { - dev_err(tps->dev, "wrong patch address %u\n", addr); -- return -EINVAL; -+ ret = -EINVAL; -+ goto release_fw; - } - - bpms_data.addr = (u8)addr; -@@ -1226,7 +1227,10 @@ static int tps6598x_probe(struct i2c_client *client) - TPS_REG_INT_PLUG_EVENT; - } - -- tps->data = device_get_match_data(tps->dev); -+ if (dev_fwnode(tps->dev)) -+ tps->data = device_get_match_data(tps->dev); -+ else -+ tps->data = i2c_get_match_data(client); - if (!tps->data) - return -EINVAL; - -@@ -1425,7 +1429,7 @@ static const struct of_device_id tps6598x_of_match[] = { - MODULE_DEVICE_TABLE(of, tps6598x_of_match); - - static const struct i2c_device_id tps6598x_id[] = { -- { "tps6598x" }, -+ { "tps6598x", (kernel_ulong_t)&tps6598x_data }, - { } - }; - MODULE_DEVICE_TABLE(i2c, tps6598x_id); diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 10129095a4c..6d3016e008e 100644 --- a/drivers/video/backlight/qcom-wled.c @@ -20992,2076 +16295,6 @@ index 10129095a4c..6d3016e008e 100644 } static const struct of_device_id wled_match_table[] = { -diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c -index 1ce7f3c7a95..0eb337a8ec0 100644 ---- a/drivers/xen/privcmd.c -+++ b/drivers/xen/privcmd.c -@@ -1115,7 +1115,7 @@ struct privcmd_kernel_ioreq { - spinlock_t lock; /* Protects ioeventfds list */ - struct list_head ioeventfds; - struct list_head list; -- struct ioreq_port ports[0]; -+ struct ioreq_port ports[] __counted_by(vcpus); - }; - - static irqreturn_t ioeventfd_interrupt(int irq, void *dev_id) -diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c -index 946bd56f0ac..0e6c6c25d15 100644 ---- a/drivers/xen/swiotlb-xen.c -+++ b/drivers/xen/swiotlb-xen.c -@@ -405,4 +405,5 @@ const struct dma_map_ops xen_swiotlb_dma_ops = { - .get_sgtable = dma_common_get_sgtable, - .alloc_pages = dma_common_alloc_pages, - .free_pages = dma_common_free_pages, -+ .max_mapping_size = swiotlb_max_mapping_size, - }; -diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c -index 4d04ef2d3ae..1fa8cf23bd3 100644 ---- a/fs/afs/dynroot.c -+++ b/fs/afs/dynroot.c -@@ -132,8 +132,8 @@ static int afs_probe_cell_name(struct dentry *dentry) - - ret = dns_query(net->net, "afsdb", name, len, "srv=1", - NULL, NULL, false); -- if (ret == -ENODATA) -- ret = -EDESTADDRREQ; -+ if (ret == -ENODATA || ret == -ENOKEY) -+ ret = -ENOENT; - return ret; - } - -diff --git a/fs/afs/internal.h b/fs/afs/internal.h -index c9cef3782b4..a812952be1c 100644 ---- a/fs/afs/internal.h -+++ b/fs/afs/internal.h -@@ -553,6 +553,7 @@ struct afs_server_entry { - }; - - struct afs_server_list { -+ struct rcu_head rcu; - afs_volid_t vids[AFS_MAXTYPES]; /* Volume IDs */ - refcount_t usage; - unsigned char nr_servers; -diff --git a/fs/afs/server_list.c b/fs/afs/server_list.c -index ed905670350..b59896b1de0 100644 ---- a/fs/afs/server_list.c -+++ b/fs/afs/server_list.c -@@ -17,7 +17,7 @@ void afs_put_serverlist(struct afs_net *net, struct afs_server_list *slist) - for (i = 0; i < slist->nr_servers; i++) - afs_unuse_server(net, slist->servers[i].server, - afs_server_trace_put_slist); -- kfree(slist); -+ kfree_rcu(slist, rcu); - } - } - -diff --git a/fs/afs/super.c b/fs/afs/super.c -index 95d713074dc..a01a0fb2cdb 100644 ---- a/fs/afs/super.c -+++ b/fs/afs/super.c -@@ -407,6 +407,10 @@ static int afs_validate_fc(struct fs_context *fc) - return PTR_ERR(volume); - - ctx->volume = volume; -+ if (volume->type != AFSVL_RWVOL) { -+ ctx->flock_mode = afs_flock_mode_local; -+ fc->sb_flags |= SB_RDONLY; -+ } - } - - return 0; -diff --git a/fs/afs/vl_rotate.c b/fs/afs/vl_rotate.c -index 488e58490b1..eb415ce5636 100644 ---- a/fs/afs/vl_rotate.c -+++ b/fs/afs/vl_rotate.c -@@ -58,6 +58,12 @@ static bool afs_start_vl_iteration(struct afs_vl_cursor *vc) - } - - /* Status load is ordered after lookup counter load */ -+ if (cell->dns_status == DNS_LOOKUP_GOT_NOT_FOUND) { -+ pr_warn("No record of cell %s\n", cell->name); -+ vc->error = -ENOENT; -+ return false; -+ } -+ - if (cell->dns_source == DNS_RECORD_UNAVAILABLE) { - vc->error = -EDESTADDRREQ; - return false; -@@ -285,6 +291,7 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc) - */ - static void afs_vl_dump_edestaddrreq(const struct afs_vl_cursor *vc) - { -+ struct afs_cell *cell = vc->cell; - static int count; - int i; - -@@ -294,6 +301,9 @@ static void afs_vl_dump_edestaddrreq(const struct afs_vl_cursor *vc) - - rcu_read_lock(); - pr_notice("EDESTADDR occurred\n"); -+ pr_notice("CELL: %s err=%d\n", cell->name, cell->error); -+ pr_notice("DNS: src=%u st=%u lc=%x\n", -+ cell->dns_source, cell->dns_status, cell->dns_lookup_count); - pr_notice("VC: ut=%lx ix=%u ni=%hu fl=%hx err=%hd\n", - vc->untried, vc->index, vc->nr_iterations, vc->flags, vc->error); - -diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c -index a5083d447a6..1f5db686366 100644 ---- a/fs/autofs/inode.c -+++ b/fs/autofs/inode.c -@@ -309,9 +309,7 @@ static int autofs_fill_super(struct super_block *s, struct fs_context *fc) - struct autofs_fs_context *ctx = fc->fs_private; - struct autofs_sb_info *sbi = s->s_fs_info; - struct inode *root_inode; -- struct dentry *root; - struct autofs_info *ino; -- int ret = -ENOMEM; - - pr_debug("starting up, sbi = %p\n", sbi); - -@@ -328,56 +326,44 @@ static int autofs_fill_super(struct super_block *s, struct fs_context *fc) - */ - ino = autofs_new_ino(sbi); - if (!ino) -- goto fail; -+ return -ENOMEM; - - root_inode = autofs_get_inode(s, S_IFDIR | 0755); -+ if (!root_inode) -+ return -ENOMEM; -+ - root_inode->i_uid = ctx->uid; - root_inode->i_gid = ctx->gid; -+ root_inode->i_fop = &autofs_root_operations; -+ root_inode->i_op = &autofs_dir_inode_operations; - -- root = d_make_root(root_inode); -- if (!root) -- goto fail_ino; -- -- root->d_fsdata = ino; -+ s->s_root = d_make_root(root_inode); -+ if (unlikely(!s->s_root)) { -+ autofs_free_ino(ino); -+ return -ENOMEM; -+ } -+ s->s_root->d_fsdata = ino; - - if (ctx->pgrp_set) { - sbi->oz_pgrp = find_get_pid(ctx->pgrp); -- if (!sbi->oz_pgrp) { -- ret = invalf(fc, "Could not find process group %d", -- ctx->pgrp); -- goto fail_dput; -- } -- } else { -+ if (!sbi->oz_pgrp) -+ return invalf(fc, "Could not find process group %d", -+ ctx->pgrp); -+ } else - sbi->oz_pgrp = get_task_pid(current, PIDTYPE_PGID); -- } - - if (autofs_type_trigger(sbi->type)) -- __managed_dentry_set_managed(root); -- -- root_inode->i_fop = &autofs_root_operations; -- root_inode->i_op = &autofs_dir_inode_operations; -+ /* s->s_root won't be contended so there's little to -+ * be gained by not taking the d_lock when setting -+ * d_flags, even when a lot mounts are being done. -+ */ -+ managed_dentry_set_managed(s->s_root); - - pr_debug("pipe fd = %d, pgrp = %u\n", - sbi->pipefd, pid_nr(sbi->oz_pgrp)); - - sbi->flags &= ~AUTOFS_SBI_CATATONIC; -- -- /* -- * Success! Install the root dentry now to indicate completion. -- */ -- s->s_root = root; - return 0; -- -- /* -- * Failure ... clean up. -- */ --fail_dput: -- dput(root); -- goto fail; --fail_ino: -- autofs_free_ino(ino); --fail: -- return ret; - } - - /* -diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c -index a25dd3d2000..b0e8774c435 100644 ---- a/fs/ecryptfs/inode.c -+++ b/fs/ecryptfs/inode.c -@@ -998,6 +998,14 @@ static int ecryptfs_getattr_link(struct mnt_idmap *idmap, - return rc; - } - -+static int ecryptfs_do_getattr(const struct path *path, struct kstat *stat, -+ u32 request_mask, unsigned int flags) -+{ -+ if (flags & AT_GETATTR_NOSEC) -+ return vfs_getattr_nosec(path, stat, request_mask, flags); -+ return vfs_getattr(path, stat, request_mask, flags); -+} -+ - static int ecryptfs_getattr(struct mnt_idmap *idmap, - const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int flags) -@@ -1006,8 +1014,8 @@ static int ecryptfs_getattr(struct mnt_idmap *idmap, - struct kstat lower_stat; - int rc; - -- rc = vfs_getattr(ecryptfs_dentry_to_lower_path(dentry), &lower_stat, -- request_mask, flags); -+ rc = ecryptfs_do_getattr(ecryptfs_dentry_to_lower_path(dentry), -+ &lower_stat, request_mask, flags); - if (!rc) { - fsstack_copy_attr_all(d_inode(dentry), - ecryptfs_inode_to_lower(d_inode(dentry))); -diff --git a/fs/erofs/Kconfig b/fs/erofs/Kconfig -index e540648dedc..1d318f85232 100644 ---- a/fs/erofs/Kconfig -+++ b/fs/erofs/Kconfig -@@ -21,7 +21,7 @@ config EROFS_FS - performance under extremely memory pressure without extra cost. - - See the documentation at -- for more details. -+ and the web pages at for more details. - - If unsure, say N. - -diff --git a/fs/erofs/data.c b/fs/erofs/data.c -index 029c761670b..c98aeda8abb 100644 ---- a/fs/erofs/data.c -+++ b/fs/erofs/data.c -@@ -220,7 +220,7 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map) - up_read(&devs->rwsem); - return 0; - } -- map->m_bdev = dif->bdev_handle->bdev; -+ map->m_bdev = dif->bdev_handle ? dif->bdev_handle->bdev : NULL; - map->m_daxdev = dif->dax_dev; - map->m_dax_part_off = dif->dax_part_off; - map->m_fscache = dif->fscache; -@@ -238,7 +238,8 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map) - if (map->m_pa >= startoff && - map->m_pa < startoff + length) { - map->m_pa -= startoff; -- map->m_bdev = dif->bdev_handle->bdev; -+ map->m_bdev = dif->bdev_handle ? -+ dif->bdev_handle->bdev : NULL; - map->m_daxdev = dif->dax_dev; - map->m_dax_part_off = dif->dax_part_off; - map->m_fscache = dif->fscache; -diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c -index b8ad05b4509..14a79d3226a 100644 ---- a/fs/erofs/inode.c -+++ b/fs/erofs/inode.c -@@ -15,11 +15,11 @@ static void *erofs_read_inode(struct erofs_buf *buf, - struct erofs_sb_info *sbi = EROFS_SB(sb); - struct erofs_inode *vi = EROFS_I(inode); - const erofs_off_t inode_loc = erofs_iloc(inode); -- - erofs_blk_t blkaddr, nblks = 0; - void *kaddr; - struct erofs_inode_compact *dic; - struct erofs_inode_extended *die, *copied = NULL; -+ union erofs_inode_i_u iu; - unsigned int ifmt; - int err; - -@@ -35,9 +35,8 @@ static void *erofs_read_inode(struct erofs_buf *buf, - - dic = kaddr + *ofs; - ifmt = le16_to_cpu(dic->i_format); -- - if (ifmt & ~EROFS_I_ALL) { -- erofs_err(inode->i_sb, "unsupported i_format %u of nid %llu", -+ erofs_err(sb, "unsupported i_format %u of nid %llu", - ifmt, vi->nid); - err = -EOPNOTSUPP; - goto err_out; -@@ -45,7 +44,7 @@ static void *erofs_read_inode(struct erofs_buf *buf, - - vi->datalayout = erofs_inode_datalayout(ifmt); - if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) { -- erofs_err(inode->i_sb, "unsupported datalayout %u of nid %llu", -+ erofs_err(sb, "unsupported datalayout %u of nid %llu", - vi->datalayout, vi->nid); - err = -EOPNOTSUPP; - goto err_out; -@@ -82,40 +81,15 @@ static void *erofs_read_inode(struct erofs_buf *buf, - vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount); - - inode->i_mode = le16_to_cpu(die->i_mode); -- switch (inode->i_mode & S_IFMT) { -- case S_IFREG: -- case S_IFDIR: -- case S_IFLNK: -- vi->raw_blkaddr = le32_to_cpu(die->i_u.raw_blkaddr); -- break; -- case S_IFCHR: -- case S_IFBLK: -- inode->i_rdev = -- new_decode_dev(le32_to_cpu(die->i_u.rdev)); -- break; -- case S_IFIFO: -- case S_IFSOCK: -- inode->i_rdev = 0; -- break; -- default: -- goto bogusimode; -- } -+ iu = die->i_u; - i_uid_write(inode, le32_to_cpu(die->i_uid)); - i_gid_write(inode, le32_to_cpu(die->i_gid)); - set_nlink(inode, le32_to_cpu(die->i_nlink)); -- -- /* extended inode has its own timestamp */ -+ /* each extended inode has its own timestamp */ - inode_set_ctime(inode, le64_to_cpu(die->i_mtime), - le32_to_cpu(die->i_mtime_nsec)); - - inode->i_size = le64_to_cpu(die->i_size); -- -- /* total blocks for compressed files */ -- if (erofs_inode_is_data_compressed(vi->datalayout)) -- nblks = le32_to_cpu(die->i_u.compressed_blocks); -- else if (vi->datalayout == EROFS_INODE_CHUNK_BASED) -- /* fill chunked inode summary info */ -- vi->chunkformat = le16_to_cpu(die->i_u.c.format); - kfree(copied); - copied = NULL; - break; -@@ -125,49 +99,51 @@ static void *erofs_read_inode(struct erofs_buf *buf, - vi->xattr_isize = erofs_xattr_ibody_size(dic->i_xattr_icount); - - inode->i_mode = le16_to_cpu(dic->i_mode); -- switch (inode->i_mode & S_IFMT) { -- case S_IFREG: -- case S_IFDIR: -- case S_IFLNK: -- vi->raw_blkaddr = le32_to_cpu(dic->i_u.raw_blkaddr); -- break; -- case S_IFCHR: -- case S_IFBLK: -- inode->i_rdev = -- new_decode_dev(le32_to_cpu(dic->i_u.rdev)); -- break; -- case S_IFIFO: -- case S_IFSOCK: -- inode->i_rdev = 0; -- break; -- default: -- goto bogusimode; -- } -+ iu = dic->i_u; - i_uid_write(inode, le16_to_cpu(dic->i_uid)); - i_gid_write(inode, le16_to_cpu(dic->i_gid)); - set_nlink(inode, le16_to_cpu(dic->i_nlink)); -- - /* use build time for compact inodes */ - inode_set_ctime(inode, sbi->build_time, sbi->build_time_nsec); - - inode->i_size = le32_to_cpu(dic->i_size); -- if (erofs_inode_is_data_compressed(vi->datalayout)) -- nblks = le32_to_cpu(dic->i_u.compressed_blocks); -- else if (vi->datalayout == EROFS_INODE_CHUNK_BASED) -- vi->chunkformat = le16_to_cpu(dic->i_u.c.format); - break; - default: -- erofs_err(inode->i_sb, -- "unsupported on-disk inode version %u of nid %llu", -+ erofs_err(sb, "unsupported on-disk inode version %u of nid %llu", - erofs_inode_version(ifmt), vi->nid); - err = -EOPNOTSUPP; - goto err_out; - } - -- if (vi->datalayout == EROFS_INODE_CHUNK_BASED) { -+ switch (inode->i_mode & S_IFMT) { -+ case S_IFREG: -+ case S_IFDIR: -+ case S_IFLNK: -+ vi->raw_blkaddr = le32_to_cpu(iu.raw_blkaddr); -+ break; -+ case S_IFCHR: -+ case S_IFBLK: -+ inode->i_rdev = new_decode_dev(le32_to_cpu(iu.rdev)); -+ break; -+ case S_IFIFO: -+ case S_IFSOCK: -+ inode->i_rdev = 0; -+ break; -+ default: -+ erofs_err(sb, "bogus i_mode (%o) @ nid %llu", inode->i_mode, -+ vi->nid); -+ err = -EFSCORRUPTED; -+ goto err_out; -+ } -+ -+ /* total blocks for compressed files */ -+ if (erofs_inode_is_data_compressed(vi->datalayout)) { -+ nblks = le32_to_cpu(iu.compressed_blocks); -+ } else if (vi->datalayout == EROFS_INODE_CHUNK_BASED) { -+ /* fill chunked inode summary info */ -+ vi->chunkformat = le16_to_cpu(iu.c.format); - if (vi->chunkformat & ~EROFS_CHUNK_FORMAT_ALL) { -- erofs_err(inode->i_sb, -- "unsupported chunk format %x of nid %llu", -+ erofs_err(sb, "unsupported chunk format %x of nid %llu", - vi->chunkformat, vi->nid); - err = -EOPNOTSUPP; - goto err_out; -@@ -191,10 +167,6 @@ static void *erofs_read_inode(struct erofs_buf *buf, - inode->i_blocks = nblks << (sb->s_blocksize_bits - 9); - return kaddr; - --bogusimode: -- erofs_err(inode->i_sb, "bogus i_mode (%o) @ nid %llu", -- inode->i_mode, vi->nid); -- err = -EFSCORRUPTED; - err_out: - DBG_BUGON(1); - kfree(copied); -diff --git a/fs/inode.c b/fs/inode.c -index edcd8a61975..f238d987dec 100644 ---- a/fs/inode.c -+++ b/fs/inode.c -@@ -215,6 +215,8 @@ int inode_init_always(struct super_block *sb, struct inode *inode) - lockdep_set_class_and_name(&mapping->invalidate_lock, - &sb->s_type->invalidate_lock_key, - "mapping.invalidate_lock"); -+ if (sb->s_iflags & SB_I_STABLE_WRITES) -+ mapping_set_stable_writes(mapping); - inode->i_private = NULL; - inode->i_mapping = mapping; - INIT_HLIST_HEAD(&inode->i_dentry); /* buggered by rcu freeing */ -diff --git a/fs/libfs.c b/fs/libfs.c -index e9440d55073..c2aa6fd4795 100644 ---- a/fs/libfs.c -+++ b/fs/libfs.c -@@ -399,6 +399,8 @@ static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence) - return -EINVAL; - } - -+ /* In this case, ->private_data is protected by f_pos_lock */ -+ file->private_data = NULL; - return vfs_setpos(file, offset, U32_MAX); - } - -@@ -428,7 +430,7 @@ static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry) - inode->i_ino, fs_umode_to_dtype(inode->i_mode)); - } - --static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx) -+static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx) - { - struct offset_ctx *so_ctx = inode->i_op->get_offset_ctx(inode); - XA_STATE(xas, &so_ctx->xa, ctx->pos); -@@ -437,7 +439,7 @@ static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx) - while (true) { - dentry = offset_find_next(&xas); - if (!dentry) -- break; -+ return ERR_PTR(-ENOENT); - - if (!offset_dir_emit(ctx, dentry)) { - dput(dentry); -@@ -447,6 +449,7 @@ static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx) - dput(dentry); - ctx->pos = xas.xa_index + 1; - } -+ return NULL; - } - - /** -@@ -479,7 +482,12 @@ static int offset_readdir(struct file *file, struct dir_context *ctx) - if (!dir_emit_dots(file, ctx)) - return 0; - -- offset_iterate_dir(d_inode(dir), ctx); -+ /* In this case, ->private_data is protected by f_pos_lock */ -+ if (ctx->pos == 2) -+ file->private_data = NULL; -+ else if (file->private_data == ERR_PTR(-ENOENT)) -+ return 0; -+ file->private_data = offset_iterate_dir(d_inode(dir), ctx); - return 0; - } - -diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c -index 345b8f161ca..c63b31a460b 100644 ---- a/fs/overlayfs/inode.c -+++ b/fs/overlayfs/inode.c -@@ -171,7 +171,7 @@ int ovl_getattr(struct mnt_idmap *idmap, const struct path *path, - - type = ovl_path_real(dentry, &realpath); - old_cred = ovl_override_creds(dentry->d_sb); -- err = vfs_getattr(&realpath, stat, request_mask, flags); -+ err = ovl_do_getattr(&realpath, stat, request_mask, flags); - if (err) - goto out; - -@@ -196,8 +196,8 @@ int ovl_getattr(struct mnt_idmap *idmap, const struct path *path, - (!is_dir ? STATX_NLINK : 0); - - ovl_path_lower(dentry, &realpath); -- err = vfs_getattr(&realpath, &lowerstat, -- lowermask, flags); -+ err = ovl_do_getattr(&realpath, &lowerstat, lowermask, -+ flags); - if (err) - goto out; - -@@ -249,8 +249,8 @@ int ovl_getattr(struct mnt_idmap *idmap, const struct path *path, - - ovl_path_lowerdata(dentry, &realpath); - if (realpath.dentry) { -- err = vfs_getattr(&realpath, &lowerdatastat, -- lowermask, flags); -+ err = ovl_do_getattr(&realpath, &lowerdatastat, -+ lowermask, flags); - if (err) - goto out; - } else { -diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h -index ca88b2636a5..05c3dd597fa 100644 ---- a/fs/overlayfs/overlayfs.h -+++ b/fs/overlayfs/overlayfs.h -@@ -408,6 +408,14 @@ static inline bool ovl_open_flags_need_copy_up(int flags) - return ((OPEN_FMODE(flags) & FMODE_WRITE) || (flags & O_TRUNC)); - } - -+static inline int ovl_do_getattr(const struct path *path, struct kstat *stat, -+ u32 request_mask, unsigned int flags) -+{ -+ if (flags & AT_GETATTR_NOSEC) -+ return vfs_getattr_nosec(path, stat, request_mask, flags); -+ return vfs_getattr(path, stat, request_mask, flags); -+} -+ - /* util.c */ - int ovl_get_write_access(struct dentry *dentry); - void ovl_put_write_access(struct dentry *dentry); -diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h -index 6ffbd81bd10..7558167f603 100644 ---- a/fs/smb/client/cifsglob.h -+++ b/fs/smb/client/cifsglob.h -@@ -191,7 +191,13 @@ struct cifs_open_info_data { - bool reparse_point; - bool symlink; - }; -- __u32 reparse_tag; -+ struct { -+ __u32 tag; -+ union { -+ struct reparse_data_buffer *buf; -+ struct reparse_posix_data *posix; -+ }; -+ } reparse; - char *symlink_target; - union { - struct smb2_file_all_info fi; -@@ -395,8 +401,7 @@ struct smb_version_operations { - struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, - const char *full_path, -- char **target_path, -- struct kvec *rsp_iov); -+ char **target_path); - /* open a file for non-posix mounts */ - int (*open)(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock, - void *buf); -@@ -551,6 +556,9 @@ struct smb_version_operations { - bool (*is_status_io_timeout)(char *buf); - /* Check for STATUS_NETWORK_NAME_DELETED */ - bool (*is_network_name_deleted)(char *buf, struct TCP_Server_Info *srv); -+ int (*parse_reparse_point)(struct cifs_sb_info *cifs_sb, -+ struct kvec *rsp_iov, -+ struct cifs_open_info_data *data); - }; - - struct smb_version_values { -diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h -index a75220db5c1..83ccc51a54d 100644 ---- a/fs/smb/client/cifspdu.h -+++ b/fs/smb/client/cifspdu.h -@@ -1356,7 +1356,7 @@ typedef struct smb_com_transaction_ioctl_rsp { - __le32 DataDisplacement; - __u8 SetupCount; /* 1 */ - __le16 ReturnedDataLen; -- __u16 ByteCount; -+ __le16 ByteCount; - } __attribute__((packed)) TRANSACT_IOCTL_RSP; - - #define CIFS_ACL_OWNER 1 -@@ -1509,7 +1509,7 @@ struct reparse_posix_data { - __le16 ReparseDataLength; - __u16 Reserved; - __le64 InodeType; /* LNK, FIFO, CHR etc. */ -- char PathBuffer[]; -+ __u8 DataBuffer[]; - } __attribute__((packed)); - - struct cifs_quota_data { -diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h -index d87e2c26cce..46feaa0880b 100644 ---- a/fs/smb/client/cifsproto.h -+++ b/fs/smb/client/cifsproto.h -@@ -210,7 +210,7 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path, - const struct cifs_fid *fid); - bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, - struct cifs_fattr *fattr, -- u32 tag); -+ struct cifs_open_info_data *data); - extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path, - struct super_block *sb, unsigned int xid); - extern int cifs_get_inode_info_unix(struct inode **pinode, -@@ -458,6 +458,12 @@ extern int CIFSSMBUnixQuerySymLink(const unsigned int xid, - struct cifs_tcon *tcon, - const unsigned char *searchName, char **syminfo, - const struct nls_table *nls_codepage, int remap); -+extern int cifs_query_reparse_point(const unsigned int xid, -+ struct cifs_tcon *tcon, -+ struct cifs_sb_info *cifs_sb, -+ const char *full_path, -+ u32 *tag, struct kvec *rsp, -+ int *rsp_buftype); - extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, - __u16 fid, char **symlinkinfo, - const struct nls_table *nls_codepage); -@@ -659,6 +665,12 @@ void cifs_put_tcp_super(struct super_block *sb); - int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix); - char *extract_hostname(const char *unc); - char *extract_sharename(const char *unc); -+int parse_reparse_point(struct reparse_data_buffer *buf, -+ u32 plen, struct cifs_sb_info *cifs_sb, -+ bool unicode, struct cifs_open_info_data *data); -+int cifs_sfu_make_node(unsigned int xid, struct inode *inode, -+ struct dentry *dentry, struct cifs_tcon *tcon, -+ const char *full_path, umode_t mode, dev_t dev); - - #ifdef CONFIG_CIFS_DFS_UPCALL - static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses, -diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c -index 25503f1a4fd..bad91ba6c3a 100644 ---- a/fs/smb/client/cifssmb.c -+++ b/fs/smb/client/cifssmb.c -@@ -2690,136 +2690,97 @@ CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, - return rc; - } - --/* -- * Recent Windows versions now create symlinks more frequently -- * and they use the "reparse point" mechanism below. We can of course -- * do symlinks nicely to Samba and other servers which support the -- * CIFS Unix Extensions and we can also do SFU symlinks and "client only" -- * "MF" symlinks optionally, but for recent Windows we really need to -- * reenable the code below and fix the cifs_symlink callers to handle this. -- * In the interim this code has been moved to its own config option so -- * it is not compiled in by default until callers fixed up and more tested. -- */ --int --CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, -- __u16 fid, char **symlinkinfo, -- const struct nls_table *nls_codepage) -+int cifs_query_reparse_point(const unsigned int xid, -+ struct cifs_tcon *tcon, -+ struct cifs_sb_info *cifs_sb, -+ const char *full_path, -+ u32 *tag, struct kvec *rsp, -+ int *rsp_buftype) - { -- int rc = 0; -- int bytes_returned; -- struct smb_com_transaction_ioctl_req *pSMB; -- struct smb_com_transaction_ioctl_rsp *pSMBr; -- bool is_unicode; -- unsigned int sub_len; -- char *sub_start; -- struct reparse_symlink_data *reparse_buf; -- struct reparse_posix_data *posix_buf; -+ struct cifs_open_parms oparms; -+ TRANSACT_IOCTL_REQ *io_req = NULL; -+ TRANSACT_IOCTL_RSP *io_rsp = NULL; -+ struct cifs_fid fid; - __u32 data_offset, data_count; -- char *end_of_smb; -+ __u8 *start, *end; -+ int io_rsp_len; -+ int oplock = 0; -+ int rc; - -- cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid); -- rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, -- (void **) &pSMBr); -+ cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path); -+ -+ if (cap_unix(tcon->ses)) -+ return -EOPNOTSUPP; -+ -+ oparms = (struct cifs_open_parms) { -+ .tcon = tcon, -+ .cifs_sb = cifs_sb, -+ .desired_access = FILE_READ_ATTRIBUTES, -+ .create_options = cifs_create_options(cifs_sb, -+ OPEN_REPARSE_POINT), -+ .disposition = FILE_OPEN, -+ .path = full_path, -+ .fid = &fid, -+ }; -+ -+ rc = CIFS_open(xid, &oparms, &oplock, NULL); - if (rc) - return rc; - -- pSMB->TotalParameterCount = 0 ; -- pSMB->TotalDataCount = 0; -- pSMB->MaxParameterCount = cpu_to_le32(2); -- /* BB find exact data count max from sess structure BB */ -- pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00); -- pSMB->MaxSetupCount = 4; -- pSMB->Reserved = 0; -- pSMB->ParameterOffset = 0; -- pSMB->DataCount = 0; -- pSMB->DataOffset = 0; -- pSMB->SetupCount = 4; -- pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); -- pSMB->ParameterCount = pSMB->TotalParameterCount; -- pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT); -- pSMB->IsFsctl = 1; /* FSCTL */ -- pSMB->IsRootFlag = 0; -- pSMB->Fid = fid; /* file handle always le */ -- pSMB->ByteCount = 0; -+ rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, -+ (void **)&io_req, (void **)&io_rsp); -+ if (rc) -+ goto error; - -- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, -- (struct smb_hdr *) pSMBr, &bytes_returned, 0); -- if (rc) { -- cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc); -- goto qreparse_out; -- } -+ io_req->TotalParameterCount = 0; -+ io_req->TotalDataCount = 0; -+ io_req->MaxParameterCount = cpu_to_le32(2); -+ /* BB find exact data count max from sess structure BB */ -+ io_req->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00); -+ io_req->MaxSetupCount = 4; -+ io_req->Reserved = 0; -+ io_req->ParameterOffset = 0; -+ io_req->DataCount = 0; -+ io_req->DataOffset = 0; -+ io_req->SetupCount = 4; -+ io_req->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); -+ io_req->ParameterCount = io_req->TotalParameterCount; -+ io_req->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT); -+ io_req->IsFsctl = 1; -+ io_req->IsRootFlag = 0; -+ io_req->Fid = fid.netfid; -+ io_req->ByteCount = 0; -+ -+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)io_req, -+ (struct smb_hdr *)io_rsp, &io_rsp_len, 0); -+ if (rc) -+ goto error; - -- data_offset = le32_to_cpu(pSMBr->DataOffset); -- data_count = le32_to_cpu(pSMBr->DataCount); -- if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { -- /* BB also check enough total bytes returned */ -- rc = -EIO; /* bad smb */ -- goto qreparse_out; -- } -- if (!data_count || (data_count > 2048)) { -+ data_offset = le32_to_cpu(io_rsp->DataOffset); -+ data_count = le32_to_cpu(io_rsp->DataCount); -+ if (get_bcc(&io_rsp->hdr) < 2 || data_offset > 512 || -+ !data_count || data_count > 2048) { - rc = -EIO; -- cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); -- goto qreparse_out; -- } -- end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; -- reparse_buf = (struct reparse_symlink_data *) -- ((char *)&pSMBr->hdr.Protocol + data_offset); -- if ((char *)reparse_buf >= end_of_smb) { -- rc = -EIO; -- goto qreparse_out; -- } -- if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) { -- cifs_dbg(FYI, "NFS style reparse tag\n"); -- posix_buf = (struct reparse_posix_data *)reparse_buf; -- -- if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) { -- cifs_dbg(FYI, "unsupported file type 0x%llx\n", -- le64_to_cpu(posix_buf->InodeType)); -- rc = -EOPNOTSUPP; -- goto qreparse_out; -- } -- is_unicode = true; -- sub_len = le16_to_cpu(reparse_buf->ReparseDataLength); -- if (posix_buf->PathBuffer + sub_len > end_of_smb) { -- cifs_dbg(FYI, "reparse buf beyond SMB\n"); -- rc = -EIO; -- goto qreparse_out; -- } -- *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer, -- sub_len, is_unicode, nls_codepage); -- goto qreparse_out; -- } else if (reparse_buf->ReparseTag != -- cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) { -- rc = -EOPNOTSUPP; -- goto qreparse_out; -+ goto error; - } - -- /* Reparse tag is NTFS symlink */ -- sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) + -- reparse_buf->PathBuffer; -- sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength); -- if (sub_start + sub_len > end_of_smb) { -- cifs_dbg(FYI, "reparse buf beyond SMB\n"); -+ end = 2 + get_bcc(&io_rsp->hdr) + (__u8 *)&io_rsp->ByteCount; -+ start = (__u8 *)&io_rsp->hdr.Protocol + data_offset; -+ if (start >= end) { - rc = -EIO; -- goto qreparse_out; -+ goto error; - } -- if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) -- is_unicode = true; -- else -- is_unicode = false; -- -- /* BB FIXME investigate remapping reserved chars here */ -- *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode, -- nls_codepage); -- if (!*symlinkinfo) -- rc = -ENOMEM; --qreparse_out: -- cifs_buf_release(pSMB); - -- /* -- * Note: On -EAGAIN error only caller can retry on handle based calls -- * since file handle passed in no longer valid. -- */ -+ *tag = le32_to_cpu(((struct reparse_data_buffer *)start)->ReparseTag); -+ rsp->iov_base = io_rsp; -+ rsp->iov_len = io_rsp_len; -+ *rsp_buftype = CIFS_LARGE_BUFFER; -+ CIFSSMBClose(xid, tcon, fid.netfid); -+ return 0; -+ -+error: -+ cifs_buf_release(io_req); -+ CIFSSMBClose(xid, tcon, fid.netfid); - return rc; - } - -diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c -index 86fbd3f847d..47f49be69ce 100644 ---- a/fs/smb/client/inode.c -+++ b/fs/smb/client/inode.c -@@ -459,8 +459,7 @@ static int cifs_get_unix_fattr(const unsigned char *full_path, - return -EOPNOTSUPP; - rc = server->ops->query_symlink(xid, tcon, - cifs_sb, full_path, -- &fattr->cf_symlink_target, -- NULL); -+ &fattr->cf_symlink_target); - cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc); - } - return rc; -@@ -722,10 +721,51 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, - fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); - } - -+static inline dev_t nfs_mkdev(struct reparse_posix_data *buf) -+{ -+ u64 v = le64_to_cpu(*(__le64 *)buf->DataBuffer); -+ -+ return MKDEV(v >> 32, v & 0xffffffff); -+} -+ - bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, - struct cifs_fattr *fattr, -- u32 tag) -+ struct cifs_open_info_data *data) - { -+ struct reparse_posix_data *buf = data->reparse.posix; -+ u32 tag = data->reparse.tag; -+ -+ if (tag == IO_REPARSE_TAG_NFS && buf) { -+ switch (le64_to_cpu(buf->InodeType)) { -+ case NFS_SPECFILE_CHR: -+ fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode; -+ fattr->cf_dtype = DT_CHR; -+ fattr->cf_rdev = nfs_mkdev(buf); -+ break; -+ case NFS_SPECFILE_BLK: -+ fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode; -+ fattr->cf_dtype = DT_BLK; -+ fattr->cf_rdev = nfs_mkdev(buf); -+ break; -+ case NFS_SPECFILE_FIFO: -+ fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode; -+ fattr->cf_dtype = DT_FIFO; -+ break; -+ case NFS_SPECFILE_SOCK: -+ fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode; -+ fattr->cf_dtype = DT_SOCK; -+ break; -+ case NFS_SPECFILE_LNK: -+ fattr->cf_mode = S_IFLNK | cifs_sb->ctx->file_mode; -+ fattr->cf_dtype = DT_LNK; -+ break; -+ default: -+ WARN_ON_ONCE(1); -+ return false; -+ } -+ return true; -+ } -+ - switch (tag) { - case IO_REPARSE_TAG_LX_SYMLINK: - fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode; -@@ -791,7 +831,7 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, - fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); - - if (cifs_open_data_reparse(data) && -- cifs_reparse_point_to_fattr(cifs_sb, fattr, data->reparse_tag)) -+ cifs_reparse_point_to_fattr(cifs_sb, fattr, data)) - goto out_reparse; - - if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { -@@ -856,7 +896,7 @@ cifs_get_file_info(struct file *filp) - data.adjust_tz = false; - if (data.symlink_target) { - data.symlink = true; -- data.reparse_tag = IO_REPARSE_TAG_SYMLINK; -+ data.reparse.tag = IO_REPARSE_TAG_SYMLINK; - } - cifs_open_info_to_fattr(&fattr, &data, inode->i_sb); - break; -@@ -1025,7 +1065,7 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data, - struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - struct kvec rsp_iov, *iov = NULL; - int rsp_buftype = CIFS_NO_BUFFER; -- u32 tag = data->reparse_tag; -+ u32 tag = data->reparse.tag; - int rc = 0; - - if (!tag && server->ops->query_reparse_point) { -@@ -1035,22 +1075,28 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data, - if (!rc) - iov = &rsp_iov; - } -- switch ((data->reparse_tag = tag)) { -+ -+ rc = -EOPNOTSUPP; -+ switch ((data->reparse.tag = tag)) { - case 0: /* SMB1 symlink */ -- iov = NULL; -- fallthrough; -- case IO_REPARSE_TAG_NFS: -- case IO_REPARSE_TAG_SYMLINK: -- if (!data->symlink_target && server->ops->query_symlink) { -+ if (server->ops->query_symlink) { - rc = server->ops->query_symlink(xid, tcon, - cifs_sb, full_path, -- &data->symlink_target, -- iov); -+ &data->symlink_target); - } - break; - case IO_REPARSE_TAG_MOUNT_POINT: - cifs_create_junction_fattr(fattr, sb); -+ rc = 0; - goto out; -+ default: -+ if (data->symlink_target) { -+ rc = 0; -+ } else if (server->ops->parse_reparse_point) { -+ rc = server->ops->parse_reparse_point(cifs_sb, -+ iov, data); -+ } -+ break; - } - - cifs_open_info_to_fattr(fattr, data, sb); -diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c -index 47fc22de8d2..d30ea2005eb 100644 ---- a/fs/smb/client/readdir.c -+++ b/fs/smb/client/readdir.c -@@ -153,6 +153,10 @@ static bool reparse_file_needs_reval(const struct cifs_fattr *fattr) - static void - cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) - { -+ struct cifs_open_info_data data = { -+ .reparse = { .tag = fattr->cf_cifstag, }, -+ }; -+ - fattr->cf_uid = cifs_sb->ctx->linux_uid; - fattr->cf_gid = cifs_sb->ctx->linux_gid; - -@@ -165,7 +169,7 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) - * reasonably map some of them to directories vs. files vs. symlinks - */ - if ((fattr->cf_cifsattrs & ATTR_REPARSE) && -- cifs_reparse_point_to_fattr(cifs_sb, fattr, fattr->cf_cifstag)) -+ cifs_reparse_point_to_fattr(cifs_sb, fattr, &data)) - goto out_reparse; - - if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { -diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c -index 8b2d7c1ca42..816e01c5589 100644 ---- a/fs/smb/client/sess.c -+++ b/fs/smb/client/sess.c -@@ -332,10 +332,10 @@ cifs_disable_secondary_channels(struct cifs_ses *ses) - - if (iface) { - spin_lock(&ses->iface_lock); -- kref_put(&iface->refcount, release_iface); - iface->num_channels--; - if (iface->weight_fulfilled) - iface->weight_fulfilled--; -+ kref_put(&iface->refcount, release_iface); - spin_unlock(&ses->iface_lock); - } - -diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c -index 9bf8735cdd1..a9eaba8083b 100644 ---- a/fs/smb/client/smb1ops.c -+++ b/fs/smb/client/smb1ops.c -@@ -976,64 +976,37 @@ static int cifs_query_symlink(const unsigned int xid, - struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, - const char *full_path, -- char **target_path, -- struct kvec *rsp_iov) -+ char **target_path) - { - int rc; -- int oplock = 0; -- bool is_reparse_point = !!rsp_iov; -- struct cifs_fid fid; -- struct cifs_open_parms oparms; - -- cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); -+ cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path); - -- if (is_reparse_point) { -- cifs_dbg(VFS, "reparse points not handled for SMB1 symlinks\n"); -+ if (!cap_unix(tcon->ses)) - return -EOPNOTSUPP; -- } -- -- /* Check for unix extensions */ -- if (cap_unix(tcon->ses)) { -- rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path, -- cifs_sb->local_nls, -- cifs_remap(cifs_sb)); -- if (rc == -EREMOTE) -- rc = cifs_unix_dfs_readlink(xid, tcon, full_path, -- target_path, -- cifs_sb->local_nls); -- -- goto out; -- } -- -- oparms = (struct cifs_open_parms) { -- .tcon = tcon, -- .cifs_sb = cifs_sb, -- .desired_access = FILE_READ_ATTRIBUTES, -- .create_options = cifs_create_options(cifs_sb, -- OPEN_REPARSE_POINT), -- .disposition = FILE_OPEN, -- .path = full_path, -- .fid = &fid, -- }; -- -- rc = CIFS_open(xid, &oparms, &oplock, NULL); -- if (rc) -- goto out; -- -- rc = CIFSSMBQuerySymLink(xid, tcon, fid.netfid, target_path, -- cifs_sb->local_nls); -- if (rc) -- goto out_close; - -- convert_delimiter(*target_path, '/'); --out_close: -- CIFSSMBClose(xid, tcon, fid.netfid); --out: -- if (!rc) -- cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); -+ rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path, -+ cifs_sb->local_nls, cifs_remap(cifs_sb)); -+ if (rc == -EREMOTE) -+ rc = cifs_unix_dfs_readlink(xid, tcon, full_path, -+ target_path, cifs_sb->local_nls); - return rc; - } - -+static int cifs_parse_reparse_point(struct cifs_sb_info *cifs_sb, -+ struct kvec *rsp_iov, -+ struct cifs_open_info_data *data) -+{ -+ struct reparse_data_buffer *buf; -+ TRANSACT_IOCTL_RSP *io = rsp_iov->iov_base; -+ bool unicode = !!(io->hdr.Flags2 & SMBFLG2_UNICODE); -+ u32 plen = le16_to_cpu(io->ByteCount); -+ -+ buf = (struct reparse_data_buffer *)((__u8 *)&io->hdr.Protocol + -+ le32_to_cpu(io->DataOffset)); -+ return parse_reparse_point(buf, plen, cifs_sb, unicode, data); -+} -+ - static bool - cifs_is_read_op(__u32 oplock) - { -@@ -1068,15 +1041,7 @@ cifs_make_node(unsigned int xid, struct inode *inode, - { - struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct inode *newinode = NULL; -- int rc = -EPERM; -- struct cifs_open_info_data buf = {}; -- struct cifs_io_parms io_parms; -- __u32 oplock = 0; -- struct cifs_fid fid; -- struct cifs_open_parms oparms; -- unsigned int bytes_written; -- struct win_dev *pdev; -- struct kvec iov[2]; -+ int rc; - - if (tcon->unix_ext) { - /* -@@ -1110,74 +1075,18 @@ cifs_make_node(unsigned int xid, struct inode *inode, - d_instantiate(dentry, newinode); - return rc; - } -- - /* -- * SMB1 SFU emulation: should work with all servers, but only -- * support block and char device (no socket & fifo) -+ * Check if mounted with mount parm 'sfu' mount parm. -+ * SFU emulation should work with all servers, but only -+ * supports block and char device (no socket & fifo), -+ * and was used by default in earlier versions of Windows - */ - if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) -- return rc; -- -- if (!S_ISCHR(mode) && !S_ISBLK(mode)) -- return rc; -- -- cifs_dbg(FYI, "sfu compat create special file\n"); -- -- oparms = (struct cifs_open_parms) { -- .tcon = tcon, -- .cifs_sb = cifs_sb, -- .desired_access = GENERIC_WRITE, -- .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR | -- CREATE_OPTION_SPECIAL), -- .disposition = FILE_CREATE, -- .path = full_path, -- .fid = &fid, -- }; -- -- if (tcon->ses->server->oplocks) -- oplock = REQ_OPLOCK; -- else -- oplock = 0; -- rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &buf); -- if (rc) -- return rc; -- -- /* -- * BB Do not bother to decode buf since no local inode yet to put -- * timestamps in, but we can reuse it safely. -- */ -- -- pdev = (struct win_dev *)&buf.fi; -- io_parms.pid = current->tgid; -- io_parms.tcon = tcon; -- io_parms.offset = 0; -- io_parms.length = sizeof(struct win_dev); -- iov[1].iov_base = &buf.fi; -- iov[1].iov_len = sizeof(struct win_dev); -- if (S_ISCHR(mode)) { -- memcpy(pdev->type, "IntxCHR", 8); -- pdev->major = cpu_to_le64(MAJOR(dev)); -- pdev->minor = cpu_to_le64(MINOR(dev)); -- rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, -- &bytes_written, iov, 1); -- } else if (S_ISBLK(mode)) { -- memcpy(pdev->type, "IntxBLK", 8); -- pdev->major = cpu_to_le64(MAJOR(dev)); -- pdev->minor = cpu_to_le64(MINOR(dev)); -- rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, -- &bytes_written, iov, 1); -- } -- tcon->ses->server->ops->close(xid, tcon, &fid); -- d_drop(dentry); -- -- /* FIXME: add code here to set EAs */ -- -- cifs_free_open_info(&buf); -- return rc; -+ return -EPERM; -+ return cifs_sfu_make_node(xid, inode, dentry, tcon, -+ full_path, mode, dev); - } - -- -- - struct smb_version_operations smb1_operations = { - .send_cancel = send_nt_cancel, - .compare_fids = cifs_compare_fids, -@@ -1214,6 +1123,7 @@ struct smb_version_operations smb1_operations = { - .is_path_accessible = cifs_is_path_accessible, - .can_echo = cifs_can_echo, - .query_path_info = cifs_query_path_info, -+ .query_reparse_point = cifs_query_reparse_point, - .query_file_info = cifs_query_file_info, - .get_srv_inum = cifs_get_srv_inum, - .set_path_size = CIFSSMBSetEOF, -@@ -1229,6 +1139,7 @@ struct smb_version_operations smb1_operations = { - .rename = CIFSSMBRename, - .create_hardlink = CIFSCreateHardLink, - .query_symlink = cifs_query_symlink, -+ .parse_reparse_point = cifs_parse_reparse_point, - .open = cifs_open_file, - .set_fid = cifs_set_fid, - .close = cifs_close_file, -diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c -index 0b89f7008ac..c94940af5d4 100644 ---- a/fs/smb/client/smb2inode.c -+++ b/fs/smb/client/smb2inode.c -@@ -555,7 +555,7 @@ static int parse_create_response(struct cifs_open_info_data *data, - break; - } - data->reparse_point = reparse_point; -- data->reparse_tag = tag; -+ data->reparse.tag = tag; - return rc; - } - -diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c -index a959ed2c9b2..82ab62fd004 100644 ---- a/fs/smb/client/smb2ops.c -+++ b/fs/smb/client/smb2ops.c -@@ -2866,115 +2866,119 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses, - return rc; - } - --static int --parse_reparse_posix(struct reparse_posix_data *symlink_buf, -- u32 plen, char **target_path, -- struct cifs_sb_info *cifs_sb) -+/* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */ -+static int parse_reparse_posix(struct reparse_posix_data *buf, -+ struct cifs_sb_info *cifs_sb, -+ struct cifs_open_info_data *data) - { - unsigned int len; -- -- /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */ -- len = le16_to_cpu(symlink_buf->ReparseDataLength); -- -- if (le64_to_cpu(symlink_buf->InodeType) != NFS_SPECFILE_LNK) { -- cifs_dbg(VFS, "%lld not a supported symlink type\n", -- le64_to_cpu(symlink_buf->InodeType)); -+ u64 type; -+ -+ switch ((type = le64_to_cpu(buf->InodeType))) { -+ case NFS_SPECFILE_LNK: -+ len = le16_to_cpu(buf->ReparseDataLength); -+ data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer, -+ len, true, -+ cifs_sb->local_nls); -+ if (!data->symlink_target) -+ return -ENOMEM; -+ convert_delimiter(data->symlink_target, '/'); -+ cifs_dbg(FYI, "%s: target path: %s\n", -+ __func__, data->symlink_target); -+ break; -+ case NFS_SPECFILE_CHR: -+ case NFS_SPECFILE_BLK: -+ case NFS_SPECFILE_FIFO: -+ case NFS_SPECFILE_SOCK: -+ break; -+ default: -+ cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n", -+ __func__, type); - return -EOPNOTSUPP; - } -- -- *target_path = cifs_strndup_from_utf16( -- symlink_buf->PathBuffer, -- len, true, cifs_sb->local_nls); -- if (!(*target_path)) -- return -ENOMEM; -- -- convert_delimiter(*target_path, '/'); -- cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); -- - return 0; - } - --static int --parse_reparse_symlink(struct reparse_symlink_data_buffer *symlink_buf, -- u32 plen, char **target_path, -- struct cifs_sb_info *cifs_sb) -+static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym, -+ u32 plen, bool unicode, -+ struct cifs_sb_info *cifs_sb, -+ struct cifs_open_info_data *data) - { -- unsigned int sub_len; -- unsigned int sub_offset; -+ unsigned int len; -+ unsigned int offs; - - /* We handle Symbolic Link reparse tag here. See: MS-FSCC 2.1.2.4 */ - -- sub_offset = le16_to_cpu(symlink_buf->SubstituteNameOffset); -- sub_len = le16_to_cpu(symlink_buf->SubstituteNameLength); -- if (sub_offset + 20 > plen || -- sub_offset + sub_len + 20 > plen) { -+ offs = le16_to_cpu(sym->SubstituteNameOffset); -+ len = le16_to_cpu(sym->SubstituteNameLength); -+ if (offs + 20 > plen || offs + len + 20 > plen) { - cifs_dbg(VFS, "srv returned malformed symlink buffer\n"); - return -EIO; - } - -- *target_path = cifs_strndup_from_utf16( -- symlink_buf->PathBuffer + sub_offset, -- sub_len, true, cifs_sb->local_nls); -- if (!(*target_path)) -+ data->symlink_target = cifs_strndup_from_utf16(sym->PathBuffer + offs, -+ len, unicode, -+ cifs_sb->local_nls); -+ if (!data->symlink_target) - return -ENOMEM; - -- convert_delimiter(*target_path, '/'); -- cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); -+ convert_delimiter(data->symlink_target, '/'); -+ cifs_dbg(FYI, "%s: target path: %s\n", __func__, data->symlink_target); - - return 0; - } - --static int --parse_reparse_point(struct reparse_data_buffer *buf, -- u32 plen, char **target_path, -- struct cifs_sb_info *cifs_sb) -+int parse_reparse_point(struct reparse_data_buffer *buf, -+ u32 plen, struct cifs_sb_info *cifs_sb, -+ bool unicode, struct cifs_open_info_data *data) - { -- if (plen < sizeof(struct reparse_data_buffer)) { -- cifs_dbg(VFS, "reparse buffer is too small. Must be at least 8 bytes but was %d\n", -- plen); -+ if (plen < sizeof(*buf)) { -+ cifs_dbg(VFS, "%s: reparse buffer is too small. Must be at least 8 bytes but was %d\n", -+ __func__, plen); - return -EIO; - } - -- if (plen < le16_to_cpu(buf->ReparseDataLength) + -- sizeof(struct reparse_data_buffer)) { -- cifs_dbg(VFS, "srv returned invalid reparse buf length: %d\n", -- plen); -+ if (plen < le16_to_cpu(buf->ReparseDataLength) + sizeof(*buf)) { -+ cifs_dbg(VFS, "%s: invalid reparse buf length: %d\n", -+ __func__, plen); - return -EIO; - } - -+ data->reparse.buf = buf; -+ - /* See MS-FSCC 2.1.2 */ - switch (le32_to_cpu(buf->ReparseTag)) { - case IO_REPARSE_TAG_NFS: -- return parse_reparse_posix( -- (struct reparse_posix_data *)buf, -- plen, target_path, cifs_sb); -+ return parse_reparse_posix((struct reparse_posix_data *)buf, -+ cifs_sb, data); - case IO_REPARSE_TAG_SYMLINK: - return parse_reparse_symlink( - (struct reparse_symlink_data_buffer *)buf, -- plen, target_path, cifs_sb); -+ plen, unicode, cifs_sb, data); -+ case IO_REPARSE_TAG_LX_SYMLINK: -+ case IO_REPARSE_TAG_AF_UNIX: -+ case IO_REPARSE_TAG_LX_FIFO: -+ case IO_REPARSE_TAG_LX_CHR: -+ case IO_REPARSE_TAG_LX_BLK: -+ return 0; - default: -- cifs_dbg(VFS, "srv returned unknown symlink buffer tag:0x%08x\n", -- le32_to_cpu(buf->ReparseTag)); -+ cifs_dbg(VFS, "%s: unhandled reparse tag: 0x%08x\n", -+ __func__, le32_to_cpu(buf->ReparseTag)); - return -EOPNOTSUPP; - } - } - --static int smb2_query_symlink(const unsigned int xid, -- struct cifs_tcon *tcon, -- struct cifs_sb_info *cifs_sb, -- const char *full_path, -- char **target_path, -- struct kvec *rsp_iov) -+static int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb, -+ struct kvec *rsp_iov, -+ struct cifs_open_info_data *data) - { - struct reparse_data_buffer *buf; - struct smb2_ioctl_rsp *io = rsp_iov->iov_base; - u32 plen = le32_to_cpu(io->OutputCount); - -- cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); -- - buf = (struct reparse_data_buffer *)((u8 *)io + - le32_to_cpu(io->OutputOffset)); -- return parse_reparse_point(buf, plen, target_path, cifs_sb); -+ return parse_reparse_point(buf, plen, cifs_sb, true, data); - } - - static int smb2_query_reparse_point(const unsigned int xid, -@@ -5064,41 +5068,24 @@ smb2_next_header(char *buf) - return le32_to_cpu(hdr->NextCommand); - } - --static int --smb2_make_node(unsigned int xid, struct inode *inode, -- struct dentry *dentry, struct cifs_tcon *tcon, -- const char *full_path, umode_t mode, dev_t dev) -+int cifs_sfu_make_node(unsigned int xid, struct inode *inode, -+ struct dentry *dentry, struct cifs_tcon *tcon, -+ const char *full_path, umode_t mode, dev_t dev) - { -- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); -- int rc = -EPERM; - struct cifs_open_info_data buf = {}; -- struct cifs_io_parms io_parms = {0}; -- __u32 oplock = 0; -- struct cifs_fid fid; -+ struct TCP_Server_Info *server = tcon->ses->server; - struct cifs_open_parms oparms; -+ struct cifs_io_parms io_parms = {}; -+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); -+ struct cifs_fid fid; - unsigned int bytes_written; - struct win_dev *pdev; - struct kvec iov[2]; -- -- /* -- * Check if mounted with mount parm 'sfu' mount parm. -- * SFU emulation should work with all servers, but only -- * supports block and char device (no socket & fifo), -- * and was used by default in earlier versions of Windows -- */ -- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) -- return rc; -- -- /* -- * TODO: Add ability to create instead via reparse point. Windows (e.g. -- * their current NFS server) uses this approach to expose special files -- * over SMB2/SMB3 and Samba will do this with SMB3.1.1 POSIX Extensions -- */ -+ __u32 oplock = server->oplocks ? REQ_OPLOCK : 0; -+ int rc; - - if (!S_ISCHR(mode) && !S_ISBLK(mode) && !S_ISFIFO(mode)) -- return rc; -- -- cifs_dbg(FYI, "sfu compat create special file\n"); -+ return -EPERM; - - oparms = (struct cifs_open_parms) { - .tcon = tcon, -@@ -5111,11 +5098,7 @@ smb2_make_node(unsigned int xid, struct inode *inode, - .fid = &fid, - }; - -- if (tcon->ses->server->oplocks) -- oplock = REQ_OPLOCK; -- else -- oplock = 0; -- rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &buf); -+ rc = server->ops->open(xid, &oparms, &oplock, &buf); - if (rc) - return rc; - -@@ -5123,42 +5106,56 @@ smb2_make_node(unsigned int xid, struct inode *inode, - * BB Do not bother to decode buf since no local inode yet to put - * timestamps in, but we can reuse it safely. - */ -- - pdev = (struct win_dev *)&buf.fi; - io_parms.pid = current->tgid; - io_parms.tcon = tcon; -- io_parms.offset = 0; -- io_parms.length = sizeof(struct win_dev); -- iov[1].iov_base = &buf.fi; -- iov[1].iov_len = sizeof(struct win_dev); -+ io_parms.length = sizeof(*pdev); -+ iov[1].iov_base = pdev; -+ iov[1].iov_len = sizeof(*pdev); - if (S_ISCHR(mode)) { - memcpy(pdev->type, "IntxCHR", 8); - pdev->major = cpu_to_le64(MAJOR(dev)); - pdev->minor = cpu_to_le64(MINOR(dev)); -- rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, -- &bytes_written, iov, 1); - } else if (S_ISBLK(mode)) { - memcpy(pdev->type, "IntxBLK", 8); - pdev->major = cpu_to_le64(MAJOR(dev)); - pdev->minor = cpu_to_le64(MINOR(dev)); -- rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, -- &bytes_written, iov, 1); - } else if (S_ISFIFO(mode)) { - memcpy(pdev->type, "LnxFIFO", 8); -- pdev->major = 0; -- pdev->minor = 0; -- rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, -- &bytes_written, iov, 1); - } -- tcon->ses->server->ops->close(xid, tcon, &fid); -- d_drop(dentry); - -+ rc = server->ops->sync_write(xid, &fid, &io_parms, -+ &bytes_written, iov, 1); -+ server->ops->close(xid, tcon, &fid); -+ d_drop(dentry); - /* FIXME: add code here to set EAs */ -- - cifs_free_open_info(&buf); - return rc; - } - -+static int smb2_make_node(unsigned int xid, struct inode *inode, -+ struct dentry *dentry, struct cifs_tcon *tcon, -+ const char *full_path, umode_t mode, dev_t dev) -+{ -+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); -+ -+ /* -+ * Check if mounted with mount parm 'sfu' mount parm. -+ * SFU emulation should work with all servers, but only -+ * supports block and char device (no socket & fifo), -+ * and was used by default in earlier versions of Windows -+ */ -+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) -+ return -EPERM; -+ /* -+ * TODO: Add ability to create instead via reparse point. Windows (e.g. -+ * their current NFS server) uses this approach to expose special files -+ * over SMB2/SMB3 and Samba will do this with SMB3.1.1 POSIX Extensions -+ */ -+ return cifs_sfu_make_node(xid, inode, dentry, tcon, -+ full_path, mode, dev); -+} -+ - #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY - struct smb_version_operations smb20_operations = { - .compare_fids = smb2_compare_fids, -@@ -5209,7 +5206,7 @@ struct smb_version_operations smb20_operations = { - .unlink = smb2_unlink, - .rename = smb2_rename_path, - .create_hardlink = smb2_create_hardlink, -- .query_symlink = smb2_query_symlink, -+ .parse_reparse_point = smb2_parse_reparse_point, - .query_mf_symlink = smb3_query_mf_symlink, - .create_mf_symlink = smb3_create_mf_symlink, - .open = smb2_open_file, -@@ -5311,7 +5308,7 @@ struct smb_version_operations smb21_operations = { - .unlink = smb2_unlink, - .rename = smb2_rename_path, - .create_hardlink = smb2_create_hardlink, -- .query_symlink = smb2_query_symlink, -+ .parse_reparse_point = smb2_parse_reparse_point, - .query_mf_symlink = smb3_query_mf_symlink, - .create_mf_symlink = smb3_create_mf_symlink, - .open = smb2_open_file, -@@ -5416,7 +5413,7 @@ struct smb_version_operations smb30_operations = { - .unlink = smb2_unlink, - .rename = smb2_rename_path, - .create_hardlink = smb2_create_hardlink, -- .query_symlink = smb2_query_symlink, -+ .parse_reparse_point = smb2_parse_reparse_point, - .query_mf_symlink = smb3_query_mf_symlink, - .create_mf_symlink = smb3_create_mf_symlink, - .open = smb2_open_file, -@@ -5530,7 +5527,7 @@ struct smb_version_operations smb311_operations = { - .unlink = smb2_unlink, - .rename = smb2_rename_path, - .create_hardlink = smb2_create_hardlink, -- .query_symlink = smb2_query_symlink, -+ .parse_reparse_point = smb2_parse_reparse_point, - .query_mf_symlink = smb3_query_mf_symlink, - .create_mf_symlink = smb3_create_mf_symlink, - .open = smb2_open_file, -diff --git a/fs/stat.c b/fs/stat.c -index 24bb0209e45..f721d26ec3f 100644 ---- a/fs/stat.c -+++ b/fs/stat.c -@@ -133,7 +133,8 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat, - idmap = mnt_idmap(path->mnt); - if (inode->i_op->getattr) - return inode->i_op->getattr(idmap, path, stat, -- request_mask, query_flags); -+ request_mask, -+ query_flags | AT_GETATTR_NOSEC); - - generic_fillattr(idmap, request_mask, inode, stat); - return 0; -@@ -166,6 +167,9 @@ int vfs_getattr(const struct path *path, struct kstat *stat, - { - int retval; - -+ if (WARN_ON_ONCE(query_flags & AT_GETATTR_NOSEC)) -+ return -EPERM; -+ - retval = security_inode_getattr(path); - if (retval) - return retval; -diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c -index f8a594a50ae..0b90869fd80 100644 ---- a/fs/tracefs/event_inode.c -+++ b/fs/tracefs/event_inode.c -@@ -27,16 +27,16 @@ - /* - * eventfs_mutex protects the eventfs_inode (ei) dentry. Any access - * to the ei->dentry must be done under this mutex and after checking -- * if ei->is_freed is not set. The ei->dentry is released under the -- * mutex at the same time ei->is_freed is set. If ei->is_freed is set -- * then the ei->dentry is invalid. -+ * if ei->is_freed is not set. When ei->is_freed is set, the dentry -+ * is on its way to being freed after the last dput() is made on it. - */ - static DEFINE_MUTEX(eventfs_mutex); - - /* - * The eventfs_inode (ei) itself is protected by SRCU. It is released from - * its parent's list and will have is_freed set (under eventfs_mutex). -- * After the SRCU grace period is over, the ei may be freed. -+ * After the SRCU grace period is over and the last dput() is called -+ * the ei is freed. - */ - DEFINE_STATIC_SRCU(eventfs_srcu); - -@@ -95,7 +95,7 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry, - if (!(dentry->d_inode->i_mode & S_IFDIR)) { - if (!ei->entry_attrs) { - ei->entry_attrs = kzalloc(sizeof(*ei->entry_attrs) * ei->nr_entries, -- GFP_KERNEL); -+ GFP_NOFS); - if (!ei->entry_attrs) { - ret = -ENOMEM; - goto out; -@@ -326,7 +326,8 @@ create_file_dentry(struct eventfs_inode *ei, int idx, - struct eventfs_attr *attr = NULL; - struct dentry **e_dentry = &ei->d_children[idx]; - struct dentry *dentry; -- bool invalidate = false; -+ -+ WARN_ON_ONCE(!inode_is_locked(parent->d_inode)); - - mutex_lock(&eventfs_mutex); - if (ei->is_freed) { -@@ -348,15 +349,8 @@ create_file_dentry(struct eventfs_inode *ei, int idx, - - mutex_unlock(&eventfs_mutex); - -- /* The lookup already has the parent->d_inode locked */ -- if (!lookup) -- inode_lock(parent->d_inode); -- - dentry = create_file(name, mode, attr, parent, data, fops); - -- if (!lookup) -- inode_unlock(parent->d_inode); -- - mutex_lock(&eventfs_mutex); - - if (IS_ERR_OR_NULL(dentry)) { -@@ -365,12 +359,14 @@ create_file_dentry(struct eventfs_inode *ei, int idx, - * created the dentry for this e_dentry. In which case - * use that one. - * -- * Note, with the mutex held, the e_dentry cannot have content -- * and the ei->is_freed be true at the same time. -+ * If ei->is_freed is set, the e_dentry is currently on its -+ * way to being freed, don't return it. If e_dentry is NULL -+ * it means it was already freed. - */ -- dentry = *e_dentry; -- if (WARN_ON_ONCE(dentry && ei->is_freed)) -+ if (ei->is_freed) - dentry = NULL; -+ else -+ dentry = *e_dentry; - /* The lookup does not need to up the dentry refcount */ - if (dentry && !lookup) - dget(dentry); -@@ -387,17 +383,14 @@ create_file_dentry(struct eventfs_inode *ei, int idx, - * Otherwise it means two dentries exist with the same name. - */ - WARN_ON_ONCE(!ei->is_freed); -- invalidate = true; -+ dentry = NULL; - } - mutex_unlock(&eventfs_mutex); - -- if (invalidate) -- d_invalidate(dentry); -- -- if (lookup || invalidate) -+ if (lookup) - dput(dentry); - -- return invalidate ? NULL : dentry; -+ return dentry; - } - - /** -@@ -437,9 +430,10 @@ static struct dentry * - create_dir_dentry(struct eventfs_inode *pei, struct eventfs_inode *ei, - struct dentry *parent, bool lookup) - { -- bool invalidate = false; - struct dentry *dentry = NULL; - -+ WARN_ON_ONCE(!inode_is_locked(parent->d_inode)); -+ - mutex_lock(&eventfs_mutex); - if (pei->is_freed || ei->is_freed) { - mutex_unlock(&eventfs_mutex); -@@ -456,15 +450,8 @@ create_dir_dentry(struct eventfs_inode *pei, struct eventfs_inode *ei, - } - mutex_unlock(&eventfs_mutex); - -- /* The lookup already has the parent->d_inode locked */ -- if (!lookup) -- inode_lock(parent->d_inode); -- - dentry = create_dir(ei, parent); - -- if (!lookup) -- inode_unlock(parent->d_inode); -- - mutex_lock(&eventfs_mutex); - - if (IS_ERR_OR_NULL(dentry) && !ei->is_freed) { -@@ -473,8 +460,8 @@ create_dir_dentry(struct eventfs_inode *pei, struct eventfs_inode *ei, - * created the dentry for this e_dentry. In which case - * use that one. - * -- * Note, with the mutex held, the e_dentry cannot have content -- * and the ei->is_freed be true at the same time. -+ * If ei->is_freed is set, the e_dentry is currently on its -+ * way to being freed. - */ - dentry = ei->dentry; - if (dentry && !lookup) -@@ -493,16 +480,14 @@ create_dir_dentry(struct eventfs_inode *pei, struct eventfs_inode *ei, - * Otherwise it means two dentries exist with the same name. - */ - WARN_ON_ONCE(!ei->is_freed); -- invalidate = true; -+ dentry = NULL; - } - mutex_unlock(&eventfs_mutex); -- if (invalidate) -- d_invalidate(dentry); - -- if (lookup || invalidate) -+ if (lookup) - dput(dentry); - -- return invalidate ? NULL : dentry; -+ return dentry; - } - - /** -@@ -632,7 +617,7 @@ static int add_dentries(struct dentry ***dentries, struct dentry *d, int cnt) - { - struct dentry **tmp; - -- tmp = krealloc(*dentries, sizeof(d) * (cnt + 2), GFP_KERNEL); -+ tmp = krealloc(*dentries, sizeof(d) * (cnt + 2), GFP_NOFS); - if (!tmp) - return -1; - tmp[cnt] = d; -@@ -698,6 +683,7 @@ static int dcache_dir_open_wrapper(struct inode *inode, struct file *file) - return -ENOMEM; - } - -+ inode_lock(parent->d_inode); - list_for_each_entry_srcu(ei_child, &ei->children, list, - srcu_read_lock_held(&eventfs_srcu)) { - d = create_dir_dentry(ei, ei_child, parent, false); -@@ -730,6 +716,7 @@ static int dcache_dir_open_wrapper(struct inode *inode, struct file *file) - cnt++; - } - } -+ inode_unlock(parent->d_inode); - srcu_read_unlock(&eventfs_srcu, idx); - ret = dcache_dir_open(inode, file); - -diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c -index 5b54948514f..ae648deed01 100644 ---- a/fs/tracefs/inode.c -+++ b/fs/tracefs/inode.c -@@ -509,20 +509,15 @@ struct dentry *eventfs_start_creating(const char *name, struct dentry *parent) - struct dentry *dentry; - int error; - -+ /* Must always have a parent. */ -+ if (WARN_ON_ONCE(!parent)) -+ return ERR_PTR(-EINVAL); -+ - error = simple_pin_fs(&trace_fs_type, &tracefs_mount, - &tracefs_mount_count); - if (error) - return ERR_PTR(error); - -- /* -- * If the parent is not specified, we create it in the root. -- * We need the root dentry to do this, which is in the super -- * block. A pointer to that is in the struct vfsmount that we -- * have around. -- */ -- if (!parent) -- parent = tracefs_mount->mnt_root; -- - if (unlikely(IS_DEADDIR(parent->d_inode))) - dentry = ERR_PTR(-ENOENT); - else -diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c -index ac6ba646624..a013b87ab8d 100644 ---- a/fs/xfs/xfs_dquot.c -+++ b/fs/xfs/xfs_dquot.c -@@ -562,7 +562,8 @@ xfs_dquot_from_disk( - struct xfs_dquot *dqp, - struct xfs_buf *bp) - { -- struct xfs_disk_dquot *ddqp = bp->b_addr + dqp->q_bufoffset; -+ struct xfs_dqblk *dqb = xfs_buf_offset(bp, dqp->q_bufoffset); -+ struct xfs_disk_dquot *ddqp = &dqb->dd_diskdq; - - /* - * Ensure that we got the type and ID we were looking for. -@@ -1250,7 +1251,7 @@ xfs_qm_dqflush( - } - - /* Flush the incore dquot to the ondisk buffer. */ -- dqblk = bp->b_addr + dqp->q_bufoffset; -+ dqblk = xfs_buf_offset(bp, dqp->q_bufoffset); - xfs_dquot_to_disk(&dqblk->dd_diskdq, dqp); - - /* -diff --git a/fs/xfs/xfs_dquot_item_recover.c b/fs/xfs/xfs_dquot_item_recover.c -index 8966ba84239..2c2720ce692 100644 ---- a/fs/xfs/xfs_dquot_item_recover.c -+++ b/fs/xfs/xfs_dquot_item_recover.c -@@ -19,6 +19,7 @@ - #include "xfs_log.h" - #include "xfs_log_priv.h" - #include "xfs_log_recover.h" -+#include "xfs_error.h" - - STATIC void - xlog_recover_dquot_ra_pass2( -@@ -65,6 +66,7 @@ xlog_recover_dquot_commit_pass2( - { - struct xfs_mount *mp = log->l_mp; - struct xfs_buf *bp; -+ struct xfs_dqblk *dqb; - struct xfs_disk_dquot *ddq, *recddq; - struct xfs_dq_logformat *dq_f; - xfs_failaddr_t fa; -@@ -130,14 +132,14 @@ xlog_recover_dquot_commit_pass2( - return error; - - ASSERT(bp); -- ddq = xfs_buf_offset(bp, dq_f->qlf_boffset); -+ dqb = xfs_buf_offset(bp, dq_f->qlf_boffset); -+ ddq = &dqb->dd_diskdq; - - /* - * If the dquot has an LSN in it, recover the dquot only if it's less - * than the lsn of the transaction we are replaying. - */ - if (xfs_has_crc(mp)) { -- struct xfs_dqblk *dqb = (struct xfs_dqblk *)ddq; - xfs_lsn_t lsn = be64_to_cpu(dqb->dd_lsn); - - if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) { -@@ -147,10 +149,23 @@ xlog_recover_dquot_commit_pass2( - - memcpy(ddq, recddq, item->ri_buf[1].i_len); - if (xfs_has_crc(mp)) { -- xfs_update_cksum((char *)ddq, sizeof(struct xfs_dqblk), -+ xfs_update_cksum((char *)dqb, sizeof(struct xfs_dqblk), - XFS_DQUOT_CRC_OFF); - } - -+ /* Validate the recovered dquot. */ -+ fa = xfs_dqblk_verify(log->l_mp, dqb, dq_f->qlf_id); -+ if (fa) { -+ XFS_CORRUPTION_ERROR("Bad dquot after recovery", -+ XFS_ERRLEVEL_LOW, mp, dqb, -+ sizeof(struct xfs_dqblk)); -+ xfs_alert(mp, -+ "Metadata corruption detected at %pS, dquot 0x%x", -+ fa, dq_f->qlf_id); -+ error = -EFSCORRUPTED; -+ goto out_release; -+ } -+ - ASSERT(dq_f->qlf_size == 2); - ASSERT(bp->b_mount == mp); - bp->b_flags |= _XBF_LOGRECOVERY; -diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h -index 3dc47937da5..3beb470f189 100644 ---- a/fs/xfs/xfs_inode.h -+++ b/fs/xfs/xfs_inode.h -@@ -569,6 +569,14 @@ extern void xfs_setup_inode(struct xfs_inode *ip); - extern void xfs_setup_iops(struct xfs_inode *ip); - extern void xfs_diflags_to_iflags(struct xfs_inode *ip, bool init); - -+static inline void xfs_update_stable_writes(struct xfs_inode *ip) -+{ -+ if (bdev_stable_writes(xfs_inode_buftarg(ip)->bt_bdev)) -+ mapping_set_stable_writes(VFS_I(ip)->i_mapping); -+ else -+ mapping_clear_stable_writes(VFS_I(ip)->i_mapping); -+} -+ - /* - * When setting up a newly allocated inode, we need to call - * xfs_finish_inode_setup() once the inode is fully instantiated at -diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c -index a82470e027f..6c3919687ea 100644 ---- a/fs/xfs/xfs_ioctl.c -+++ b/fs/xfs/xfs_ioctl.c -@@ -1121,23 +1121,25 @@ xfs_ioctl_setattr_xflags( - struct fileattr *fa) - { - struct xfs_mount *mp = ip->i_mount; -+ bool rtflag = (fa->fsx_xflags & FS_XFLAG_REALTIME); - uint64_t i_flags2; - -- /* Can't change realtime flag if any extents are allocated. */ -- if ((ip->i_df.if_nextents || ip->i_delayed_blks) && -- XFS_IS_REALTIME_INODE(ip) != (fa->fsx_xflags & FS_XFLAG_REALTIME)) -- return -EINVAL; -+ if (rtflag != XFS_IS_REALTIME_INODE(ip)) { -+ /* Can't change realtime flag if any extents are allocated. */ -+ if (ip->i_df.if_nextents || ip->i_delayed_blks) -+ return -EINVAL; -+ } - -- /* If realtime flag is set then must have realtime device */ -- if (fa->fsx_xflags & FS_XFLAG_REALTIME) { -+ if (rtflag) { -+ /* If realtime flag is set then must have realtime device */ - if (mp->m_sb.sb_rblocks == 0 || mp->m_sb.sb_rextsize == 0 || - xfs_extlen_to_rtxmod(mp, ip->i_extsize)) - return -EINVAL; -- } - -- /* Clear reflink if we are actually able to set the rt flag. */ -- if ((fa->fsx_xflags & FS_XFLAG_REALTIME) && xfs_is_reflink_inode(ip)) -- ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK; -+ /* Clear reflink if we are actually able to set the rt flag. */ -+ if (xfs_is_reflink_inode(ip)) -+ ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK; -+ } - - /* diflags2 only valid for v3 inodes. */ - i_flags2 = xfs_flags2diflags2(ip, fa->fsx_xflags); -@@ -1148,6 +1150,14 @@ xfs_ioctl_setattr_xflags( - ip->i_diflags2 = i_flags2; - - xfs_diflags_to_iflags(ip, false); -+ -+ /* -+ * Make the stable writes flag match that of the device the inode -+ * resides on when flipping the RT flag. -+ */ -+ if (rtflag != XFS_IS_REALTIME_INODE(ip) && S_ISREG(VFS_I(ip)->i_mode)) -+ xfs_update_stable_writes(ip); -+ - xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - XFS_STATS_INC(mp, xs_ig_attrchg); -diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c -index fdfda4fba12..a0d77f5f512 100644 ---- a/fs/xfs/xfs_iops.c -+++ b/fs/xfs/xfs_iops.c -@@ -1298,6 +1298,13 @@ xfs_setup_inode( - gfp_mask = mapping_gfp_mask(inode->i_mapping); - mapping_set_gfp_mask(inode->i_mapping, (gfp_mask & ~(__GFP_FS))); - -+ /* -+ * For real-time inodes update the stable write flags to that of the RT -+ * device instead of the data device. -+ */ -+ if (S_ISREG(inode->i_mode) && XFS_IS_REALTIME_INODE(ip)) -+ xfs_update_stable_writes(ip); -+ - /* - * If there is no attribute fork no ACL can exist on this inode, - * and it can't have any file capabilities attached to it either. -diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h -index afeed6e7204..1216d72c650 100644 ---- a/include/acpi/acpi_bus.h -+++ b/include/acpi/acpi_bus.h -@@ -542,6 +542,7 @@ int acpi_device_set_power(struct acpi_device *device, int state); - int acpi_bus_init_power(struct acpi_device *device); - int acpi_device_fix_up_power(struct acpi_device *device); - void acpi_device_fix_up_power_extended(struct acpi_device *adev); -+void acpi_device_fix_up_power_children(struct acpi_device *adev); - int acpi_bus_update_power(acpi_handle handle, int *state_p); - int acpi_device_update_power(struct acpi_device *device, int *state_p); - bool acpi_bus_power_manageable(acpi_handle handle); -diff --git a/include/asm-generic/qspinlock.h b/include/asm-generic/qspinlock.h -index 995513fa269..0655aa5b57b 100644 ---- a/include/asm-generic/qspinlock.h -+++ b/include/asm-generic/qspinlock.h -@@ -70,7 +70,7 @@ static __always_inline int queued_spin_is_locked(struct qspinlock *lock) - */ - static __always_inline int queued_spin_value_unlocked(struct qspinlock lock) - { -- return !atomic_read(&lock.val); -+ return !lock.val.counter; - } - - /** diff --git a/include/dt-bindings/input/qcom,spmi-haptics.h b/include/dt-bindings/input/qcom,spmi-haptics.h new file mode 100644 index 00000000000..14a7e7d1471 @@ -23231,177 +16464,6 @@ index 00000000000..825bf7d47fe +#define VOICEMMODE1 1 + +#endif /* __DT_BINDINGS_Q6_VOICE_H__ */ -diff --git a/include/linux/blk-pm.h b/include/linux/blk-pm.h -index 2580e05a8ab..004b38a538f 100644 ---- a/include/linux/blk-pm.h -+++ b/include/linux/blk-pm.h -@@ -15,7 +15,6 @@ extern int blk_pre_runtime_suspend(struct request_queue *q); - extern void blk_post_runtime_suspend(struct request_queue *q, int err); - extern void blk_pre_runtime_resume(struct request_queue *q); - extern void blk_post_runtime_resume(struct request_queue *q); --extern void blk_set_runtime_active(struct request_queue *q); - #else - static inline void blk_pm_runtime_init(struct request_queue *q, - struct device *dev) {} -diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h -index 24213a99cc7..aa4d19d0bc9 100644 ---- a/include/linux/bpf_verifier.h -+++ b/include/linux/bpf_verifier.h -@@ -301,6 +301,17 @@ struct bpf_func_state { - struct tnum callback_ret_range; - bool in_async_callback_fn; - bool in_exception_callback_fn; -+ /* For callback calling functions that limit number of possible -+ * callback executions (e.g. bpf_loop) keeps track of current -+ * simulated iteration number. -+ * Value in frame N refers to number of times callback with frame -+ * N+1 was simulated, e.g. for the following call: -+ * -+ * bpf_loop(..., fn, ...); | suppose current frame is N -+ * | fn would be simulated in frame N+1 -+ * | number of simulations is tracked in frame N -+ */ -+ u32 callback_depth; - - /* The following fields should be last. See copy_func_state() */ - int acquired_refs; -@@ -400,6 +411,7 @@ struct bpf_verifier_state { - struct bpf_idx_pair *jmp_history; - u32 jmp_history_cnt; - u32 dfs_depth; -+ u32 callback_unroll_depth; - }; - - #define bpf_get_spilled_reg(slot, frame, mask) \ -@@ -511,6 +523,10 @@ struct bpf_insn_aux_data { - * this instruction, regardless of any heuristics - */ - bool force_checkpoint; -+ /* true if instruction is a call to a helper function that -+ * accepts callback function as a parameter. -+ */ -+ bool calls_callback; - }; - - #define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */ -diff --git a/include/linux/hid.h b/include/linux/hid.h -index 5a8387a4a71..bf43f3ff666 100644 ---- a/include/linux/hid.h -+++ b/include/linux/hid.h -@@ -679,6 +679,7 @@ struct hid_device { /* device report descriptor */ - struct list_head debug_list; - spinlock_t debug_list_lock; - wait_queue_head_t debug_wait; -+ struct kref ref; - - unsigned int id; /* system unique id */ - -@@ -687,6 +688,8 @@ struct hid_device { /* device report descriptor */ - #endif /* CONFIG_BPF */ - }; - -+void hiddev_free(struct kref *ref); -+ - #define to_hid_device(pdev) \ - container_of(pdev, struct hid_device, dev) - -diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h -index a16c9cc063f..2564e209465 100644 ---- a/include/linux/netdevice.h -+++ b/include/linux/netdevice.h -@@ -1797,6 +1797,13 @@ enum netdev_ml_priv_type { - ML_PRIV_CAN, - }; - -+enum netdev_stat_type { -+ NETDEV_PCPU_STAT_NONE, -+ NETDEV_PCPU_STAT_LSTATS, /* struct pcpu_lstats */ -+ NETDEV_PCPU_STAT_TSTATS, /* struct pcpu_sw_netstats */ -+ NETDEV_PCPU_STAT_DSTATS, /* struct pcpu_dstats */ -+}; -+ - /** - * struct net_device - The DEVICE structure. - * -@@ -1991,10 +1998,14 @@ enum netdev_ml_priv_type { - * - * @ml_priv: Mid-layer private - * @ml_priv_type: Mid-layer private type -- * @lstats: Loopback statistics -- * @tstats: Tunnel statistics -- * @dstats: Dummy statistics -- * @vstats: Virtual ethernet statistics -+ * -+ * @pcpu_stat_type: Type of device statistics which the core should -+ * allocate/free: none, lstats, tstats, dstats. none -+ * means the driver is handling statistics allocation/ -+ * freeing internally. -+ * @lstats: Loopback statistics: packets, bytes -+ * @tstats: Tunnel statistics: RX/TX packets, RX/TX bytes -+ * @dstats: Dummy statistics: RX/TX/drop packets, RX/TX bytes - * - * @garp_port: GARP - * @mrp_port: MRP -@@ -2354,6 +2365,7 @@ struct net_device { - void *ml_priv; - enum netdev_ml_priv_type ml_priv_type; - -+ enum netdev_stat_type pcpu_stat_type:8; - union { - struct pcpu_lstats __percpu *lstats; - struct pcpu_sw_netstats __percpu *tstats; -@@ -2755,6 +2767,16 @@ struct pcpu_sw_netstats { - struct u64_stats_sync syncp; - } __aligned(4 * sizeof(u64)); - -+struct pcpu_dstats { -+ u64 rx_packets; -+ u64 rx_bytes; -+ u64 rx_drops; -+ u64 tx_packets; -+ u64 tx_bytes; -+ u64 tx_drops; -+ struct u64_stats_sync syncp; -+} __aligned(8 * sizeof(u64)); -+ - struct pcpu_lstats { - u64_stats_t packets; - u64_stats_t bytes; -diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h -index bcc1ea44b4e..06142ff7f9c 100644 ---- a/include/linux/pagemap.h -+++ b/include/linux/pagemap.h -@@ -204,6 +204,8 @@ enum mapping_flags { - AS_NO_WRITEBACK_TAGS = 5, - AS_LARGE_FOLIO_SUPPORT = 6, - AS_RELEASE_ALWAYS, /* Call ->release_folio(), even if no private data */ -+ AS_STABLE_WRITES, /* must wait for writeback before modifying -+ folio contents */ - }; - - /** -@@ -289,6 +291,21 @@ static inline void mapping_clear_release_always(struct address_space *mapping) - clear_bit(AS_RELEASE_ALWAYS, &mapping->flags); - } - -+static inline bool mapping_stable_writes(const struct address_space *mapping) -+{ -+ return test_bit(AS_STABLE_WRITES, &mapping->flags); -+} -+ -+static inline void mapping_set_stable_writes(struct address_space *mapping) -+{ -+ set_bit(AS_STABLE_WRITES, &mapping->flags); -+} -+ -+static inline void mapping_clear_stable_writes(struct address_space *mapping) -+{ -+ clear_bit(AS_STABLE_WRITES, &mapping->flags); -+} -+ - static inline gfp_t mapping_gfp_mask(struct address_space * mapping) - { - return mapping->gfp_mask; diff --git a/include/linux/regulator/s2dos05.h b/include/linux/regulator/s2dos05.h new file mode 100644 index 00000000000..e33e8625758 @@ -23595,86 +16657,6 @@ index ab7eea01ab4..974597960b5 100644 struct rmi_device_platform_data_spi spi_data; /* function handler pdata */ -diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h -index b513749582d..e4de6bc1f69 100644 ---- a/include/linux/usb/phy.h -+++ b/include/linux/usb/phy.h -@@ -144,10 +144,6 @@ struct usb_phy { - */ - int (*set_wakeup)(struct usb_phy *x, bool enabled); - -- /* notify phy port status change */ -- int (*notify_port_status)(struct usb_phy *x, int port, -- u16 portstatus, u16 portchange); -- - /* notify phy connect status change */ - int (*notify_connect)(struct usb_phy *x, - enum usb_device_speed speed); -@@ -320,15 +316,6 @@ usb_phy_set_wakeup(struct usb_phy *x, bool enabled) - return 0; - } - --static inline int --usb_phy_notify_port_status(struct usb_phy *x, int port, u16 portstatus, u16 portchange) --{ -- if (x && x->notify_port_status) -- return x->notify_port_status(x, port, portstatus, portchange); -- else -- return 0; --} -- - static inline int - usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed) - { -diff --git a/include/net/netkit.h b/include/net/netkit.h -index 0ba2e6b847c..9ec0163739f 100644 ---- a/include/net/netkit.h -+++ b/include/net/netkit.h -@@ -10,6 +10,7 @@ int netkit_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog); - int netkit_link_attach(const union bpf_attr *attr, struct bpf_prog *prog); - int netkit_prog_detach(const union bpf_attr *attr, struct bpf_prog *prog); - int netkit_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr); -+INDIRECT_CALLABLE_DECLARE(struct net_device *netkit_peer_dev(struct net_device *dev)); - #else - static inline int netkit_prog_attach(const union bpf_attr *attr, - struct bpf_prog *prog) -@@ -34,5 +35,10 @@ static inline int netkit_prog_query(const union bpf_attr *attr, - { - return -EINVAL; - } -+ -+static inline struct net_device *netkit_peer_dev(struct net_device *dev) -+{ -+ return NULL; -+} - #endif /* CONFIG_NETKIT */ - #endif /* __NET_NETKIT_H */ -diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h -index 4c53a5ef625..f7e537f64db 100644 ---- a/include/trace/events/rxrpc.h -+++ b/include/trace/events/rxrpc.h -@@ -328,7 +328,7 @@ - E_(rxrpc_rtt_tx_ping, "PING") - - #define rxrpc_rtt_rx_traces \ -- EM(rxrpc_rtt_rx_cancel, "CNCL") \ -+ EM(rxrpc_rtt_rx_other_ack, "OACK") \ - EM(rxrpc_rtt_rx_obsolete, "OBSL") \ - EM(rxrpc_rtt_rx_lost, "LOST") \ - EM(rxrpc_rtt_rx_ping_response, "PONG") \ -diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h -index 6c80f96049b..282e90aeb16 100644 ---- a/include/uapi/linux/fcntl.h -+++ b/include/uapi/linux/fcntl.h -@@ -116,5 +116,8 @@ - #define AT_HANDLE_FID AT_REMOVEDIR /* file handle is needed to - compare object identity and may not - be usable to open_by_handle_at(2) */ -+#if defined(__KERNEL__) -+#define AT_GETATTR_NOSEC 0x80000000 -+#endif - - #endif /* _UAPI_LINUX_FCNTL_H */ diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index 022a520e31f..e8d5ee027b4 100644 --- a/include/uapi/linux/input-event-codes.h @@ -23700,1250 +16682,6 @@ index 022a520e31f..e8d5ee027b4 100644 +#define SND_PROFILE_RING 0x02 + #endif -diff --git a/io_uring/fs.c b/io_uring/fs.c -index 08e3b175469..eccea851dd5 100644 ---- a/io_uring/fs.c -+++ b/io_uring/fs.c -@@ -254,7 +254,7 @@ int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) - newf = u64_to_user_ptr(READ_ONCE(sqe->addr2)); - lnk->flags = READ_ONCE(sqe->hardlink_flags); - -- lnk->oldpath = getname(oldf); -+ lnk->oldpath = getname_uflags(oldf, lnk->flags); - if (IS_ERR(lnk->oldpath)) - return PTR_ERR(lnk->oldpath); - -diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c -index 7034be55533..f521c5965a9 100644 ---- a/io_uring/rsrc.c -+++ b/io_uring/rsrc.c -@@ -1258,7 +1258,7 @@ int io_import_fixed(int ddir, struct iov_iter *iter, - */ - const struct bio_vec *bvec = imu->bvec; - -- if (offset <= bvec->bv_len) { -+ if (offset < bvec->bv_len) { - /* - * Note, huge pages buffers consists of one large - * bvec entry and should always go this way. The other -diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c -index 6da370a047f..af2819d5c8e 100644 ---- a/kernel/bpf/verifier.c -+++ b/kernel/bpf/verifier.c -@@ -547,13 +547,12 @@ static bool is_dynptr_ref_function(enum bpf_func_id func_id) - return func_id == BPF_FUNC_dynptr_data; - } - --static bool is_callback_calling_kfunc(u32 btf_id); -+static bool is_sync_callback_calling_kfunc(u32 btf_id); - static bool is_bpf_throw_kfunc(struct bpf_insn *insn); - --static bool is_callback_calling_function(enum bpf_func_id func_id) -+static bool is_sync_callback_calling_function(enum bpf_func_id func_id) - { - return func_id == BPF_FUNC_for_each_map_elem || -- func_id == BPF_FUNC_timer_set_callback || - func_id == BPF_FUNC_find_vma || - func_id == BPF_FUNC_loop || - func_id == BPF_FUNC_user_ringbuf_drain; -@@ -564,6 +563,18 @@ static bool is_async_callback_calling_function(enum bpf_func_id func_id) - return func_id == BPF_FUNC_timer_set_callback; - } - -+static bool is_callback_calling_function(enum bpf_func_id func_id) -+{ -+ return is_sync_callback_calling_function(func_id) || -+ is_async_callback_calling_function(func_id); -+} -+ -+static bool is_sync_callback_calling_insn(struct bpf_insn *insn) -+{ -+ return (bpf_helper_call(insn) && is_sync_callback_calling_function(insn->imm)) || -+ (bpf_pseudo_kfunc_call(insn) && is_sync_callback_calling_kfunc(insn->imm)); -+} -+ - static bool is_storage_get_function(enum bpf_func_id func_id) - { - return func_id == BPF_FUNC_sk_storage_get || -@@ -1808,6 +1819,7 @@ static int copy_verifier_state(struct bpf_verifier_state *dst_state, - dst_state->first_insn_idx = src->first_insn_idx; - dst_state->last_insn_idx = src->last_insn_idx; - dst_state->dfs_depth = src->dfs_depth; -+ dst_state->callback_unroll_depth = src->callback_unroll_depth; - dst_state->used_as_loop_entry = src->used_as_loop_entry; - for (i = 0; i <= src->curframe; i++) { - dst = dst_state->frame[i]; -@@ -3439,13 +3451,11 @@ static void mark_insn_zext(struct bpf_verifier_env *env, - reg->subreg_def = DEF_NOT_SUBREG; - } - --static int check_reg_arg(struct bpf_verifier_env *env, u32 regno, -- enum reg_arg_type t) -+static int __check_reg_arg(struct bpf_verifier_env *env, struct bpf_reg_state *regs, u32 regno, -+ enum reg_arg_type t) - { -- struct bpf_verifier_state *vstate = env->cur_state; -- struct bpf_func_state *state = vstate->frame[vstate->curframe]; - struct bpf_insn *insn = env->prog->insnsi + env->insn_idx; -- struct bpf_reg_state *reg, *regs = state->regs; -+ struct bpf_reg_state *reg; - bool rw64; - - if (regno >= MAX_BPF_REG) { -@@ -3486,6 +3496,15 @@ static int check_reg_arg(struct bpf_verifier_env *env, u32 regno, - return 0; - } - -+static int check_reg_arg(struct bpf_verifier_env *env, u32 regno, -+ enum reg_arg_type t) -+{ -+ struct bpf_verifier_state *vstate = env->cur_state; -+ struct bpf_func_state *state = vstate->frame[vstate->curframe]; -+ -+ return __check_reg_arg(env, state->regs, regno, t); -+} -+ - static void mark_jmp_point(struct bpf_verifier_env *env, int idx) - { - env->insn_aux_data[idx].jmp_point = true; -@@ -3724,6 +3743,8 @@ static void fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask) - } - } - -+static bool calls_callback(struct bpf_verifier_env *env, int insn_idx); -+ - /* For given verifier state backtrack_insn() is called from the last insn to - * the first insn. Its purpose is to compute a bitmask of registers and - * stack slots that needs precision in the parent verifier state. -@@ -3899,16 +3920,13 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, - return -EFAULT; - return 0; - } -- } else if ((bpf_helper_call(insn) && -- is_callback_calling_function(insn->imm) && -- !is_async_callback_calling_function(insn->imm)) || -- (bpf_pseudo_kfunc_call(insn) && is_callback_calling_kfunc(insn->imm))) { -- /* callback-calling helper or kfunc call, which means -- * we are exiting from subprog, but unlike the subprog -- * call handling above, we shouldn't propagate -- * precision of r1-r5 (if any requested), as they are -- * not actually arguments passed directly to callback -- * subprogs -+ } else if (is_sync_callback_calling_insn(insn) && idx != subseq_idx - 1) { -+ /* exit from callback subprog to callback-calling helper or -+ * kfunc call. Use idx/subseq_idx check to discern it from -+ * straight line code backtracking. -+ * Unlike the subprog call handling above, we shouldn't -+ * propagate precision of r1-r5 (if any requested), as they are -+ * not actually arguments passed directly to callback subprogs - */ - if (bt_reg_mask(bt) & ~BPF_REGMASK_ARGS) { - verbose(env, "BUG regs %x\n", bt_reg_mask(bt)); -@@ -3943,10 +3961,18 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, - } else if (opcode == BPF_EXIT) { - bool r0_precise; - -+ /* Backtracking to a nested function call, 'idx' is a part of -+ * the inner frame 'subseq_idx' is a part of the outer frame. -+ * In case of a regular function call, instructions giving -+ * precision to registers R1-R5 should have been found already. -+ * In case of a callback, it is ok to have R1-R5 marked for -+ * backtracking, as these registers are set by the function -+ * invoking callback. -+ */ -+ if (subseq_idx >= 0 && calls_callback(env, subseq_idx)) -+ for (i = BPF_REG_1; i <= BPF_REG_5; i++) -+ bt_clear_reg(bt, i); - if (bt_reg_mask(bt) & BPF_REGMASK_ARGS) { -- /* if backtracing was looking for registers R1-R5 -- * they should have been found already. -- */ - verbose(env, "BUG regs %x\n", bt_reg_mask(bt)); - WARN_ONCE(1, "verifier backtracking bug"); - return -EFAULT; -@@ -9350,7 +9376,7 @@ static void clear_caller_saved_regs(struct bpf_verifier_env *env, - /* after the call registers r0 - r5 were scratched */ - for (i = 0; i < CALLER_SAVED_REGS; i++) { - mark_reg_not_init(env, regs, caller_saved[i]); -- check_reg_arg(env, caller_saved[i], DST_OP_NO_MARK); -+ __check_reg_arg(env, regs, caller_saved[i], DST_OP_NO_MARK); - } - } - -@@ -9363,11 +9389,10 @@ static int set_callee_state(struct bpf_verifier_env *env, - struct bpf_func_state *caller, - struct bpf_func_state *callee, int insn_idx); - --static int __check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn, -- int *insn_idx, int subprog, -- set_callee_state_fn set_callee_state_cb) -+static int setup_func_entry(struct bpf_verifier_env *env, int subprog, int callsite, -+ set_callee_state_fn set_callee_state_cb, -+ struct bpf_verifier_state *state) - { -- struct bpf_verifier_state *state = env->cur_state; - struct bpf_func_state *caller, *callee; - int err; - -@@ -9377,54 +9402,72 @@ static int __check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn - return -E2BIG; - } - -- caller = state->frame[state->curframe]; - if (state->frame[state->curframe + 1]) { - verbose(env, "verifier bug. Frame %d already allocated\n", - state->curframe + 1); - return -EFAULT; - } - -+ caller = state->frame[state->curframe]; -+ callee = kzalloc(sizeof(*callee), GFP_KERNEL); -+ if (!callee) -+ return -ENOMEM; -+ state->frame[state->curframe + 1] = callee; -+ -+ /* callee cannot access r0, r6 - r9 for reading and has to write -+ * into its own stack before reading from it. -+ * callee can read/write into caller's stack -+ */ -+ init_func_state(env, callee, -+ /* remember the callsite, it will be used by bpf_exit */ -+ callsite, -+ state->curframe + 1 /* frameno within this callchain */, -+ subprog /* subprog number within this prog */); -+ /* Transfer references to the callee */ -+ err = copy_reference_state(callee, caller); -+ err = err ?: set_callee_state_cb(env, caller, callee, callsite); -+ if (err) -+ goto err_out; -+ -+ /* only increment it after check_reg_arg() finished */ -+ state->curframe++; -+ -+ return 0; -+ -+err_out: -+ free_func_state(callee); -+ state->frame[state->curframe + 1] = NULL; -+ return err; -+} -+ -+static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *insn, -+ int insn_idx, int subprog, -+ set_callee_state_fn set_callee_state_cb) -+{ -+ struct bpf_verifier_state *state = env->cur_state, *callback_state; -+ struct bpf_func_state *caller, *callee; -+ int err; -+ -+ caller = state->frame[state->curframe]; - err = btf_check_subprog_call(env, subprog, caller->regs); - if (err == -EFAULT) - return err; -- if (subprog_is_global(env, subprog)) { -- if (err) { -- verbose(env, "Caller passes invalid args into func#%d\n", -- subprog); -- return err; -- } else { -- if (env->log.level & BPF_LOG_LEVEL) -- verbose(env, -- "Func#%d is global and valid. Skipping.\n", -- subprog); -- clear_caller_saved_regs(env, caller->regs); -- -- /* All global functions return a 64-bit SCALAR_VALUE */ -- mark_reg_unknown(env, caller->regs, BPF_REG_0); -- caller->regs[BPF_REG_0].subreg_def = DEF_NOT_SUBREG; -- -- /* continue with next insn after call */ -- return 0; -- } -- } - - /* set_callee_state is used for direct subprog calls, but we are - * interested in validating only BPF helpers that can call subprogs as - * callbacks - */ -- if (set_callee_state_cb != set_callee_state) { -- env->subprog_info[subprog].is_cb = true; -- if (bpf_pseudo_kfunc_call(insn) && -- !is_callback_calling_kfunc(insn->imm)) { -- verbose(env, "verifier bug: kfunc %s#%d not marked as callback-calling\n", -- func_id_name(insn->imm), insn->imm); -- return -EFAULT; -- } else if (!bpf_pseudo_kfunc_call(insn) && -- !is_callback_calling_function(insn->imm)) { /* helper */ -- verbose(env, "verifier bug: helper %s#%d not marked as callback-calling\n", -- func_id_name(insn->imm), insn->imm); -- return -EFAULT; -- } -+ env->subprog_info[subprog].is_cb = true; -+ if (bpf_pseudo_kfunc_call(insn) && -+ !is_sync_callback_calling_kfunc(insn->imm)) { -+ verbose(env, "verifier bug: kfunc %s#%d not marked as callback-calling\n", -+ func_id_name(insn->imm), insn->imm); -+ return -EFAULT; -+ } else if (!bpf_pseudo_kfunc_call(insn) && -+ !is_callback_calling_function(insn->imm)) { /* helper */ -+ verbose(env, "verifier bug: helper %s#%d not marked as callback-calling\n", -+ func_id_name(insn->imm), insn->imm); -+ return -EFAULT; - } - - if (insn->code == (BPF_JMP | BPF_CALL) && -@@ -9435,53 +9478,83 @@ static int __check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn - /* there is no real recursion here. timer callbacks are async */ - env->subprog_info[subprog].is_async_cb = true; - async_cb = push_async_cb(env, env->subprog_info[subprog].start, -- *insn_idx, subprog); -+ insn_idx, subprog); - if (!async_cb) - return -EFAULT; - callee = async_cb->frame[0]; - callee->async_entry_cnt = caller->async_entry_cnt + 1; - - /* Convert bpf_timer_set_callback() args into timer callback args */ -- err = set_callee_state_cb(env, caller, callee, *insn_idx); -+ err = set_callee_state_cb(env, caller, callee, insn_idx); - if (err) - return err; - -+ return 0; -+ } -+ -+ /* for callback functions enqueue entry to callback and -+ * proceed with next instruction within current frame. -+ */ -+ callback_state = push_stack(env, env->subprog_info[subprog].start, insn_idx, false); -+ if (!callback_state) -+ return -ENOMEM; -+ -+ err = setup_func_entry(env, subprog, insn_idx, set_callee_state_cb, -+ callback_state); -+ if (err) -+ return err; -+ -+ callback_state->callback_unroll_depth++; -+ callback_state->frame[callback_state->curframe - 1]->callback_depth++; -+ caller->callback_depth = 0; -+ return 0; -+} -+ -+static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn, -+ int *insn_idx) -+{ -+ struct bpf_verifier_state *state = env->cur_state; -+ struct bpf_func_state *caller; -+ int err, subprog, target_insn; -+ -+ target_insn = *insn_idx + insn->imm + 1; -+ subprog = find_subprog(env, target_insn); -+ if (subprog < 0) { -+ verbose(env, "verifier bug. No program starts at insn %d\n", target_insn); -+ return -EFAULT; -+ } -+ -+ caller = state->frame[state->curframe]; -+ err = btf_check_subprog_call(env, subprog, caller->regs); -+ if (err == -EFAULT) -+ return err; -+ if (subprog_is_global(env, subprog)) { -+ if (err) { -+ verbose(env, "Caller passes invalid args into func#%d\n", subprog); -+ return err; -+ } -+ -+ if (env->log.level & BPF_LOG_LEVEL) -+ verbose(env, "Func#%d is global and valid. Skipping.\n", subprog); - clear_caller_saved_regs(env, caller->regs); -+ -+ /* All global functions return a 64-bit SCALAR_VALUE */ - mark_reg_unknown(env, caller->regs, BPF_REG_0); - caller->regs[BPF_REG_0].subreg_def = DEF_NOT_SUBREG; -+ - /* continue with next insn after call */ - return 0; - } - -- callee = kzalloc(sizeof(*callee), GFP_KERNEL); -- if (!callee) -- return -ENOMEM; -- state->frame[state->curframe + 1] = callee; -- -- /* callee cannot access r0, r6 - r9 for reading and has to write -- * into its own stack before reading from it. -- * callee can read/write into caller's stack -+ /* for regular function entry setup new frame and continue -+ * from that frame. - */ -- init_func_state(env, callee, -- /* remember the callsite, it will be used by bpf_exit */ -- *insn_idx /* callsite */, -- state->curframe + 1 /* frameno within this callchain */, -- subprog /* subprog number within this prog */); -- -- /* Transfer references to the callee */ -- err = copy_reference_state(callee, caller); -+ err = setup_func_entry(env, subprog, *insn_idx, set_callee_state, state); - if (err) -- goto err_out; -- -- err = set_callee_state_cb(env, caller, callee, *insn_idx); -- if (err) -- goto err_out; -+ return err; - - clear_caller_saved_regs(env, caller->regs); - -- /* only increment it after check_reg_arg() finished */ -- state->curframe++; -- - /* and go analyze first insn of the callee */ - *insn_idx = env->subprog_info[subprog].start - 1; - -@@ -9489,14 +9562,10 @@ static int __check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn - verbose(env, "caller:\n"); - print_verifier_state(env, caller, true); - verbose(env, "callee:\n"); -- print_verifier_state(env, callee, true); -+ print_verifier_state(env, state->frame[state->curframe], true); - } -- return 0; - --err_out: -- free_func_state(callee); -- state->frame[state->curframe + 1] = NULL; -- return err; -+ return 0; - } - - int map_set_for_each_callback_args(struct bpf_verifier_env *env, -@@ -9540,22 +9609,6 @@ static int set_callee_state(struct bpf_verifier_env *env, - return 0; - } - --static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn, -- int *insn_idx) --{ -- int subprog, target_insn; -- -- target_insn = *insn_idx + insn->imm + 1; -- subprog = find_subprog(env, target_insn); -- if (subprog < 0) { -- verbose(env, "verifier bug. No program starts at insn %d\n", -- target_insn); -- return -EFAULT; -- } -- -- return __check_func_call(env, insn, insn_idx, subprog, set_callee_state); --} -- - static int set_map_elem_callback_state(struct bpf_verifier_env *env, - struct bpf_func_state *caller, - struct bpf_func_state *callee, -@@ -9748,9 +9801,10 @@ static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env) - - static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) - { -- struct bpf_verifier_state *state = env->cur_state; -+ struct bpf_verifier_state *state = env->cur_state, *prev_st; - struct bpf_func_state *caller, *callee; - struct bpf_reg_state *r0; -+ bool in_callback_fn; - int err; - - callee = state->frame[state->curframe]; -@@ -9779,6 +9833,11 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) - verbose_invalid_scalar(env, r0, &range, "callback return", "R0"); - return -EINVAL; - } -+ if (!calls_callback(env, callee->callsite)) { -+ verbose(env, "BUG: in callback at %d, callsite %d !calls_callback\n", -+ *insn_idx, callee->callsite); -+ return -EFAULT; -+ } - } else { - /* return to the caller whatever r0 had in the callee */ - caller->regs[BPF_REG_0] = *r0; -@@ -9796,7 +9855,16 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) - return err; - } - -- *insn_idx = callee->callsite + 1; -+ /* for callbacks like bpf_loop or bpf_for_each_map_elem go back to callsite, -+ * there function call logic would reschedule callback visit. If iteration -+ * converges is_state_visited() would prune that visit eventually. -+ */ -+ in_callback_fn = callee->in_callback_fn; -+ if (in_callback_fn) -+ *insn_idx = callee->callsite; -+ else -+ *insn_idx = callee->callsite + 1; -+ - if (env->log.level & BPF_LOG_LEVEL) { - verbose(env, "returning from callee:\n"); - print_verifier_state(env, callee, true); -@@ -9807,6 +9875,24 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) - * bpf_throw, this will be done by copy_verifier_state for extra frames. */ - free_func_state(callee); - state->frame[state->curframe--] = NULL; -+ -+ /* for callbacks widen imprecise scalars to make programs like below verify: -+ * -+ * struct ctx { int i; } -+ * void cb(int idx, struct ctx *ctx) { ctx->i++; ... } -+ * ... -+ * struct ctx = { .i = 0; } -+ * bpf_loop(100, cb, &ctx, 0); -+ * -+ * This is similar to what is done in process_iter_next_call() for open -+ * coded iterators. -+ */ -+ prev_st = in_callback_fn ? find_prev_entry(env, state, *insn_idx) : NULL; -+ if (prev_st) { -+ err = widen_imprecise_scalars(env, prev_st, state); -+ if (err) -+ return err; -+ } - return 0; - } - -@@ -10209,24 +10295,37 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn - } - break; - case BPF_FUNC_for_each_map_elem: -- err = __check_func_call(env, insn, insn_idx_p, meta.subprogno, -- set_map_elem_callback_state); -+ err = push_callback_call(env, insn, insn_idx, meta.subprogno, -+ set_map_elem_callback_state); - break; - case BPF_FUNC_timer_set_callback: -- err = __check_func_call(env, insn, insn_idx_p, meta.subprogno, -- set_timer_callback_state); -+ err = push_callback_call(env, insn, insn_idx, meta.subprogno, -+ set_timer_callback_state); - break; - case BPF_FUNC_find_vma: -- err = __check_func_call(env, insn, insn_idx_p, meta.subprogno, -- set_find_vma_callback_state); -+ err = push_callback_call(env, insn, insn_idx, meta.subprogno, -+ set_find_vma_callback_state); - break; - case BPF_FUNC_snprintf: - err = check_bpf_snprintf_call(env, regs); - break; - case BPF_FUNC_loop: - update_loop_inline_state(env, meta.subprogno); -- err = __check_func_call(env, insn, insn_idx_p, meta.subprogno, -- set_loop_callback_state); -+ /* Verifier relies on R1 value to determine if bpf_loop() iteration -+ * is finished, thus mark it precise. -+ */ -+ err = mark_chain_precision(env, BPF_REG_1); -+ if (err) -+ return err; -+ if (cur_func(env)->callback_depth < regs[BPF_REG_1].umax_value) { -+ err = push_callback_call(env, insn, insn_idx, meta.subprogno, -+ set_loop_callback_state); -+ } else { -+ cur_func(env)->callback_depth = 0; -+ if (env->log.level & BPF_LOG_LEVEL2) -+ verbose(env, "frame%d bpf_loop iteration limit reached\n", -+ env->cur_state->curframe); -+ } - break; - case BPF_FUNC_dynptr_from_mem: - if (regs[BPF_REG_1].type != PTR_TO_MAP_VALUE) { -@@ -10322,8 +10421,8 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn - break; - } - case BPF_FUNC_user_ringbuf_drain: -- err = __check_func_call(env, insn, insn_idx_p, meta.subprogno, -- set_user_ringbuf_callback_state); -+ err = push_callback_call(env, insn, insn_idx, meta.subprogno, -+ set_user_ringbuf_callback_state); - break; - } - -@@ -11211,7 +11310,7 @@ static bool is_bpf_graph_api_kfunc(u32 btf_id) - btf_id == special_kfunc_list[KF_bpf_refcount_acquire_impl]; - } - --static bool is_callback_calling_kfunc(u32 btf_id) -+static bool is_sync_callback_calling_kfunc(u32 btf_id) - { - return btf_id == special_kfunc_list[KF_bpf_rbtree_add_impl]; - } -@@ -11963,6 +12062,21 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, - return -EACCES; - } - -+ /* Check the arguments */ -+ err = check_kfunc_args(env, &meta, insn_idx); -+ if (err < 0) -+ return err; -+ -+ if (meta.func_id == special_kfunc_list[KF_bpf_rbtree_add_impl]) { -+ err = push_callback_call(env, insn, insn_idx, meta.subprogno, -+ set_rbtree_add_callback_state); -+ if (err) { -+ verbose(env, "kfunc %s#%d failed callback verification\n", -+ func_name, meta.func_id); -+ return err; -+ } -+ } -+ - rcu_lock = is_kfunc_bpf_rcu_read_lock(&meta); - rcu_unlock = is_kfunc_bpf_rcu_read_unlock(&meta); - -@@ -11998,10 +12112,6 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, - return -EINVAL; - } - -- /* Check the arguments */ -- err = check_kfunc_args(env, &meta, insn_idx); -- if (err < 0) -- return err; - /* In case of release function, we get register number of refcounted - * PTR_TO_BTF_ID in bpf_kfunc_arg_meta, do the release now. - */ -@@ -12035,16 +12145,6 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, - } - } - -- if (meta.func_id == special_kfunc_list[KF_bpf_rbtree_add_impl]) { -- err = __check_func_call(env, insn, insn_idx_p, meta.subprogno, -- set_rbtree_add_callback_state); -- if (err) { -- verbose(env, "kfunc %s#%d failed callback verification\n", -- func_name, meta.func_id); -- return err; -- } -- } -- - if (meta.func_id == special_kfunc_list[KF_bpf_throw]) { - if (!bpf_jit_supports_exceptions()) { - verbose(env, "JIT does not support calling kfunc %s#%d\n", -@@ -15408,6 +15508,15 @@ static bool is_force_checkpoint(struct bpf_verifier_env *env, int insn_idx) - return env->insn_aux_data[insn_idx].force_checkpoint; - } - -+static void mark_calls_callback(struct bpf_verifier_env *env, int idx) -+{ -+ env->insn_aux_data[idx].calls_callback = true; -+} -+ -+static bool calls_callback(struct bpf_verifier_env *env, int insn_idx) -+{ -+ return env->insn_aux_data[insn_idx].calls_callback; -+} - - enum { - DONE_EXPLORING = 0, -@@ -15521,6 +15630,21 @@ static int visit_insn(int t, struct bpf_verifier_env *env) - * async state will be pushed for further exploration. - */ - mark_prune_point(env, t); -+ /* For functions that invoke callbacks it is not known how many times -+ * callback would be called. Verifier models callback calling functions -+ * by repeatedly visiting callback bodies and returning to origin call -+ * instruction. -+ * In order to stop such iteration verifier needs to identify when a -+ * state identical some state from a previous iteration is reached. -+ * Check below forces creation of checkpoint before callback calling -+ * instruction to allow search for such identical states. -+ */ -+ if (is_sync_callback_calling_insn(insn)) { -+ mark_calls_callback(env, t); -+ mark_force_checkpoint(env, t); -+ mark_prune_point(env, t); -+ mark_jmp_point(env, t); -+ } - if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) { - struct bpf_kfunc_call_arg_meta meta; - -@@ -16990,10 +17114,16 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) - } - goto skip_inf_loop_check; - } -+ if (calls_callback(env, insn_idx)) { -+ if (states_equal(env, &sl->state, cur, true)) -+ goto hit; -+ goto skip_inf_loop_check; -+ } - /* attempt to detect infinite loop to avoid unnecessary doomed work */ - if (states_maybe_looping(&sl->state, cur) && - states_equal(env, &sl->state, cur, false) && -- !iter_active_depths_differ(&sl->state, cur)) { -+ !iter_active_depths_differ(&sl->state, cur) && -+ sl->state.callback_unroll_depth == cur->callback_unroll_depth) { - verbose_linfo(env, insn_idx, "; "); - verbose(env, "infinite loop detected at insn %d\n", insn_idx); - verbose(env, "cur state:"); -diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c -index e85b5ad3e20..151bd3de593 100644 ---- a/kernel/locking/lockdep.c -+++ b/kernel/locking/lockdep.c -@@ -3497,7 +3497,8 @@ static int alloc_chain_hlocks(int req) - size = chain_block_size(curr); - if (likely(size >= req)) { - del_chain_block(0, size, chain_block_next(curr)); -- add_chain_block(curr + req, size - req); -+ if (size > req) -+ add_chain_block(curr + req, size - req); - return curr; - } - } -diff --git a/lib/errname.c b/lib/errname.c -index dd1b998552c..4f9112b38f3 100644 ---- a/lib/errname.c -+++ b/lib/errname.c -@@ -111,9 +111,6 @@ static const char *names_0[] = { - E(ENOSPC), - E(ENOSR), - E(ENOSTR), --#ifdef ENOSYM -- E(ENOSYM), --#endif - E(ENOSYS), - E(ENOTBLK), - E(ENOTCONN), -@@ -144,9 +141,6 @@ static const char *names_0[] = { - #endif - E(EREMOTE), - E(EREMOTEIO), --#ifdef EREMOTERELEASE -- E(EREMOTERELEASE), --#endif - E(ERESTART), - E(ERFKILL), - E(EROFS), -diff --git a/lib/iov_iter.c b/lib/iov_iter.c -index de7d11cf4c6..8ff6824a100 100644 ---- a/lib/iov_iter.c -+++ b/lib/iov_iter.c -@@ -409,7 +409,7 @@ size_t copy_page_to_iter_nofault(struct page *page, unsigned offset, size_t byte - void *kaddr = kmap_local_page(page); - size_t n = min(bytes, (size_t)PAGE_SIZE - offset); - -- n = iterate_and_advance(i, bytes, kaddr, -+ n = iterate_and_advance(i, n, kaddr + offset, - copy_to_user_iter_nofault, - memcpy_to_iter); - kunmap_local(kaddr); -diff --git a/mm/page-writeback.c b/mm/page-writeback.c -index 46f2f5d3d18..ee2fd6a6af4 100644 ---- a/mm/page-writeback.c -+++ b/mm/page-writeback.c -@@ -3107,7 +3107,7 @@ EXPORT_SYMBOL_GPL(folio_wait_writeback_killable); - */ - void folio_wait_stable(struct folio *folio) - { -- if (folio_inode(folio)->i_sb->s_iflags & SB_I_STABLE_WRITES) -+ if (mapping_stable_writes(folio_mapping(folio))) - folio_wait_writeback(folio); - } - EXPORT_SYMBOL_GPL(folio_wait_stable); -diff --git a/net/core/dev.c b/net/core/dev.c -index af53f6d838c..c879246be48 100644 ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -10051,6 +10051,54 @@ void netif_tx_stop_all_queues(struct net_device *dev) - } - EXPORT_SYMBOL(netif_tx_stop_all_queues); - -+static int netdev_do_alloc_pcpu_stats(struct net_device *dev) -+{ -+ void __percpu *v; -+ -+ /* Drivers implementing ndo_get_peer_dev must support tstat -+ * accounting, so that skb_do_redirect() can bump the dev's -+ * RX stats upon network namespace switch. -+ */ -+ if (dev->netdev_ops->ndo_get_peer_dev && -+ dev->pcpu_stat_type != NETDEV_PCPU_STAT_TSTATS) -+ return -EOPNOTSUPP; -+ -+ switch (dev->pcpu_stat_type) { -+ case NETDEV_PCPU_STAT_NONE: -+ return 0; -+ case NETDEV_PCPU_STAT_LSTATS: -+ v = dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); -+ break; -+ case NETDEV_PCPU_STAT_TSTATS: -+ v = dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); -+ break; -+ case NETDEV_PCPU_STAT_DSTATS: -+ v = dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return v ? 0 : -ENOMEM; -+} -+ -+static void netdev_do_free_pcpu_stats(struct net_device *dev) -+{ -+ switch (dev->pcpu_stat_type) { -+ case NETDEV_PCPU_STAT_NONE: -+ return; -+ case NETDEV_PCPU_STAT_LSTATS: -+ free_percpu(dev->lstats); -+ break; -+ case NETDEV_PCPU_STAT_TSTATS: -+ free_percpu(dev->tstats); -+ break; -+ case NETDEV_PCPU_STAT_DSTATS: -+ free_percpu(dev->dstats); -+ break; -+ } -+} -+ - /** - * register_netdevice() - register a network device - * @dev: device to register -@@ -10111,9 +10159,13 @@ int register_netdevice(struct net_device *dev) - goto err_uninit; - } - -+ ret = netdev_do_alloc_pcpu_stats(dev); -+ if (ret) -+ goto err_uninit; -+ - ret = dev_index_reserve(net, dev->ifindex); - if (ret < 0) -- goto err_uninit; -+ goto err_free_pcpu; - dev->ifindex = ret; - - /* Transfer changeable features to wanted_features and enable -@@ -10219,6 +10271,8 @@ int register_netdevice(struct net_device *dev) - call_netdevice_notifiers(NETDEV_PRE_UNINIT, dev); - err_ifindex_release: - dev_index_release(net, dev->ifindex); -+err_free_pcpu: -+ netdev_do_free_pcpu_stats(dev); - err_uninit: - if (dev->netdev_ops->ndo_uninit) - dev->netdev_ops->ndo_uninit(dev); -@@ -10471,6 +10525,7 @@ void netdev_run_todo(void) - WARN_ON(rcu_access_pointer(dev->ip_ptr)); - WARN_ON(rcu_access_pointer(dev->ip6_ptr)); - -+ netdev_do_free_pcpu_stats(dev); - if (dev->priv_destructor) - dev->priv_destructor(dev); - if (dev->needs_free_netdev) -diff --git a/net/core/filter.c b/net/core/filter.c -index 383f96b0a1c..7e4d7c3bcc8 100644 ---- a/net/core/filter.c -+++ b/net/core/filter.c -@@ -81,6 +81,7 @@ - #include - #include - #include -+#include - #include - - #include "dev.h" -@@ -2468,6 +2469,16 @@ static const struct bpf_func_proto bpf_clone_redirect_proto = { - DEFINE_PER_CPU(struct bpf_redirect_info, bpf_redirect_info); - EXPORT_PER_CPU_SYMBOL_GPL(bpf_redirect_info); - -+static struct net_device *skb_get_peer_dev(struct net_device *dev) -+{ -+ const struct net_device_ops *ops = dev->netdev_ops; -+ -+ if (likely(ops->ndo_get_peer_dev)) -+ return INDIRECT_CALL_1(ops->ndo_get_peer_dev, -+ netkit_peer_dev, dev); -+ return NULL; -+} -+ - int skb_do_redirect(struct sk_buff *skb) - { - struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info); -@@ -2481,17 +2492,15 @@ int skb_do_redirect(struct sk_buff *skb) - if (unlikely(!dev)) - goto out_drop; - if (flags & BPF_F_PEER) { -- const struct net_device_ops *ops = dev->netdev_ops; -- -- if (unlikely(!ops->ndo_get_peer_dev || -- !skb_at_tc_ingress(skb))) -+ if (unlikely(!skb_at_tc_ingress(skb))) - goto out_drop; -- dev = ops->ndo_get_peer_dev(dev); -+ dev = skb_get_peer_dev(dev); - if (unlikely(!dev || - !(dev->flags & IFF_UP) || - net_eq(net, dev_net(dev)))) - goto out_drop; - skb->dev = dev; -+ dev_sw_netstats_rx_add(dev, skb->len); - return -EAGAIN; - } - return flags & BPF_F_NEIGH ? -diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c -index f01aee832aa..7d0e7aaa71e 100644 ---- a/net/ipv4/inet_diag.c -+++ b/net/ipv4/inet_diag.c -@@ -1481,5 +1481,6 @@ static void __exit inet_diag_exit(void) - module_init(inet_diag_init); - module_exit(inet_diag_exit); - MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("INET/INET6: socket monitoring via SOCK_DIAG"); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2 /* AF_INET */); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 10 /* AF_INET6 */); -diff --git a/net/ipv4/raw_diag.c b/net/ipv4/raw_diag.c -index 63a40e4b678..fe2140c8375 100644 ---- a/net/ipv4/raw_diag.c -+++ b/net/ipv4/raw_diag.c -@@ -257,5 +257,6 @@ static void __exit raw_diag_exit(void) - module_init(raw_diag_init); - module_exit(raw_diag_exit); - MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("RAW socket monitoring via SOCK_DIAG"); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-255 /* AF_INET - IPPROTO_RAW */); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 10-255 /* AF_INET6 - IPPROTO_RAW */); -diff --git a/net/ipv4/route.c b/net/ipv4/route.c -index 3290a4442b4..16615d107cf 100644 ---- a/net/ipv4/route.c -+++ b/net/ipv4/route.c -@@ -780,7 +780,7 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow - goto reject_redirect; - } - -- n = __ipv4_neigh_lookup(rt->dst.dev, new_gw); -+ n = __ipv4_neigh_lookup(rt->dst.dev, (__force u32)new_gw); - if (!n) - n = neigh_create(&arp_tbl, &new_gw, rt->dst.dev); - if (!IS_ERR(n)) { -diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c -index 01b50fa7918..4cbe4b44425 100644 ---- a/net/ipv4/tcp_diag.c -+++ b/net/ipv4/tcp_diag.c -@@ -247,4 +247,5 @@ static void __exit tcp_diag_exit(void) - module_init(tcp_diag_init); - module_exit(tcp_diag_exit); - MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("TCP socket monitoring via SOCK_DIAG"); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-6 /* AF_INET - IPPROTO_TCP */); -diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c -index de3f2d31f51..dc41a22ee80 100644 ---- a/net/ipv4/udp_diag.c -+++ b/net/ipv4/udp_diag.c -@@ -296,5 +296,6 @@ static void __exit udp_diag_exit(void) - module_init(udp_diag_init); - module_exit(udp_diag_exit); - MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("UDP socket monitoring via SOCK_DIAG"); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-17 /* AF_INET - IPPROTO_UDP */); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-136 /* AF_INET - IPPROTO_UDPLITE */); -diff --git a/net/mptcp/mptcp_diag.c b/net/mptcp/mptcp_diag.c -index 8df1bdb647e..5409c2ea3f5 100644 ---- a/net/mptcp/mptcp_diag.c -+++ b/net/mptcp/mptcp_diag.c -@@ -245,4 +245,5 @@ static void __exit mptcp_diag_exit(void) - module_init(mptcp_diag_init); - module_exit(mptcp_diag_exit); - MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("MPTCP socket monitoring via SOCK_DIAG"); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-262 /* AF_INET - IPPROTO_MPTCP */); -diff --git a/net/packet/diag.c b/net/packet/diag.c -index f6b200cb3c0..9a7980e3309 100644 ---- a/net/packet/diag.c -+++ b/net/packet/diag.c -@@ -262,4 +262,5 @@ static void __exit packet_diag_exit(void) - module_init(packet_diag_init); - module_exit(packet_diag_exit); - MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("PACKET socket monitoring via SOCK_DIAG"); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 17 /* AF_PACKET */); -diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c -index 981ca5b98bc..1d95f8bc769 100644 ---- a/net/rxrpc/conn_client.c -+++ b/net/rxrpc/conn_client.c -@@ -73,6 +73,7 @@ static void rxrpc_destroy_client_conn_ids(struct rxrpc_local *local) - static struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_call *call, - gfp_t gfp) - { -+ static atomic_t rxrpc_bundle_id; - struct rxrpc_bundle *bundle; - - bundle = kzalloc(sizeof(*bundle), gfp); -@@ -85,6 +86,7 @@ static struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_call *call, - bundle->upgrade = test_bit(RXRPC_CALL_UPGRADE, &call->flags); - bundle->service_id = call->dest_srx.srx_service; - bundle->security_level = call->security_level; -+ bundle->debug_id = atomic_inc_return(&rxrpc_bundle_id); - refcount_set(&bundle->ref, 1); - atomic_set(&bundle->active, 1); - INIT_LIST_HEAD(&bundle->waiting_calls); -@@ -105,7 +107,8 @@ struct rxrpc_bundle *rxrpc_get_bundle(struct rxrpc_bundle *bundle, - - static void rxrpc_free_bundle(struct rxrpc_bundle *bundle) - { -- trace_rxrpc_bundle(bundle->debug_id, 1, rxrpc_bundle_free); -+ trace_rxrpc_bundle(bundle->debug_id, refcount_read(&bundle->ref), -+ rxrpc_bundle_free); - rxrpc_put_peer(bundle->peer, rxrpc_peer_put_bundle); - key_put(bundle->key); - kfree(bundle); -@@ -239,7 +242,6 @@ static bool rxrpc_may_reuse_conn(struct rxrpc_connection *conn) - */ - int rxrpc_look_up_bundle(struct rxrpc_call *call, gfp_t gfp) - { -- static atomic_t rxrpc_bundle_id; - struct rxrpc_bundle *bundle, *candidate; - struct rxrpc_local *local = call->local; - struct rb_node *p, **pp, *parent; -@@ -306,7 +308,6 @@ int rxrpc_look_up_bundle(struct rxrpc_call *call, gfp_t gfp) - } - - _debug("new bundle"); -- candidate->debug_id = atomic_inc_return(&rxrpc_bundle_id); - rb_link_node(&candidate->local_node, parent, pp); - rb_insert_color(&candidate->local_node, &local->client_bundles); - call->bundle = rxrpc_get_bundle(candidate, rxrpc_bundle_get_client_call); -diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c -index 030d64f282f..92495e73b86 100644 ---- a/net/rxrpc/input.c -+++ b/net/rxrpc/input.c -@@ -643,12 +643,8 @@ static void rxrpc_complete_rtt_probe(struct rxrpc_call *call, - clear_bit(i + RXRPC_CALL_RTT_PEND_SHIFT, &call->rtt_avail); - smp_mb(); /* Read data before setting avail bit */ - set_bit(i, &call->rtt_avail); -- if (type != rxrpc_rtt_rx_cancel) -- rxrpc_peer_add_rtt(call, type, i, acked_serial, ack_serial, -- sent_at, resp_time); -- else -- trace_rxrpc_rtt_rx(call, rxrpc_rtt_rx_cancel, i, -- orig_serial, acked_serial, 0, 0); -+ rxrpc_peer_add_rtt(call, type, i, acked_serial, ack_serial, -+ sent_at, resp_time); - matched = true; - } - -@@ -801,28 +797,21 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) - summary.ack_reason, nr_acks); - rxrpc_inc_stat(call->rxnet, stat_rx_acks[ack.reason]); - -- switch (ack.reason) { -- case RXRPC_ACK_PING_RESPONSE: -- rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial, -- rxrpc_rtt_rx_ping_response); -- break; -- case RXRPC_ACK_REQUESTED: -- rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial, -- rxrpc_rtt_rx_requested_ack); -- break; -- default: -- if (acked_serial != 0) -+ if (acked_serial != 0) { -+ switch (ack.reason) { -+ case RXRPC_ACK_PING_RESPONSE: - rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial, -- rxrpc_rtt_rx_cancel); -- break; -- } -- -- if (ack.reason == RXRPC_ACK_PING) { -- rxrpc_send_ACK(call, RXRPC_ACK_PING_RESPONSE, ack_serial, -- rxrpc_propose_ack_respond_to_ping); -- } else if (sp->hdr.flags & RXRPC_REQUEST_ACK) { -- rxrpc_send_ACK(call, RXRPC_ACK_REQUESTED, ack_serial, -- rxrpc_propose_ack_respond_to_ack); -+ rxrpc_rtt_rx_ping_response); -+ break; -+ case RXRPC_ACK_REQUESTED: -+ rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial, -+ rxrpc_rtt_rx_requested_ack); -+ break; -+ default: -+ rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial, -+ rxrpc_rtt_rx_other_ack); -+ break; -+ } - } - - /* If we get an EXCEEDS_WINDOW ACK from the server, it probably -@@ -835,7 +824,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) - rxrpc_is_client_call(call)) { - rxrpc_set_call_completion(call, RXRPC_CALL_REMOTELY_ABORTED, - 0, -ENETRESET); -- return; -+ goto send_response; - } - - /* If we get an OUT_OF_SEQUENCE ACK from the server, that can also -@@ -849,7 +838,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) - rxrpc_is_client_call(call)) { - rxrpc_set_call_completion(call, RXRPC_CALL_REMOTELY_ABORTED, - 0, -ENETRESET); -- return; -+ goto send_response; - } - - /* Discard any out-of-order or duplicate ACKs (outside lock). */ -@@ -857,7 +846,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) - trace_rxrpc_rx_discard_ack(call->debug_id, ack_serial, - first_soft_ack, call->acks_first_seq, - prev_pkt, call->acks_prev_seq); -- return; -+ goto send_response; - } - - info.rxMTU = 0; -@@ -897,7 +886,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) - case RXRPC_CALL_SERVER_AWAIT_ACK: - break; - default: -- return; -+ goto send_response; - } - - if (before(hard_ack, call->acks_hard_ack) || -@@ -909,7 +898,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) - if (after(hard_ack, call->acks_hard_ack)) { - if (rxrpc_rotate_tx_window(call, hard_ack, &summary)) { - rxrpc_end_tx_phase(call, false, rxrpc_eproto_unexpected_ack); -- return; -+ goto send_response; - } - } - -@@ -927,6 +916,14 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) - rxrpc_propose_ack_ping_for_lost_reply); - - rxrpc_congestion_management(call, skb, &summary, acked_serial); -+ -+send_response: -+ if (ack.reason == RXRPC_ACK_PING) -+ rxrpc_send_ACK(call, RXRPC_ACK_PING_RESPONSE, ack_serial, -+ rxrpc_propose_ack_respond_to_ping); -+ else if (sp->hdr.flags & RXRPC_REQUEST_ACK) -+ rxrpc_send_ACK(call, RXRPC_ACK_REQUESTED, ack_serial, -+ rxrpc_propose_ack_respond_to_ack); - } - - /* -diff --git a/net/sctp/diag.c b/net/sctp/diag.c -index c3d6b92dd38..eb05131ff1d 100644 ---- a/net/sctp/diag.c -+++ b/net/sctp/diag.c -@@ -527,4 +527,5 @@ static void __exit sctp_diag_exit(void) - module_init(sctp_diag_init); - module_exit(sctp_diag_exit); - MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("SCTP socket monitoring via SOCK_DIAG"); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-132); -diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c -index da97f946b79..2a138884195 100644 ---- a/net/smc/af_smc.c -+++ b/net/smc/af_smc.c -@@ -598,8 +598,12 @@ static int smcr_clnt_conf_first_link(struct smc_sock *smc) - struct smc_llc_qentry *qentry; - int rc; - -- /* receive CONFIRM LINK request from server over RoCE fabric */ -- qentry = smc_llc_wait(link->lgr, NULL, SMC_LLC_WAIT_TIME, -+ /* Receive CONFIRM LINK request from server over RoCE fabric. -+ * Increasing the client's timeout by twice as much as the server's -+ * timeout by default can temporarily avoid decline messages of -+ * both sides crossing or colliding -+ */ -+ qentry = smc_llc_wait(link->lgr, NULL, 2 * SMC_LLC_WAIT_TIME, - SMC_LLC_CONFIRM_LINK); - if (!qentry) { - struct smc_clc_msg_decline dclc; -diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c -index 7ff2152971a..a584613aca1 100644 ---- a/net/smc/smc_diag.c -+++ b/net/smc/smc_diag.c -@@ -268,5 +268,6 @@ static void __exit smc_diag_exit(void) - module_init(smc_diag_init); - module_exit(smc_diag_exit); - MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("SMC socket monitoring via SOCK_DIAG"); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 43 /* AF_SMC */); - MODULE_ALIAS_GENL_FAMILY(SMCR_GENL_FAMILY_NAME); -diff --git a/net/tipc/diag.c b/net/tipc/diag.c -index 73137f4aeb6..18733451c9e 100644 ---- a/net/tipc/diag.c -+++ b/net/tipc/diag.c -@@ -113,4 +113,5 @@ module_init(tipc_diag_init); - module_exit(tipc_diag_exit); - - MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_DESCRIPTION("TIPC socket monitoring via SOCK_DIAG"); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, AF_TIPC); -diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c -index a78e8e72240..316f7618796 100644 ---- a/net/tls/tls_sw.c -+++ b/net/tls/tls_sw.c -@@ -1232,11 +1232,14 @@ void tls_sw_splice_eof(struct socket *sock) - lock_sock(sk); - - retry: -+ /* same checks as in tls_sw_push_pending_record() */ - rec = ctx->open_rec; - if (!rec) - goto unlock; - - msg_pl = &rec->msg_plaintext; -+ if (msg_pl->sg.size == 0) -+ goto unlock; - - /* Check the BPF advisor and perform transmission. */ - ret = bpf_exec_tx_verdict(msg_pl, sk, false, TLS_RECORD_TYPE_DATA, -diff --git a/net/unix/diag.c b/net/unix/diag.c -index 616b55c5b89..bec09a3a1d4 100644 ---- a/net/unix/diag.c -+++ b/net/unix/diag.c -@@ -339,4 +339,5 @@ static void __exit unix_diag_exit(void) - module_init(unix_diag_init); - module_exit(unix_diag_exit); - MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("UNIX socket monitoring via SOCK_DIAG"); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 1 /* AF_LOCAL */); -diff --git a/net/vmw_vsock/diag.c b/net/vmw_vsock/diag.c -index a2823b1c5e2..2e29994f92f 100644 ---- a/net/vmw_vsock/diag.c -+++ b/net/vmw_vsock/diag.c -@@ -174,5 +174,6 @@ static void __exit vsock_diag_exit(void) - module_init(vsock_diag_init); - module_exit(vsock_diag_exit); - MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("VMware Virtual Sockets monitoring via SOCK_DIAG"); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, - 40 /* AF_VSOCK */); -diff --git a/net/xdp/xsk_diag.c b/net/xdp/xsk_diag.c -index 22b36c8143c..9f895536727 100644 ---- a/net/xdp/xsk_diag.c -+++ b/net/xdp/xsk_diag.c -@@ -211,4 +211,5 @@ static void __exit xsk_diag_exit(void) - module_init(xsk_diag_init); - module_exit(xsk_diag_exit); - MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("XDP socket monitoring via SOCK_DIAG"); - MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, AF_XDP); -diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl -index 84f5fb7f1ce..d83ba5d8f3f 100755 ---- a/scripts/checkstack.pl -+++ b/scripts/checkstack.pl -@@ -97,8 +97,7 @@ my (@stack, $re, $dre, $sub, $x, $xs, $funcre, $min_stack); - # 11160: a7 fb ff 60 aghi %r15,-160 - # or - # 100092: e3 f0 ff c8 ff 71 lay %r15,-56(%r15) -- $re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2}) -- (?:\(\%r15\))?$/ox; -+ $re = qr/.*(?:lay|ag?hi).*\%r15,-([0-9]+)(?:\(\%r15\))?$/o; - } elsif ($arch eq 'sparc' || $arch eq 'sparc64') { - # f0019d10: 9d e3 bf 90 save %sp, -112, %sp - $re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3429419ca69..fe4dd313198 100644 --- a/sound/soc/codecs/Kconfig @@ -65606,1572 +57344,3 @@ index 252a0f0819b..09c0b445da6 100644 break; -diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h -index 87245c58478..8d94739d75c 100644 ---- a/tools/arch/parisc/include/uapi/asm/errno.h -+++ b/tools/arch/parisc/include/uapi/asm/errno.h -@@ -75,7 +75,6 @@ - - /* We now return you to your regularly scheduled HPUX. */ - --#define ENOSYM 215 /* symbol does not exist in executable */ - #define ENOTSOCK 216 /* Socket operation on non-socket */ - #define EDESTADDRREQ 217 /* Destination address required */ - #define EMSGSIZE 218 /* Message too long */ -@@ -101,7 +100,6 @@ - #define ETIMEDOUT 238 /* Connection timed out */ - #define ECONNREFUSED 239 /* Connection refused */ - #define EREFUSED ECONNREFUSED /* for HP's NFS apparently */ --#define EREMOTERELEASE 240 /* Remote peer released connection */ - #define EHOSTDOWN 241 /* Host is down */ - #define EHOSTUNREACH 242 /* No route to host */ - -diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c -index 264eeb9c46a..318e2dad27e 100644 ---- a/tools/hv/hv_kvp_daemon.c -+++ b/tools/hv/hv_kvp_daemon.c -@@ -1421,7 +1421,7 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) - if (error) - goto setval_error; - -- if (new_val->addr_family == ADDR_FAMILY_IPV6) { -+ if (new_val->addr_family & ADDR_FAMILY_IPV6) { - error = fprintf(nmfile, "\n[ipv6]\n"); - if (error < 0) - goto setval_error; -@@ -1455,14 +1455,18 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) - if (error < 0) - goto setval_error; - -- error = fprintf(nmfile, "gateway=%s\n", (char *)new_val->gate_way); -- if (error < 0) -- goto setval_error; -- -- error = fprintf(nmfile, "dns=%s\n", (char *)new_val->dns_addr); -- if (error < 0) -- goto setval_error; -+ /* we do not want ipv4 addresses in ipv6 section and vice versa */ -+ if (is_ipv6 != is_ipv4((char *)new_val->gate_way)) { -+ error = fprintf(nmfile, "gateway=%s\n", (char *)new_val->gate_way); -+ if (error < 0) -+ goto setval_error; -+ } - -+ if (is_ipv6 != is_ipv4((char *)new_val->dns_addr)) { -+ error = fprintf(nmfile, "dns=%s\n", (char *)new_val->dns_addr); -+ if (error < 0) -+ goto setval_error; -+ } - fclose(nmfile); - fclose(ifcfg_file); - -diff --git a/tools/hv/hv_set_ifconfig.sh b/tools/hv/hv_set_ifconfig.sh -index ae5a7a8249a..440a91b3582 100755 ---- a/tools/hv/hv_set_ifconfig.sh -+++ b/tools/hv/hv_set_ifconfig.sh -@@ -53,7 +53,7 @@ - # or "manual" if no boot-time protocol should be used) - # - # address1=ipaddr1/plen --# address=ipaddr2/plen -+# address2=ipaddr2/plen - # - # gateway=gateway1;gateway2 - # -@@ -61,7 +61,7 @@ - # - # [ipv6] - # address1=ipaddr1/plen --# address2=ipaddr1/plen -+# address2=ipaddr2/plen - # - # gateway=gateway1;gateway2 - # -diff --git a/tools/net/ynl/Makefile.deps b/tools/net/ynl/Makefile.deps -index 64d139400db..3110f84dd02 100644 ---- a/tools/net/ynl/Makefile.deps -+++ b/tools/net/ynl/Makefile.deps -@@ -18,4 +18,4 @@ CFLAGS_devlink:=$(call get_hdr_inc,_LINUX_DEVLINK_H_,devlink.h) - CFLAGS_ethtool:=$(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h) - CFLAGS_handshake:=$(call get_hdr_inc,_LINUX_HANDSHAKE_H,handshake.h) - CFLAGS_netdev:=$(call get_hdr_inc,_LINUX_NETDEV_H,netdev.h) --CFLAGS_nfsd:=$(call get_hdr_inc,_LINUX_NFSD_H,nfsd.h) -+CFLAGS_nfsd:=$(call get_hdr_inc,_LINUX_NFSD_NETLINK_H,nfsd_netlink.h) -diff --git a/tools/net/ynl/generated/devlink-user.c b/tools/net/ynl/generated/devlink-user.c -index bc5065bd99b..c12ca87ca2b 100644 ---- a/tools/net/ynl/generated/devlink-user.c -+++ b/tools/net/ynl/generated/devlink-user.c -@@ -15,7 +15,7 @@ - /* Enums */ - static const char * const devlink_op_strmap[] = { - [3] = "get", -- [7] = "port-get", -+ // skip "port-get", duplicate reply value - [DEVLINK_CMD_PORT_NEW] = "port-new", - [13] = "sb-get", - [17] = "sb-pool-get", -diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py -index c4003a83cd5..3bd6b928c14 100755 ---- a/tools/net/ynl/ynl-gen-c.py -+++ b/tools/net/ynl/ynl-gen-c.py -@@ -1505,6 +1505,12 @@ def put_op_name(family, cw): - cw.block_start(line=f"static const char * const {map_name}[] =") - for op_name, op in family.msgs.items(): - if op.rsp_value: -+ # Make sure we don't add duplicated entries, if multiple commands -+ # produce the same response in legacy families. -+ if family.rsp_by_value[op.rsp_value] != op: -+ cw.p(f'// skip "{op_name}", duplicate reply value') -+ continue -+ - if op.req_value == op.rsp_value: - cw.p(f'[{op.enum_name}] = "{op_name}",') - else: -diff --git a/tools/power/pm-graph/sleepgraph.py b/tools/power/pm-graph/sleepgraph.py -index 4a356a70678..40ad221e888 100755 ---- a/tools/power/pm-graph/sleepgraph.py -+++ b/tools/power/pm-graph/sleepgraph.py -@@ -4151,7 +4151,7 @@ def parseKernelLog(data): - elif(re.match('Enabling non-boot CPUs .*', msg)): - # start of first cpu resume - cpu_start = ktime -- elif(re.match('smpboot: CPU (?P[0-9]*) is now offline', msg)) \ -+ elif(re.match('smpboot: CPU (?P[0-9]*) is now offline', msg) \ - or re.match('psci: CPU(?P[0-9]*) killed.*', msg)): - # end of a cpu suspend, start of the next - m = re.match('smpboot: CPU (?P[0-9]*) is now offline', msg) -diff --git a/tools/testing/selftests/arm64/fp/za-fork.c b/tools/testing/selftests/arm64/fp/za-fork.c -index b86cb104949..587b9464822 100644 ---- a/tools/testing/selftests/arm64/fp/za-fork.c -+++ b/tools/testing/selftests/arm64/fp/za-fork.c -@@ -85,7 +85,7 @@ int main(int argc, char **argv) - */ - ret = open("/proc/sys/abi/sme_default_vector_length", O_RDONLY, 0); - if (ret >= 0) { -- ksft_test_result(fork_test(), "fork_test"); -+ ksft_test_result(fork_test(), "fork_test\n"); - - } else { - ksft_print_msg("SME not supported\n"); -diff --git a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c -index 6ee22c3b251..518f143c5b0 100644 ---- a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c -+++ b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c -@@ -24,6 +24,7 @@ - - #include "test_progs.h" - #include "network_helpers.h" -+#include "netlink_helpers.h" - #include "test_tc_neigh_fib.skel.h" - #include "test_tc_neigh.skel.h" - #include "test_tc_peer.skel.h" -@@ -110,11 +111,17 @@ static void netns_setup_namespaces_nofail(const char *verb) - } - } - -+enum dev_mode { -+ MODE_VETH, -+ MODE_NETKIT, -+}; -+ - struct netns_setup_result { -- int ifindex_veth_src; -- int ifindex_veth_src_fwd; -- int ifindex_veth_dst; -- int ifindex_veth_dst_fwd; -+ enum dev_mode dev_mode; -+ int ifindex_src; -+ int ifindex_src_fwd; -+ int ifindex_dst; -+ int ifindex_dst_fwd; - }; - - static int get_ifaddr(const char *name, char *ifaddr) -@@ -137,58 +144,110 @@ static int get_ifaddr(const char *name, char *ifaddr) - return 0; - } - -+static int create_netkit(int mode, char *prim, char *peer) -+{ -+ struct rtattr *linkinfo, *data, *peer_info; -+ struct rtnl_handle rth = { .fd = -1 }; -+ const char *type = "netkit"; -+ struct { -+ struct nlmsghdr n; -+ struct ifinfomsg i; -+ char buf[1024]; -+ } req = {}; -+ int err; -+ -+ err = rtnl_open(&rth, 0); -+ if (!ASSERT_OK(err, "open_rtnetlink")) -+ return err; -+ -+ memset(&req, 0, sizeof(req)); -+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); -+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; -+ req.n.nlmsg_type = RTM_NEWLINK; -+ req.i.ifi_family = AF_UNSPEC; -+ -+ addattr_l(&req.n, sizeof(req), IFLA_IFNAME, prim, strlen(prim)); -+ linkinfo = addattr_nest(&req.n, sizeof(req), IFLA_LINKINFO); -+ addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type, strlen(type)); -+ data = addattr_nest(&req.n, sizeof(req), IFLA_INFO_DATA); -+ addattr32(&req.n, sizeof(req), IFLA_NETKIT_MODE, mode); -+ peer_info = addattr_nest(&req.n, sizeof(req), IFLA_NETKIT_PEER_INFO); -+ req.n.nlmsg_len += sizeof(struct ifinfomsg); -+ addattr_l(&req.n, sizeof(req), IFLA_IFNAME, peer, strlen(peer)); -+ addattr_nest_end(&req.n, peer_info); -+ addattr_nest_end(&req.n, data); -+ addattr_nest_end(&req.n, linkinfo); -+ -+ err = rtnl_talk(&rth, &req.n, NULL); -+ ASSERT_OK(err, "talk_rtnetlink"); -+ rtnl_close(&rth); -+ return err; -+} -+ - static int netns_setup_links_and_routes(struct netns_setup_result *result) - { - struct nstoken *nstoken = NULL; -- char veth_src_fwd_addr[IFADDR_STR_LEN+1] = {}; -- -- SYS(fail, "ip link add veth_src type veth peer name veth_src_fwd"); -- SYS(fail, "ip link add veth_dst type veth peer name veth_dst_fwd"); -+ char src_fwd_addr[IFADDR_STR_LEN+1] = {}; -+ int err; - -- SYS(fail, "ip link set veth_dst_fwd address " MAC_DST_FWD); -- SYS(fail, "ip link set veth_dst address " MAC_DST); -+ if (result->dev_mode == MODE_VETH) { -+ SYS(fail, "ip link add src type veth peer name src_fwd"); -+ SYS(fail, "ip link add dst type veth peer name dst_fwd"); -+ -+ SYS(fail, "ip link set dst_fwd address " MAC_DST_FWD); -+ SYS(fail, "ip link set dst address " MAC_DST); -+ } else if (result->dev_mode == MODE_NETKIT) { -+ err = create_netkit(NETKIT_L3, "src", "src_fwd"); -+ if (!ASSERT_OK(err, "create_ifindex_src")) -+ goto fail; -+ err = create_netkit(NETKIT_L3, "dst", "dst_fwd"); -+ if (!ASSERT_OK(err, "create_ifindex_dst")) -+ goto fail; -+ } - -- if (get_ifaddr("veth_src_fwd", veth_src_fwd_addr)) -+ if (get_ifaddr("src_fwd", src_fwd_addr)) - goto fail; - -- result->ifindex_veth_src = if_nametoindex("veth_src"); -- if (!ASSERT_GT(result->ifindex_veth_src, 0, "ifindex_veth_src")) -+ result->ifindex_src = if_nametoindex("src"); -+ if (!ASSERT_GT(result->ifindex_src, 0, "ifindex_src")) - goto fail; - -- result->ifindex_veth_src_fwd = if_nametoindex("veth_src_fwd"); -- if (!ASSERT_GT(result->ifindex_veth_src_fwd, 0, "ifindex_veth_src_fwd")) -+ result->ifindex_src_fwd = if_nametoindex("src_fwd"); -+ if (!ASSERT_GT(result->ifindex_src_fwd, 0, "ifindex_src_fwd")) - goto fail; - -- result->ifindex_veth_dst = if_nametoindex("veth_dst"); -- if (!ASSERT_GT(result->ifindex_veth_dst, 0, "ifindex_veth_dst")) -+ result->ifindex_dst = if_nametoindex("dst"); -+ if (!ASSERT_GT(result->ifindex_dst, 0, "ifindex_dst")) - goto fail; - -- result->ifindex_veth_dst_fwd = if_nametoindex("veth_dst_fwd"); -- if (!ASSERT_GT(result->ifindex_veth_dst_fwd, 0, "ifindex_veth_dst_fwd")) -+ result->ifindex_dst_fwd = if_nametoindex("dst_fwd"); -+ if (!ASSERT_GT(result->ifindex_dst_fwd, 0, "ifindex_dst_fwd")) - goto fail; - -- SYS(fail, "ip link set veth_src netns " NS_SRC); -- SYS(fail, "ip link set veth_src_fwd netns " NS_FWD); -- SYS(fail, "ip link set veth_dst_fwd netns " NS_FWD); -- SYS(fail, "ip link set veth_dst netns " NS_DST); -+ SYS(fail, "ip link set src netns " NS_SRC); -+ SYS(fail, "ip link set src_fwd netns " NS_FWD); -+ SYS(fail, "ip link set dst_fwd netns " NS_FWD); -+ SYS(fail, "ip link set dst netns " NS_DST); - - /** setup in 'src' namespace */ - nstoken = open_netns(NS_SRC); - if (!ASSERT_OK_PTR(nstoken, "setns src")) - goto fail; - -- SYS(fail, "ip addr add " IP4_SRC "/32 dev veth_src"); -- SYS(fail, "ip addr add " IP6_SRC "/128 dev veth_src nodad"); -- SYS(fail, "ip link set dev veth_src up"); -+ SYS(fail, "ip addr add " IP4_SRC "/32 dev src"); -+ SYS(fail, "ip addr add " IP6_SRC "/128 dev src nodad"); -+ SYS(fail, "ip link set dev src up"); - -- SYS(fail, "ip route add " IP4_DST "/32 dev veth_src scope global"); -- SYS(fail, "ip route add " IP4_NET "/16 dev veth_src scope global"); -- SYS(fail, "ip route add " IP6_DST "/128 dev veth_src scope global"); -+ SYS(fail, "ip route add " IP4_DST "/32 dev src scope global"); -+ SYS(fail, "ip route add " IP4_NET "/16 dev src scope global"); -+ SYS(fail, "ip route add " IP6_DST "/128 dev src scope global"); - -- SYS(fail, "ip neigh add " IP4_DST " dev veth_src lladdr %s", -- veth_src_fwd_addr); -- SYS(fail, "ip neigh add " IP6_DST " dev veth_src lladdr %s", -- veth_src_fwd_addr); -+ if (result->dev_mode == MODE_VETH) { -+ SYS(fail, "ip neigh add " IP4_DST " dev src lladdr %s", -+ src_fwd_addr); -+ SYS(fail, "ip neigh add " IP6_DST " dev src lladdr %s", -+ src_fwd_addr); -+ } - - close_netns(nstoken); - -@@ -201,15 +260,15 @@ static int netns_setup_links_and_routes(struct netns_setup_result *result) - * needs v4 one in order to start ARP probing. IP4_NET route is added - * to the endpoints so that the ARP processing will reply. - */ -- SYS(fail, "ip addr add " IP4_SLL "/32 dev veth_src_fwd"); -- SYS(fail, "ip addr add " IP4_DLL "/32 dev veth_dst_fwd"); -- SYS(fail, "ip link set dev veth_src_fwd up"); -- SYS(fail, "ip link set dev veth_dst_fwd up"); -+ SYS(fail, "ip addr add " IP4_SLL "/32 dev src_fwd"); -+ SYS(fail, "ip addr add " IP4_DLL "/32 dev dst_fwd"); -+ SYS(fail, "ip link set dev src_fwd up"); -+ SYS(fail, "ip link set dev dst_fwd up"); - -- SYS(fail, "ip route add " IP4_SRC "/32 dev veth_src_fwd scope global"); -- SYS(fail, "ip route add " IP6_SRC "/128 dev veth_src_fwd scope global"); -- SYS(fail, "ip route add " IP4_DST "/32 dev veth_dst_fwd scope global"); -- SYS(fail, "ip route add " IP6_DST "/128 dev veth_dst_fwd scope global"); -+ SYS(fail, "ip route add " IP4_SRC "/32 dev src_fwd scope global"); -+ SYS(fail, "ip route add " IP6_SRC "/128 dev src_fwd scope global"); -+ SYS(fail, "ip route add " IP4_DST "/32 dev dst_fwd scope global"); -+ SYS(fail, "ip route add " IP6_DST "/128 dev dst_fwd scope global"); - - close_netns(nstoken); - -@@ -218,16 +277,18 @@ static int netns_setup_links_and_routes(struct netns_setup_result *result) - if (!ASSERT_OK_PTR(nstoken, "setns dst")) - goto fail; - -- SYS(fail, "ip addr add " IP4_DST "/32 dev veth_dst"); -- SYS(fail, "ip addr add " IP6_DST "/128 dev veth_dst nodad"); -- SYS(fail, "ip link set dev veth_dst up"); -+ SYS(fail, "ip addr add " IP4_DST "/32 dev dst"); -+ SYS(fail, "ip addr add " IP6_DST "/128 dev dst nodad"); -+ SYS(fail, "ip link set dev dst up"); - -- SYS(fail, "ip route add " IP4_SRC "/32 dev veth_dst scope global"); -- SYS(fail, "ip route add " IP4_NET "/16 dev veth_dst scope global"); -- SYS(fail, "ip route add " IP6_SRC "/128 dev veth_dst scope global"); -+ SYS(fail, "ip route add " IP4_SRC "/32 dev dst scope global"); -+ SYS(fail, "ip route add " IP4_NET "/16 dev dst scope global"); -+ SYS(fail, "ip route add " IP6_SRC "/128 dev dst scope global"); - -- SYS(fail, "ip neigh add " IP4_SRC " dev veth_dst lladdr " MAC_DST_FWD); -- SYS(fail, "ip neigh add " IP6_SRC " dev veth_dst lladdr " MAC_DST_FWD); -+ if (result->dev_mode == MODE_VETH) { -+ SYS(fail, "ip neigh add " IP4_SRC " dev dst lladdr " MAC_DST_FWD); -+ SYS(fail, "ip neigh add " IP6_SRC " dev dst lladdr " MAC_DST_FWD); -+ } - - close_netns(nstoken); - -@@ -293,23 +354,23 @@ static int netns_load_bpf(const struct bpf_program *src_prog, - const struct bpf_program *chk_prog, - const struct netns_setup_result *setup_result) - { -- LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_src_fwd); -- LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_dst_fwd); -+ LIBBPF_OPTS(bpf_tc_hook, qdisc_src_fwd); -+ LIBBPF_OPTS(bpf_tc_hook, qdisc_dst_fwd); - int err; - -- /* tc qdisc add dev veth_src_fwd clsact */ -- QDISC_CLSACT_CREATE(&qdisc_veth_src_fwd, setup_result->ifindex_veth_src_fwd); -- /* tc filter add dev veth_src_fwd ingress bpf da src_prog */ -- XGRESS_FILTER_ADD(&qdisc_veth_src_fwd, BPF_TC_INGRESS, src_prog, 0); -- /* tc filter add dev veth_src_fwd egress bpf da chk_prog */ -- XGRESS_FILTER_ADD(&qdisc_veth_src_fwd, BPF_TC_EGRESS, chk_prog, 0); -+ /* tc qdisc add dev src_fwd clsact */ -+ QDISC_CLSACT_CREATE(&qdisc_src_fwd, setup_result->ifindex_src_fwd); -+ /* tc filter add dev src_fwd ingress bpf da src_prog */ -+ XGRESS_FILTER_ADD(&qdisc_src_fwd, BPF_TC_INGRESS, src_prog, 0); -+ /* tc filter add dev src_fwd egress bpf da chk_prog */ -+ XGRESS_FILTER_ADD(&qdisc_src_fwd, BPF_TC_EGRESS, chk_prog, 0); - -- /* tc qdisc add dev veth_dst_fwd clsact */ -- QDISC_CLSACT_CREATE(&qdisc_veth_dst_fwd, setup_result->ifindex_veth_dst_fwd); -- /* tc filter add dev veth_dst_fwd ingress bpf da dst_prog */ -- XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_INGRESS, dst_prog, 0); -- /* tc filter add dev veth_dst_fwd egress bpf da chk_prog */ -- XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_EGRESS, chk_prog, 0); -+ /* tc qdisc add dev dst_fwd clsact */ -+ QDISC_CLSACT_CREATE(&qdisc_dst_fwd, setup_result->ifindex_dst_fwd); -+ /* tc filter add dev dst_fwd ingress bpf da dst_prog */ -+ XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_INGRESS, dst_prog, 0); -+ /* tc filter add dev dst_fwd egress bpf da chk_prog */ -+ XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_EGRESS, chk_prog, 0); - - return 0; - fail: -@@ -539,10 +600,10 @@ static void test_inet_dtime(int family, int type, const char *addr, __u16 port) - static int netns_load_dtime_bpf(struct test_tc_dtime *skel, - const struct netns_setup_result *setup_result) - { -- LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_src_fwd); -- LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_dst_fwd); -- LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_src); -- LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_dst); -+ LIBBPF_OPTS(bpf_tc_hook, qdisc_src_fwd); -+ LIBBPF_OPTS(bpf_tc_hook, qdisc_dst_fwd); -+ LIBBPF_OPTS(bpf_tc_hook, qdisc_src); -+ LIBBPF_OPTS(bpf_tc_hook, qdisc_dst); - struct nstoken *nstoken; - int err; - -@@ -550,58 +611,58 @@ static int netns_load_dtime_bpf(struct test_tc_dtime *skel, - nstoken = open_netns(NS_SRC); - if (!ASSERT_OK_PTR(nstoken, "setns " NS_SRC)) - return -1; -- /* tc qdisc add dev veth_src clsact */ -- QDISC_CLSACT_CREATE(&qdisc_veth_src, setup_result->ifindex_veth_src); -- /* tc filter add dev veth_src ingress bpf da ingress_host */ -- XGRESS_FILTER_ADD(&qdisc_veth_src, BPF_TC_INGRESS, skel->progs.ingress_host, 0); -- /* tc filter add dev veth_src egress bpf da egress_host */ -- XGRESS_FILTER_ADD(&qdisc_veth_src, BPF_TC_EGRESS, skel->progs.egress_host, 0); -+ /* tc qdisc add dev src clsact */ -+ QDISC_CLSACT_CREATE(&qdisc_src, setup_result->ifindex_src); -+ /* tc filter add dev src ingress bpf da ingress_host */ -+ XGRESS_FILTER_ADD(&qdisc_src, BPF_TC_INGRESS, skel->progs.ingress_host, 0); -+ /* tc filter add dev src egress bpf da egress_host */ -+ XGRESS_FILTER_ADD(&qdisc_src, BPF_TC_EGRESS, skel->progs.egress_host, 0); - close_netns(nstoken); - - /* setup ns_dst tc progs */ - nstoken = open_netns(NS_DST); - if (!ASSERT_OK_PTR(nstoken, "setns " NS_DST)) - return -1; -- /* tc qdisc add dev veth_dst clsact */ -- QDISC_CLSACT_CREATE(&qdisc_veth_dst, setup_result->ifindex_veth_dst); -- /* tc filter add dev veth_dst ingress bpf da ingress_host */ -- XGRESS_FILTER_ADD(&qdisc_veth_dst, BPF_TC_INGRESS, skel->progs.ingress_host, 0); -- /* tc filter add dev veth_dst egress bpf da egress_host */ -- XGRESS_FILTER_ADD(&qdisc_veth_dst, BPF_TC_EGRESS, skel->progs.egress_host, 0); -+ /* tc qdisc add dev dst clsact */ -+ QDISC_CLSACT_CREATE(&qdisc_dst, setup_result->ifindex_dst); -+ /* tc filter add dev dst ingress bpf da ingress_host */ -+ XGRESS_FILTER_ADD(&qdisc_dst, BPF_TC_INGRESS, skel->progs.ingress_host, 0); -+ /* tc filter add dev dst egress bpf da egress_host */ -+ XGRESS_FILTER_ADD(&qdisc_dst, BPF_TC_EGRESS, skel->progs.egress_host, 0); - close_netns(nstoken); - - /* setup ns_fwd tc progs */ - nstoken = open_netns(NS_FWD); - if (!ASSERT_OK_PTR(nstoken, "setns " NS_FWD)) - return -1; -- /* tc qdisc add dev veth_dst_fwd clsact */ -- QDISC_CLSACT_CREATE(&qdisc_veth_dst_fwd, setup_result->ifindex_veth_dst_fwd); -- /* tc filter add dev veth_dst_fwd ingress prio 100 bpf da ingress_fwdns_prio100 */ -- XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_INGRESS, -+ /* tc qdisc add dev dst_fwd clsact */ -+ QDISC_CLSACT_CREATE(&qdisc_dst_fwd, setup_result->ifindex_dst_fwd); -+ /* tc filter add dev dst_fwd ingress prio 100 bpf da ingress_fwdns_prio100 */ -+ XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_INGRESS, - skel->progs.ingress_fwdns_prio100, 100); -- /* tc filter add dev veth_dst_fwd ingress prio 101 bpf da ingress_fwdns_prio101 */ -- XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_INGRESS, -+ /* tc filter add dev dst_fwd ingress prio 101 bpf da ingress_fwdns_prio101 */ -+ XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_INGRESS, - skel->progs.ingress_fwdns_prio101, 101); -- /* tc filter add dev veth_dst_fwd egress prio 100 bpf da egress_fwdns_prio100 */ -- XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_EGRESS, -+ /* tc filter add dev dst_fwd egress prio 100 bpf da egress_fwdns_prio100 */ -+ XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_EGRESS, - skel->progs.egress_fwdns_prio100, 100); -- /* tc filter add dev veth_dst_fwd egress prio 101 bpf da egress_fwdns_prio101 */ -- XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_EGRESS, -+ /* tc filter add dev dst_fwd egress prio 101 bpf da egress_fwdns_prio101 */ -+ XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_EGRESS, - skel->progs.egress_fwdns_prio101, 101); - -- /* tc qdisc add dev veth_src_fwd clsact */ -- QDISC_CLSACT_CREATE(&qdisc_veth_src_fwd, setup_result->ifindex_veth_src_fwd); -- /* tc filter add dev veth_src_fwd ingress prio 100 bpf da ingress_fwdns_prio100 */ -- XGRESS_FILTER_ADD(&qdisc_veth_src_fwd, BPF_TC_INGRESS, -+ /* tc qdisc add dev src_fwd clsact */ -+ QDISC_CLSACT_CREATE(&qdisc_src_fwd, setup_result->ifindex_src_fwd); -+ /* tc filter add dev src_fwd ingress prio 100 bpf da ingress_fwdns_prio100 */ -+ XGRESS_FILTER_ADD(&qdisc_src_fwd, BPF_TC_INGRESS, - skel->progs.ingress_fwdns_prio100, 100); -- /* tc filter add dev veth_src_fwd ingress prio 101 bpf da ingress_fwdns_prio101 */ -- XGRESS_FILTER_ADD(&qdisc_veth_src_fwd, BPF_TC_INGRESS, -+ /* tc filter add dev src_fwd ingress prio 101 bpf da ingress_fwdns_prio101 */ -+ XGRESS_FILTER_ADD(&qdisc_src_fwd, BPF_TC_INGRESS, - skel->progs.ingress_fwdns_prio101, 101); -- /* tc filter add dev veth_src_fwd egress prio 100 bpf da egress_fwdns_prio100 */ -- XGRESS_FILTER_ADD(&qdisc_veth_src_fwd, BPF_TC_EGRESS, -+ /* tc filter add dev src_fwd egress prio 100 bpf da egress_fwdns_prio100 */ -+ XGRESS_FILTER_ADD(&qdisc_src_fwd, BPF_TC_EGRESS, - skel->progs.egress_fwdns_prio100, 100); -- /* tc filter add dev veth_src_fwd egress prio 101 bpf da egress_fwdns_prio101 */ -- XGRESS_FILTER_ADD(&qdisc_veth_src_fwd, BPF_TC_EGRESS, -+ /* tc filter add dev src_fwd egress prio 101 bpf da egress_fwdns_prio101 */ -+ XGRESS_FILTER_ADD(&qdisc_src_fwd, BPF_TC_EGRESS, - skel->progs.egress_fwdns_prio101, 101); - close_netns(nstoken); - return 0; -@@ -777,8 +838,8 @@ static void test_tc_redirect_dtime(struct netns_setup_result *setup_result) - if (!ASSERT_OK_PTR(skel, "test_tc_dtime__open")) - return; - -- skel->rodata->IFINDEX_SRC = setup_result->ifindex_veth_src_fwd; -- skel->rodata->IFINDEX_DST = setup_result->ifindex_veth_dst_fwd; -+ skel->rodata->IFINDEX_SRC = setup_result->ifindex_src_fwd; -+ skel->rodata->IFINDEX_DST = setup_result->ifindex_dst_fwd; - - err = test_tc_dtime__load(skel); - if (!ASSERT_OK(err, "test_tc_dtime__load")) -@@ -868,8 +929,8 @@ static void test_tc_redirect_neigh(struct netns_setup_result *setup_result) - if (!ASSERT_OK_PTR(skel, "test_tc_neigh__open")) - goto done; - -- skel->rodata->IFINDEX_SRC = setup_result->ifindex_veth_src_fwd; -- skel->rodata->IFINDEX_DST = setup_result->ifindex_veth_dst_fwd; -+ skel->rodata->IFINDEX_SRC = setup_result->ifindex_src_fwd; -+ skel->rodata->IFINDEX_DST = setup_result->ifindex_dst_fwd; - - err = test_tc_neigh__load(skel); - if (!ASSERT_OK(err, "test_tc_neigh__load")) -@@ -904,8 +965,8 @@ static void test_tc_redirect_peer(struct netns_setup_result *setup_result) - if (!ASSERT_OK_PTR(skel, "test_tc_peer__open")) - goto done; - -- skel->rodata->IFINDEX_SRC = setup_result->ifindex_veth_src_fwd; -- skel->rodata->IFINDEX_DST = setup_result->ifindex_veth_dst_fwd; -+ skel->rodata->IFINDEX_SRC = setup_result->ifindex_src_fwd; -+ skel->rodata->IFINDEX_DST = setup_result->ifindex_dst_fwd; - - err = test_tc_peer__load(skel); - if (!ASSERT_OK(err, "test_tc_peer__load")) -@@ -996,7 +1057,7 @@ static int tun_relay_loop(int src_fd, int target_fd) - static void test_tc_redirect_peer_l3(struct netns_setup_result *setup_result) - { - LIBBPF_OPTS(bpf_tc_hook, qdisc_tun_fwd); -- LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_dst_fwd); -+ LIBBPF_OPTS(bpf_tc_hook, qdisc_dst_fwd); - struct test_tc_peer *skel = NULL; - struct nstoken *nstoken = NULL; - int err; -@@ -1045,7 +1106,7 @@ static void test_tc_redirect_peer_l3(struct netns_setup_result *setup_result) - goto fail; - - skel->rodata->IFINDEX_SRC = ifindex; -- skel->rodata->IFINDEX_DST = setup_result->ifindex_veth_dst_fwd; -+ skel->rodata->IFINDEX_DST = setup_result->ifindex_dst_fwd; - - err = test_tc_peer__load(skel); - if (!ASSERT_OK(err, "test_tc_peer__load")) -@@ -1053,19 +1114,19 @@ static void test_tc_redirect_peer_l3(struct netns_setup_result *setup_result) - - /* Load "tc_src_l3" to the tun_fwd interface to redirect packets - * towards dst, and "tc_dst" to redirect packets -- * and "tc_chk" on veth_dst_fwd to drop non-redirected packets. -+ * and "tc_chk" on dst_fwd to drop non-redirected packets. - */ - /* tc qdisc add dev tun_fwd clsact */ - QDISC_CLSACT_CREATE(&qdisc_tun_fwd, ifindex); - /* tc filter add dev tun_fwd ingress bpf da tc_src_l3 */ - XGRESS_FILTER_ADD(&qdisc_tun_fwd, BPF_TC_INGRESS, skel->progs.tc_src_l3, 0); - -- /* tc qdisc add dev veth_dst_fwd clsact */ -- QDISC_CLSACT_CREATE(&qdisc_veth_dst_fwd, setup_result->ifindex_veth_dst_fwd); -- /* tc filter add dev veth_dst_fwd ingress bpf da tc_dst_l3 */ -- XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_INGRESS, skel->progs.tc_dst_l3, 0); -- /* tc filter add dev veth_dst_fwd egress bpf da tc_chk */ -- XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_EGRESS, skel->progs.tc_chk, 0); -+ /* tc qdisc add dev dst_fwd clsact */ -+ QDISC_CLSACT_CREATE(&qdisc_dst_fwd, setup_result->ifindex_dst_fwd); -+ /* tc filter add dev dst_fwd ingress bpf da tc_dst_l3 */ -+ XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_INGRESS, skel->progs.tc_dst_l3, 0); -+ /* tc filter add dev dst_fwd egress bpf da tc_chk */ -+ XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_EGRESS, skel->progs.tc_chk, 0); - - /* Setup route and neigh tables */ - SYS(fail, "ip -netns " NS_SRC " addr add dev tun_src " IP4_TUN_SRC "/24"); -@@ -1074,17 +1135,17 @@ static void test_tc_redirect_peer_l3(struct netns_setup_result *setup_result) - SYS(fail, "ip -netns " NS_SRC " addr add dev tun_src " IP6_TUN_SRC "/64 nodad"); - SYS(fail, "ip -netns " NS_FWD " addr add dev tun_fwd " IP6_TUN_FWD "/64 nodad"); - -- SYS(fail, "ip -netns " NS_SRC " route del " IP4_DST "/32 dev veth_src scope global"); -+ SYS(fail, "ip -netns " NS_SRC " route del " IP4_DST "/32 dev src scope global"); - SYS(fail, "ip -netns " NS_SRC " route add " IP4_DST "/32 via " IP4_TUN_FWD - " dev tun_src scope global"); -- SYS(fail, "ip -netns " NS_DST " route add " IP4_TUN_SRC "/32 dev veth_dst scope global"); -- SYS(fail, "ip -netns " NS_SRC " route del " IP6_DST "/128 dev veth_src scope global"); -+ SYS(fail, "ip -netns " NS_DST " route add " IP4_TUN_SRC "/32 dev dst scope global"); -+ SYS(fail, "ip -netns " NS_SRC " route del " IP6_DST "/128 dev src scope global"); - SYS(fail, "ip -netns " NS_SRC " route add " IP6_DST "/128 via " IP6_TUN_FWD - " dev tun_src scope global"); -- SYS(fail, "ip -netns " NS_DST " route add " IP6_TUN_SRC "/128 dev veth_dst scope global"); -+ SYS(fail, "ip -netns " NS_DST " route add " IP6_TUN_SRC "/128 dev dst scope global"); - -- SYS(fail, "ip -netns " NS_DST " neigh add " IP4_TUN_SRC " dev veth_dst lladdr " MAC_DST_FWD); -- SYS(fail, "ip -netns " NS_DST " neigh add " IP6_TUN_SRC " dev veth_dst lladdr " MAC_DST_FWD); -+ SYS(fail, "ip -netns " NS_DST " neigh add " IP4_TUN_SRC " dev dst lladdr " MAC_DST_FWD); -+ SYS(fail, "ip -netns " NS_DST " neigh add " IP6_TUN_SRC " dev dst lladdr " MAC_DST_FWD); - - if (!ASSERT_OK(set_forwarding(false), "disable forwarding")) - goto fail; -@@ -1106,9 +1167,9 @@ static void test_tc_redirect_peer_l3(struct netns_setup_result *setup_result) - close_netns(nstoken); - } - --#define RUN_TEST(name) \ -+#define RUN_TEST(name, mode) \ - ({ \ -- struct netns_setup_result setup_result; \ -+ struct netns_setup_result setup_result = { .dev_mode = mode, }; \ - if (test__start_subtest(#name)) \ - if (ASSERT_OK(netns_setup_namespaces("add"), "setup namespaces")) { \ - if (ASSERT_OK(netns_setup_links_and_routes(&setup_result), \ -@@ -1122,11 +1183,13 @@ static void *test_tc_redirect_run_tests(void *arg) - { - netns_setup_namespaces_nofail("delete"); - -- RUN_TEST(tc_redirect_peer); -- RUN_TEST(tc_redirect_peer_l3); -- RUN_TEST(tc_redirect_neigh); -- RUN_TEST(tc_redirect_neigh_fib); -- RUN_TEST(tc_redirect_dtime); -+ RUN_TEST(tc_redirect_peer, MODE_VETH); -+ RUN_TEST(tc_redirect_peer, MODE_NETKIT); -+ RUN_TEST(tc_redirect_peer_l3, MODE_VETH); -+ RUN_TEST(tc_redirect_peer_l3, MODE_NETKIT); -+ RUN_TEST(tc_redirect_neigh, MODE_VETH); -+ RUN_TEST(tc_redirect_neigh_fib, MODE_VETH); -+ RUN_TEST(tc_redirect_dtime, MODE_VETH); - return NULL; - } - -diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c -index e5c61aa6604..5cfa7a6316b 100644 ---- a/tools/testing/selftests/bpf/prog_tests/verifier.c -+++ b/tools/testing/selftests/bpf/prog_tests/verifier.c -@@ -31,6 +31,7 @@ - #include "verifier_helper_restricted.skel.h" - #include "verifier_helper_value_access.skel.h" - #include "verifier_int_ptr.skel.h" -+#include "verifier_iterating_callbacks.skel.h" - #include "verifier_jeq_infer_not_null.skel.h" - #include "verifier_ld_ind.skel.h" - #include "verifier_ldsx.skel.h" -@@ -139,6 +140,7 @@ void test_verifier_helper_packet_access(void) { RUN(verifier_helper_packet_acces - void test_verifier_helper_restricted(void) { RUN(verifier_helper_restricted); } - void test_verifier_helper_value_access(void) { RUN(verifier_helper_value_access); } - void test_verifier_int_ptr(void) { RUN(verifier_int_ptr); } -+void test_verifier_iterating_callbacks(void) { RUN(verifier_iterating_callbacks); } - void test_verifier_jeq_infer_not_null(void) { RUN(verifier_jeq_infer_not_null); } - void test_verifier_ld_ind(void) { RUN(verifier_ld_ind); } - void test_verifier_ldsx(void) { RUN(verifier_ldsx); } -diff --git a/tools/testing/selftests/bpf/progs/bpf_loop_bench.c b/tools/testing/selftests/bpf/progs/bpf_loop_bench.c -index 4ce76eb064c..d461746fd3c 100644 ---- a/tools/testing/selftests/bpf/progs/bpf_loop_bench.c -+++ b/tools/testing/selftests/bpf/progs/bpf_loop_bench.c -@@ -15,13 +15,16 @@ static int empty_callback(__u32 index, void *data) - return 0; - } - -+static int outer_loop(__u32 index, void *data) -+{ -+ bpf_loop(nr_loops, empty_callback, NULL, 0); -+ __sync_add_and_fetch(&hits, nr_loops); -+ return 0; -+} -+ - SEC("fentry/" SYS_PREFIX "sys_getpgid") - int benchmark(void *ctx) - { -- for (int i = 0; i < 1000; i++) { -- bpf_loop(nr_loops, empty_callback, NULL, 0); -- -- __sync_add_and_fetch(&hits, nr_loops); -- } -+ bpf_loop(1000, outer_loop, NULL, 0); - return 0; - } -diff --git a/tools/testing/selftests/bpf/progs/cb_refs.c b/tools/testing/selftests/bpf/progs/cb_refs.c -index 76d661b20e8..56c764df819 100644 ---- a/tools/testing/selftests/bpf/progs/cb_refs.c -+++ b/tools/testing/selftests/bpf/progs/cb_refs.c -@@ -33,6 +33,7 @@ int underflow_prog(void *ctx) - if (!p) - return 0; - bpf_for_each_map_elem(&array_map, cb1, &p, 0); -+ bpf_kfunc_call_test_release(p); - return 0; - } - -diff --git a/tools/testing/selftests/bpf/progs/exceptions_fail.c b/tools/testing/selftests/bpf/progs/exceptions_fail.c -index 4c39e920dac..8c0ef274220 100644 ---- a/tools/testing/selftests/bpf/progs/exceptions_fail.c -+++ b/tools/testing/selftests/bpf/progs/exceptions_fail.c -@@ -171,6 +171,7 @@ int reject_with_rbtree_add_throw(void *ctx) - return 0; - bpf_spin_lock(&lock); - bpf_rbtree_add(&rbtree, &f->node, rbless); -+ bpf_spin_unlock(&lock); - return 0; - } - -@@ -214,6 +215,7 @@ int reject_with_cb_reference(void *ctx) - if (!f) - return 0; - bpf_loop(5, subprog_cb_ref, NULL, 0); -+ bpf_obj_drop(f); - return 0; - } - -diff --git a/tools/testing/selftests/bpf/progs/strobemeta.h b/tools/testing/selftests/bpf/progs/strobemeta.h -index e02cfd38074..40df2cc26ea 100644 ---- a/tools/testing/selftests/bpf/progs/strobemeta.h -+++ b/tools/testing/selftests/bpf/progs/strobemeta.h -@@ -24,9 +24,11 @@ struct task_struct {}; - #define STACK_TABLE_EPOCH_SHIFT 20 - #define STROBE_MAX_STR_LEN 1 - #define STROBE_MAX_CFGS 32 -+#define READ_MAP_VAR_PAYLOAD_CAP \ -+ ((1 + STROBE_MAX_MAP_ENTRIES * 2) * STROBE_MAX_STR_LEN) - #define STROBE_MAX_PAYLOAD \ - (STROBE_MAX_STRS * STROBE_MAX_STR_LEN + \ -- STROBE_MAX_MAPS * (1 + STROBE_MAX_MAP_ENTRIES * 2) * STROBE_MAX_STR_LEN) -+ STROBE_MAX_MAPS * READ_MAP_VAR_PAYLOAD_CAP) - - struct strobe_value_header { - /* -@@ -355,7 +357,7 @@ static __always_inline uint64_t read_str_var(struct strobemeta_cfg *cfg, - size_t idx, void *tls_base, - struct strobe_value_generic *value, - struct strobemeta_payload *data, -- void *payload) -+ size_t off) - { - void *location; - uint64_t len; -@@ -366,7 +368,7 @@ static __always_inline uint64_t read_str_var(struct strobemeta_cfg *cfg, - return 0; - - bpf_probe_read_user(value, sizeof(struct strobe_value_generic), location); -- len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN, value->ptr); -+ len = bpf_probe_read_user_str(&data->payload[off], STROBE_MAX_STR_LEN, value->ptr); - /* - * if bpf_probe_read_user_str returns error (<0), due to casting to - * unsinged int, it will become big number, so next check is -@@ -378,14 +380,14 @@ static __always_inline uint64_t read_str_var(struct strobemeta_cfg *cfg, - return 0; - - data->str_lens[idx] = len; -- return len; -+ return off + len; - } - --static __always_inline void *read_map_var(struct strobemeta_cfg *cfg, -- size_t idx, void *tls_base, -- struct strobe_value_generic *value, -- struct strobemeta_payload *data, -- void *payload) -+static __always_inline uint64_t read_map_var(struct strobemeta_cfg *cfg, -+ size_t idx, void *tls_base, -+ struct strobe_value_generic *value, -+ struct strobemeta_payload *data, -+ size_t off) - { - struct strobe_map_descr* descr = &data->map_descrs[idx]; - struct strobe_map_raw map; -@@ -397,11 +399,11 @@ static __always_inline void *read_map_var(struct strobemeta_cfg *cfg, - - location = calc_location(&cfg->map_locs[idx], tls_base); - if (!location) -- return payload; -+ return off; - - bpf_probe_read_user(value, sizeof(struct strobe_value_generic), location); - if (bpf_probe_read_user(&map, sizeof(struct strobe_map_raw), value->ptr)) -- return payload; -+ return off; - - descr->id = map.id; - descr->cnt = map.cnt; -@@ -410,10 +412,10 @@ static __always_inline void *read_map_var(struct strobemeta_cfg *cfg, - data->req_meta_valid = 1; - } - -- len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN, map.tag); -+ len = bpf_probe_read_user_str(&data->payload[off], STROBE_MAX_STR_LEN, map.tag); - if (len <= STROBE_MAX_STR_LEN) { - descr->tag_len = len; -- payload += len; -+ off += len; - } - - #ifdef NO_UNROLL -@@ -426,22 +428,22 @@ static __always_inline void *read_map_var(struct strobemeta_cfg *cfg, - break; - - descr->key_lens[i] = 0; -- len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN, -+ len = bpf_probe_read_user_str(&data->payload[off], STROBE_MAX_STR_LEN, - map.entries[i].key); - if (len <= STROBE_MAX_STR_LEN) { - descr->key_lens[i] = len; -- payload += len; -+ off += len; - } - descr->val_lens[i] = 0; -- len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN, -+ len = bpf_probe_read_user_str(&data->payload[off], STROBE_MAX_STR_LEN, - map.entries[i].val); - if (len <= STROBE_MAX_STR_LEN) { - descr->val_lens[i] = len; -- payload += len; -+ off += len; - } - } - -- return payload; -+ return off; - } - - #ifdef USE_BPF_LOOP -@@ -455,14 +457,20 @@ struct read_var_ctx { - struct strobemeta_payload *data; - void *tls_base; - struct strobemeta_cfg *cfg; -- void *payload; -+ size_t payload_off; - /* value gets mutated */ - struct strobe_value_generic *value; - enum read_type type; - }; - --static int read_var_callback(__u32 index, struct read_var_ctx *ctx) -+static int read_var_callback(__u64 index, struct read_var_ctx *ctx) - { -+ /* lose precision info for ctx->payload_off, verifier won't track -+ * double xor, barrier_var() is needed to force clang keep both xors. -+ */ -+ ctx->payload_off ^= index; -+ barrier_var(ctx->payload_off); -+ ctx->payload_off ^= index; - switch (ctx->type) { - case READ_INT_VAR: - if (index >= STROBE_MAX_INTS) -@@ -472,14 +480,18 @@ static int read_var_callback(__u32 index, struct read_var_ctx *ctx) - case READ_MAP_VAR: - if (index >= STROBE_MAX_MAPS) - return 1; -- ctx->payload = read_map_var(ctx->cfg, index, ctx->tls_base, -- ctx->value, ctx->data, ctx->payload); -+ if (ctx->payload_off > sizeof(ctx->data->payload) - READ_MAP_VAR_PAYLOAD_CAP) -+ return 1; -+ ctx->payload_off = read_map_var(ctx->cfg, index, ctx->tls_base, -+ ctx->value, ctx->data, ctx->payload_off); - break; - case READ_STR_VAR: - if (index >= STROBE_MAX_STRS) - return 1; -- ctx->payload += read_str_var(ctx->cfg, index, ctx->tls_base, -- ctx->value, ctx->data, ctx->payload); -+ if (ctx->payload_off > sizeof(ctx->data->payload) - STROBE_MAX_STR_LEN) -+ return 1; -+ ctx->payload_off = read_str_var(ctx->cfg, index, ctx->tls_base, -+ ctx->value, ctx->data, ctx->payload_off); - break; - } - return 0; -@@ -501,7 +513,8 @@ static void *read_strobe_meta(struct task_struct *task, - pid_t pid = bpf_get_current_pid_tgid() >> 32; - struct strobe_value_generic value = {0}; - struct strobemeta_cfg *cfg; -- void *tls_base, *payload; -+ size_t payload_off; -+ void *tls_base; - - cfg = bpf_map_lookup_elem(&strobemeta_cfgs, &pid); - if (!cfg) -@@ -509,7 +522,7 @@ static void *read_strobe_meta(struct task_struct *task, - - data->int_vals_set_mask = 0; - data->req_meta_valid = 0; -- payload = data->payload; -+ payload_off = 0; - /* - * we don't have struct task_struct definition, it should be: - * tls_base = (void *)task->thread.fsbase; -@@ -522,7 +535,7 @@ static void *read_strobe_meta(struct task_struct *task, - .tls_base = tls_base, - .value = &value, - .data = data, -- .payload = payload, -+ .payload_off = 0, - }; - int err; - -@@ -540,6 +553,11 @@ static void *read_strobe_meta(struct task_struct *task, - err = bpf_loop(STROBE_MAX_MAPS, read_var_callback, &ctx, 0); - if (err != STROBE_MAX_MAPS) - return NULL; -+ -+ payload_off = ctx.payload_off; -+ /* this should not really happen, here only to satisfy verifer */ -+ if (payload_off > sizeof(data->payload)) -+ payload_off = sizeof(data->payload); - #else - #ifdef NO_UNROLL - #pragma clang loop unroll(disable) -@@ -555,7 +573,7 @@ static void *read_strobe_meta(struct task_struct *task, - #pragma unroll - #endif /* NO_UNROLL */ - for (int i = 0; i < STROBE_MAX_STRS; ++i) { -- payload += read_str_var(cfg, i, tls_base, &value, data, payload); -+ payload_off = read_str_var(cfg, i, tls_base, &value, data, payload_off); - } - #ifdef NO_UNROLL - #pragma clang loop unroll(disable) -@@ -563,7 +581,7 @@ static void *read_strobe_meta(struct task_struct *task, - #pragma unroll - #endif /* NO_UNROLL */ - for (int i = 0; i < STROBE_MAX_MAPS; ++i) { -- payload = read_map_var(cfg, i, tls_base, &value, data, payload); -+ payload_off = read_map_var(cfg, i, tls_base, &value, data, payload_off); - } - #endif /* USE_BPF_LOOP */ - -@@ -571,7 +589,7 @@ static void *read_strobe_meta(struct task_struct *task, - * return pointer right after end of payload, so it's possible to - * calculate exact amount of useful data that needs to be sent - */ -- return payload; -+ return &data->payload[payload_off]; - } - - SEC("raw_tracepoint/kfree_skb") -diff --git a/tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c b/tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c -new file mode 100644 -index 00000000000..5905e036e0e ---- /dev/null -+++ b/tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c -@@ -0,0 +1,242 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include -+#include -+#include "bpf_misc.h" -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_ARRAY); -+ __uint(max_entries, 8); -+ __type(key, __u32); -+ __type(value, __u64); -+} map SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_USER_RINGBUF); -+ __uint(max_entries, 8); -+} ringbuf SEC(".maps"); -+ -+struct vm_area_struct; -+struct bpf_map; -+ -+struct buf_context { -+ char *buf; -+}; -+ -+struct num_context { -+ __u64 i; -+ __u64 j; -+}; -+ -+__u8 choice_arr[2] = { 0, 1 }; -+ -+static int unsafe_on_2nd_iter_cb(__u32 idx, struct buf_context *ctx) -+{ -+ if (idx == 0) { -+ ctx->buf = (char *)(0xDEAD); -+ return 0; -+ } -+ -+ if (bpf_probe_read_user(ctx->buf, 8, (void *)(0xBADC0FFEE))) -+ return 1; -+ -+ return 0; -+} -+ -+SEC("?raw_tp") -+__failure __msg("R1 type=scalar expected=fp") -+int unsafe_on_2nd_iter(void *unused) -+{ -+ char buf[4]; -+ struct buf_context loop_ctx = { .buf = buf }; -+ -+ bpf_loop(100, unsafe_on_2nd_iter_cb, &loop_ctx, 0); -+ return 0; -+} -+ -+static int unsafe_on_zero_iter_cb(__u32 idx, struct num_context *ctx) -+{ -+ ctx->i = 0; -+ return 0; -+} -+ -+SEC("?raw_tp") -+__failure __msg("invalid access to map value, value_size=2 off=32 size=1") -+int unsafe_on_zero_iter(void *unused) -+{ -+ struct num_context loop_ctx = { .i = 32 }; -+ -+ bpf_loop(100, unsafe_on_zero_iter_cb, &loop_ctx, 0); -+ return choice_arr[loop_ctx.i]; -+} -+ -+static int widening_cb(__u32 idx, struct num_context *ctx) -+{ -+ ++ctx->i; -+ return 0; -+} -+ -+SEC("?raw_tp") -+__success -+int widening(void *unused) -+{ -+ struct num_context loop_ctx = { .i = 0, .j = 1 }; -+ -+ bpf_loop(100, widening_cb, &loop_ctx, 0); -+ /* loop_ctx.j is not changed during callback iteration, -+ * verifier should not apply widening to it. -+ */ -+ return choice_arr[loop_ctx.j]; -+} -+ -+static int loop_detection_cb(__u32 idx, struct num_context *ctx) -+{ -+ for (;;) {} -+ return 0; -+} -+ -+SEC("?raw_tp") -+__failure __msg("infinite loop detected") -+int loop_detection(void *unused) -+{ -+ struct num_context loop_ctx = { .i = 0 }; -+ -+ bpf_loop(100, loop_detection_cb, &loop_ctx, 0); -+ return 0; -+} -+ -+static __always_inline __u64 oob_state_machine(struct num_context *ctx) -+{ -+ switch (ctx->i) { -+ case 0: -+ ctx->i = 1; -+ break; -+ case 1: -+ ctx->i = 32; -+ break; -+ } -+ return 0; -+} -+ -+static __u64 for_each_map_elem_cb(struct bpf_map *map, __u32 *key, __u64 *val, void *data) -+{ -+ return oob_state_machine(data); -+} -+ -+SEC("?raw_tp") -+__failure __msg("invalid access to map value, value_size=2 off=32 size=1") -+int unsafe_for_each_map_elem(void *unused) -+{ -+ struct num_context loop_ctx = { .i = 0 }; -+ -+ bpf_for_each_map_elem(&map, for_each_map_elem_cb, &loop_ctx, 0); -+ return choice_arr[loop_ctx.i]; -+} -+ -+static __u64 ringbuf_drain_cb(struct bpf_dynptr *dynptr, void *data) -+{ -+ return oob_state_machine(data); -+} -+ -+SEC("?raw_tp") -+__failure __msg("invalid access to map value, value_size=2 off=32 size=1") -+int unsafe_ringbuf_drain(void *unused) -+{ -+ struct num_context loop_ctx = { .i = 0 }; -+ -+ bpf_user_ringbuf_drain(&ringbuf, ringbuf_drain_cb, &loop_ctx, 0); -+ return choice_arr[loop_ctx.i]; -+} -+ -+static __u64 find_vma_cb(struct task_struct *task, struct vm_area_struct *vma, void *data) -+{ -+ return oob_state_machine(data); -+} -+ -+SEC("?raw_tp") -+__failure __msg("invalid access to map value, value_size=2 off=32 size=1") -+int unsafe_find_vma(void *unused) -+{ -+ struct task_struct *task = bpf_get_current_task_btf(); -+ struct num_context loop_ctx = { .i = 0 }; -+ -+ bpf_find_vma(task, 0, find_vma_cb, &loop_ctx, 0); -+ return choice_arr[loop_ctx.i]; -+} -+ -+static int iter_limit_cb(__u32 idx, struct num_context *ctx) -+{ -+ ctx->i++; -+ return 0; -+} -+ -+SEC("?raw_tp") -+__success -+int bpf_loop_iter_limit_ok(void *unused) -+{ -+ struct num_context ctx = { .i = 0 }; -+ -+ bpf_loop(1, iter_limit_cb, &ctx, 0); -+ return choice_arr[ctx.i]; -+} -+ -+SEC("?raw_tp") -+__failure __msg("invalid access to map value, value_size=2 off=2 size=1") -+int bpf_loop_iter_limit_overflow(void *unused) -+{ -+ struct num_context ctx = { .i = 0 }; -+ -+ bpf_loop(2, iter_limit_cb, &ctx, 0); -+ return choice_arr[ctx.i]; -+} -+ -+static int iter_limit_level2a_cb(__u32 idx, struct num_context *ctx) -+{ -+ ctx->i += 100; -+ return 0; -+} -+ -+static int iter_limit_level2b_cb(__u32 idx, struct num_context *ctx) -+{ -+ ctx->i += 10; -+ return 0; -+} -+ -+static int iter_limit_level1_cb(__u32 idx, struct num_context *ctx) -+{ -+ ctx->i += 1; -+ bpf_loop(1, iter_limit_level2a_cb, ctx, 0); -+ bpf_loop(1, iter_limit_level2b_cb, ctx, 0); -+ return 0; -+} -+ -+/* Check that path visiting every callback function once had been -+ * reached by verifier. Variables 'ctx{1,2}i' below serve as flags, -+ * with each decimal digit corresponding to a callback visit marker. -+ */ -+SEC("socket") -+__success __retval(111111) -+int bpf_loop_iter_limit_nested(void *unused) -+{ -+ struct num_context ctx1 = { .i = 0 }; -+ struct num_context ctx2 = { .i = 0 }; -+ __u64 a, b, c; -+ -+ bpf_loop(1, iter_limit_level1_cb, &ctx1, 0); -+ bpf_loop(1, iter_limit_level1_cb, &ctx2, 0); -+ a = ctx1.i; -+ b = ctx2.i; -+ /* Force 'ctx1.i' and 'ctx2.i' precise. */ -+ c = choice_arr[(a + b) % 2]; -+ /* This makes 'c' zero, but neither clang nor verifier know it. */ -+ c /= 10; -+ /* Make sure that verifier does not visit 'impossible' states: -+ * enumerate all possible callback visit masks. -+ */ -+ if (a != 0 && a != 1 && a != 11 && a != 101 && a != 111 && -+ b != 0 && b != 1 && b != 11 && b != 101 && b != 111) -+ asm volatile ("r0 /= 0;" ::: "r0"); -+ return 1000 * a + b + c; -+} -+ -+char _license[] SEC("license") = "GPL"; -diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c -index db6b3143338..f61d623b1ce 100644 ---- a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c -+++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c -@@ -119,15 +119,41 @@ __naked int global_subprog_result_precise(void) - - SEC("?raw_tp") - __success __log_level(2) -+/* First simulated path does not include callback body, -+ * r1 and r4 are always precise for bpf_loop() calls. -+ */ -+__msg("9: (85) call bpf_loop#181") -+__msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1") -+__msg("mark_precise: frame0: parent state regs=r4 stack=:") -+__msg("mark_precise: frame0: last_idx 8 first_idx 0 subseq_idx 9") -+__msg("mark_precise: frame0: regs=r4 stack= before 8: (b7) r4 = 0") -+__msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1") -+__msg("mark_precise: frame0: parent state regs=r1 stack=:") -+__msg("mark_precise: frame0: last_idx 8 first_idx 0 subseq_idx 9") -+__msg("mark_precise: frame0: regs=r1 stack= before 8: (b7) r4 = 0") -+__msg("mark_precise: frame0: regs=r1 stack= before 7: (b7) r3 = 0") -+__msg("mark_precise: frame0: regs=r1 stack= before 6: (bf) r2 = r8") -+__msg("mark_precise: frame0: regs=r1 stack= before 5: (bf) r1 = r6") -+__msg("mark_precise: frame0: regs=r6 stack= before 4: (b7) r6 = 3") -+/* r6 precision propagation */ - __msg("14: (0f) r1 += r6") --__msg("mark_precise: frame0: last_idx 14 first_idx 10") -+__msg("mark_precise: frame0: last_idx 14 first_idx 9") - __msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7") - __msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4") - __msg("mark_precise: frame0: regs=r6 stack= before 11: (25) if r6 > 0x3 goto pc+4") - __msg("mark_precise: frame0: regs=r6 stack= before 10: (bf) r6 = r0") --__msg("mark_precise: frame0: parent state regs=r0 stack=:") --__msg("mark_precise: frame0: last_idx 18 first_idx 0") --__msg("mark_precise: frame0: regs=r0 stack= before 18: (95) exit") -+__msg("mark_precise: frame0: regs=r0 stack= before 9: (85) call bpf_loop") -+/* State entering callback body popped from states stack */ -+__msg("from 9 to 17: frame1:") -+__msg("17: frame1: R1=scalar() R2=0 R10=fp0 cb") -+__msg("17: (b7) r0 = 0") -+__msg("18: (95) exit") -+__msg("returning from callee:") -+__msg("to caller at 9:") -+__msg("frame 0: propagating r1,r4") -+__msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1") -+__msg("mark_precise: frame0: regs=r1,r4 stack= before 18: (95) exit") -+__msg("from 18 to 9: safe") - __naked int callback_result_precise(void) - { - asm volatile ( -@@ -233,20 +259,36 @@ __naked int parent_callee_saved_reg_precise_global(void) - - SEC("?raw_tp") - __success __log_level(2) -+/* First simulated path does not include callback body */ - __msg("12: (0f) r1 += r6") --__msg("mark_precise: frame0: last_idx 12 first_idx 10") -+__msg("mark_precise: frame0: last_idx 12 first_idx 9") - __msg("mark_precise: frame0: regs=r6 stack= before 11: (bf) r1 = r7") - __msg("mark_precise: frame0: regs=r6 stack= before 10: (27) r6 *= 4") -+__msg("mark_precise: frame0: regs=r6 stack= before 9: (85) call bpf_loop") - __msg("mark_precise: frame0: parent state regs=r6 stack=:") --__msg("mark_precise: frame0: last_idx 16 first_idx 0") --__msg("mark_precise: frame0: regs=r6 stack= before 16: (95) exit") --__msg("mark_precise: frame1: regs= stack= before 15: (b7) r0 = 0") --__msg("mark_precise: frame1: regs= stack= before 9: (85) call bpf_loop#181") -+__msg("mark_precise: frame0: last_idx 8 first_idx 0 subseq_idx 9") - __msg("mark_precise: frame0: regs=r6 stack= before 8: (b7) r4 = 0") - __msg("mark_precise: frame0: regs=r6 stack= before 7: (b7) r3 = 0") - __msg("mark_precise: frame0: regs=r6 stack= before 6: (bf) r2 = r8") - __msg("mark_precise: frame0: regs=r6 stack= before 5: (b7) r1 = 1") - __msg("mark_precise: frame0: regs=r6 stack= before 4: (b7) r6 = 3") -+/* State entering callback body popped from states stack */ -+__msg("from 9 to 15: frame1:") -+__msg("15: frame1: R1=scalar() R2=0 R10=fp0 cb") -+__msg("15: (b7) r0 = 0") -+__msg("16: (95) exit") -+__msg("returning from callee:") -+__msg("to caller at 9:") -+/* r1, r4 are always precise for bpf_loop(), -+ * r6 was marked before backtracking to callback body. -+ */ -+__msg("frame 0: propagating r1,r4,r6") -+__msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1") -+__msg("mark_precise: frame0: regs=r1,r4,r6 stack= before 16: (95) exit") -+__msg("mark_precise: frame1: regs= stack= before 15: (b7) r0 = 0") -+__msg("mark_precise: frame1: regs= stack= before 9: (85) call bpf_loop") -+__msg("mark_precise: frame0: parent state regs= stack=:") -+__msg("from 16 to 9: safe") - __naked int parent_callee_saved_reg_precise_with_callback(void) - { - asm volatile ( -@@ -373,22 +415,38 @@ __naked int parent_stack_slot_precise_global(void) - - SEC("?raw_tp") - __success __log_level(2) -+/* First simulated path does not include callback body */ - __msg("14: (0f) r1 += r6") --__msg("mark_precise: frame0: last_idx 14 first_idx 11") -+__msg("mark_precise: frame0: last_idx 14 first_idx 10") - __msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7") - __msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4") - __msg("mark_precise: frame0: regs=r6 stack= before 11: (79) r6 = *(u64 *)(r10 -8)") -+__msg("mark_precise: frame0: regs= stack=-8 before 10: (85) call bpf_loop") - __msg("mark_precise: frame0: parent state regs= stack=-8:") --__msg("mark_precise: frame0: last_idx 18 first_idx 0") --__msg("mark_precise: frame0: regs= stack=-8 before 18: (95) exit") --__msg("mark_precise: frame1: regs= stack= before 17: (b7) r0 = 0") --__msg("mark_precise: frame1: regs= stack= before 10: (85) call bpf_loop#181") -+__msg("mark_precise: frame0: last_idx 9 first_idx 0 subseq_idx 10") - __msg("mark_precise: frame0: regs= stack=-8 before 9: (b7) r4 = 0") - __msg("mark_precise: frame0: regs= stack=-8 before 8: (b7) r3 = 0") - __msg("mark_precise: frame0: regs= stack=-8 before 7: (bf) r2 = r8") - __msg("mark_precise: frame0: regs= stack=-8 before 6: (bf) r1 = r6") - __msg("mark_precise: frame0: regs= stack=-8 before 5: (7b) *(u64 *)(r10 -8) = r6") - __msg("mark_precise: frame0: regs=r6 stack= before 4: (b7) r6 = 3") -+/* State entering callback body popped from states stack */ -+__msg("from 10 to 17: frame1:") -+__msg("17: frame1: R1=scalar() R2=0 R10=fp0 cb") -+__msg("17: (b7) r0 = 0") -+__msg("18: (95) exit") -+__msg("returning from callee:") -+__msg("to caller at 10:") -+/* r1, r4 are always precise for bpf_loop(), -+ * fp-8 was marked before backtracking to callback body. -+ */ -+__msg("frame 0: propagating r1,r4,fp-8") -+__msg("mark_precise: frame0: last_idx 10 first_idx 10 subseq_idx -1") -+__msg("mark_precise: frame0: regs=r1,r4 stack=-8 before 18: (95) exit") -+__msg("mark_precise: frame1: regs= stack= before 17: (b7) r0 = 0") -+__msg("mark_precise: frame1: regs= stack= before 10: (85) call bpf_loop#181") -+__msg("mark_precise: frame0: parent state regs= stack=:") -+__msg("from 18 to 10: safe") - __naked int parent_stack_slot_precise_with_callback(void) - { - asm volatile ( -diff --git a/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c b/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c -index e959336c7a7..80f620602d5 100644 ---- a/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c -+++ b/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c -@@ -53,6 +53,8 @@ - #define DEFAULT_TTL 64 - #define MAX_ALLOWED_PORTS 8 - -+#define MAX_PACKET_OFF 0xffff -+ - #define swap(a, b) \ - do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) - -@@ -183,63 +185,76 @@ static __always_inline __u32 tcp_clock_ms(void) - } - - struct tcpopt_context { -- __u8 *ptr; -- __u8 *end; -+ void *data; - void *data_end; - __be32 *tsecr; - __u8 wscale; - bool option_timestamp; - bool option_sack; -+ __u32 off; - }; - --static int tscookie_tcpopt_parse(struct tcpopt_context *ctx) -+static __always_inline u8 *next(struct tcpopt_context *ctx, __u32 sz) - { -- __u8 opcode, opsize; -+ __u64 off = ctx->off; -+ __u8 *data; - -- if (ctx->ptr >= ctx->end) -- return 1; -- if (ctx->ptr >= ctx->data_end) -- return 1; -+ /* Verifier forbids access to packet when offset exceeds MAX_PACKET_OFF */ -+ if (off > MAX_PACKET_OFF - sz) -+ return NULL; - -- opcode = ctx->ptr[0]; -+ data = ctx->data + off; -+ barrier_var(data); -+ if (data + sz >= ctx->data_end) -+ return NULL; - -- if (opcode == TCPOPT_EOL) -- return 1; -- if (opcode == TCPOPT_NOP) { -- ++ctx->ptr; -- return 0; -- } -+ ctx->off += sz; -+ return data; -+} - -- if (ctx->ptr + 1 >= ctx->end) -- return 1; -- if (ctx->ptr + 1 >= ctx->data_end) -+static int tscookie_tcpopt_parse(struct tcpopt_context *ctx) -+{ -+ __u8 *opcode, *opsize, *wscale, *tsecr; -+ __u32 off = ctx->off; -+ -+ opcode = next(ctx, 1); -+ if (!opcode) - return 1; -- opsize = ctx->ptr[1]; -- if (opsize < 2) -+ -+ if (*opcode == TCPOPT_EOL) - return 1; -+ if (*opcode == TCPOPT_NOP) -+ return 0; - -- if (ctx->ptr + opsize > ctx->end) -+ opsize = next(ctx, 1); -+ if (!opsize || *opsize < 2) - return 1; - -- switch (opcode) { -+ switch (*opcode) { - case TCPOPT_WINDOW: -- if (opsize == TCPOLEN_WINDOW && ctx->ptr + TCPOLEN_WINDOW <= ctx->data_end) -- ctx->wscale = ctx->ptr[2] < TCP_MAX_WSCALE ? ctx->ptr[2] : TCP_MAX_WSCALE; -+ wscale = next(ctx, 1); -+ if (!wscale) -+ return 1; -+ if (*opsize == TCPOLEN_WINDOW) -+ ctx->wscale = *wscale < TCP_MAX_WSCALE ? *wscale : TCP_MAX_WSCALE; - break; - case TCPOPT_TIMESTAMP: -- if (opsize == TCPOLEN_TIMESTAMP && ctx->ptr + TCPOLEN_TIMESTAMP <= ctx->data_end) { -+ tsecr = next(ctx, 4); -+ if (!tsecr) -+ return 1; -+ if (*opsize == TCPOLEN_TIMESTAMP) { - ctx->option_timestamp = true; - /* Client's tsval becomes our tsecr. */ -- *ctx->tsecr = get_unaligned((__be32 *)(ctx->ptr + 2)); -+ *ctx->tsecr = get_unaligned((__be32 *)tsecr); - } - break; - case TCPOPT_SACK_PERM: -- if (opsize == TCPOLEN_SACK_PERM) -+ if (*opsize == TCPOLEN_SACK_PERM) - ctx->option_sack = true; - break; - } - -- ctx->ptr += opsize; -+ ctx->off = off + *opsize; - - return 0; - } -@@ -256,16 +271,21 @@ static int tscookie_tcpopt_parse_batch(__u32 index, void *context) - - static __always_inline bool tscookie_init(struct tcphdr *tcp_header, - __u16 tcp_len, __be32 *tsval, -- __be32 *tsecr, void *data_end) -+ __be32 *tsecr, void *data, void *data_end) - { - struct tcpopt_context loop_ctx = { -- .ptr = (__u8 *)(tcp_header + 1), -- .end = (__u8 *)tcp_header + tcp_len, -+ .data = data, - .data_end = data_end, - .tsecr = tsecr, - .wscale = TS_OPT_WSCALE_MASK, - .option_timestamp = false, - .option_sack = false, -+ /* Note: currently verifier would track .off as unbound scalar. -+ * In case if verifier would at some point get smarter and -+ * compute bounded value for this var, beware that it might -+ * hinder bpf_loop() convergence validation. -+ */ -+ .off = (__u8 *)(tcp_header + 1) - (__u8 *)data, - }; - u32 cookie; - -@@ -635,7 +655,7 @@ static __always_inline int syncookie_handle_syn(struct header_pointers *hdr, - cookie = (__u32)value; - - if (tscookie_init((void *)hdr->tcp, hdr->tcp_len, -- &tsopt_buf[0], &tsopt_buf[1], data_end)) -+ &tsopt_buf[0], &tsopt_buf[1], data, data_end)) - tsopt = tsopt_buf; - - /* Check that there is enough space for a SYNACK. It also covers -diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh -index 5f2b3f6c0d7..38be9706c45 100755 ---- a/tools/testing/selftests/net/rtnetlink.sh -+++ b/tools/testing/selftests/net/rtnetlink.sh -@@ -859,7 +859,7 @@ kci_test_gretap() - - - run_cmd ip -netns "$testns" addr add dev "$DEV_NS" 10.1.1.100/24 -- run_cmd ip -netns "$testns" link set dev $DEV_NS ups -+ run_cmd ip -netns "$testns" link set dev $DEV_NS up - run_cmd ip -netns "$testns" link del "$DEV_NS" - - # test external mode -diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c -index 5b0e93f9996..01fa816868b 100644 ---- a/tools/testing/vsock/vsock_test.c -+++ b/tools/testing/vsock/vsock_test.c -@@ -353,11 +353,12 @@ static void test_stream_msg_peek_server(const struct test_opts *opts) - } - - #define SOCK_BUF_SIZE (2 * 1024 * 1024) --#define MAX_MSG_SIZE (32 * 1024) -+#define MAX_MSG_PAGES 4 - - static void test_seqpacket_msg_bounds_client(const struct test_opts *opts) - { - unsigned long curr_hash; -+ size_t max_msg_size; - int page_size; - int msg_count; - int fd; -@@ -373,7 +374,8 @@ static void test_seqpacket_msg_bounds_client(const struct test_opts *opts) - - curr_hash = 0; - page_size = getpagesize(); -- msg_count = SOCK_BUF_SIZE / MAX_MSG_SIZE; -+ max_msg_size = MAX_MSG_PAGES * page_size; -+ msg_count = SOCK_BUF_SIZE / max_msg_size; - - for (int i = 0; i < msg_count; i++) { - size_t buf_size; -@@ -383,7 +385,7 @@ static void test_seqpacket_msg_bounds_client(const struct test_opts *opts) - /* Use "small" buffers and "big" buffers. */ - if (i & 1) - buf_size = page_size + -- (rand() % (MAX_MSG_SIZE - page_size)); -+ (rand() % (max_msg_size - page_size)); - else - buf_size = 1 + (rand() % page_size); - -@@ -429,7 +431,6 @@ static void test_seqpacket_msg_bounds_server(const struct test_opts *opts) - unsigned long remote_hash; - unsigned long curr_hash; - int fd; -- char buf[MAX_MSG_SIZE]; - struct msghdr msg = {0}; - struct iovec iov = {0}; - -@@ -457,8 +458,13 @@ static void test_seqpacket_msg_bounds_server(const struct test_opts *opts) - control_writeln("SRVREADY"); - /* Wait, until peer sends whole data. */ - control_expectln("SENDDONE"); -- iov.iov_base = buf; -- iov.iov_len = sizeof(buf); -+ iov.iov_len = MAX_MSG_PAGES * getpagesize(); -+ iov.iov_base = malloc(iov.iov_len); -+ if (!iov.iov_base) { -+ perror("malloc"); -+ exit(EXIT_FAILURE); -+ } -+ - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - -@@ -483,6 +489,7 @@ static void test_seqpacket_msg_bounds_server(const struct test_opts *opts) - curr_hash += hash_djb2(msg.msg_iov[0].iov_base, recv_size); - } - -+ free(iov.iov_base); - close(fd); - remote_hash = control_readulong(); - diff --git a/system/hardware/oneplus-enchilada/pkgs.nix b/system/hardware/oneplus-enchilada/pkgs.nix index 9626e77..8c33119 100644 --- a/system/hardware/oneplus-enchilada/pkgs.nix +++ b/system/hardware/oneplus-enchilada/pkgs.nix @@ -119,10 +119,7 @@ in { meta.license = lib.licenses.unfreeRedistributableFirmware; }; - linux_enchilada = pkgs.linux_testing.override { - argsOverride.version = "6.7-rc3"; - argsOverride.modDirVersion = lib.versions.pad 3 "6.7-rc3"; - + linux_enchilada = pkgs.linux_latest.override { # TODO: uncomment # ignoreConfigErrors = false; kernelPatches = [ @@ -136,12 +133,6 @@ in { } ]; - postPatch = '' - substituteInPlace arch/arm64/configs/defconfig \ - --replace CONFIG_QCOM_LLCC=m CONFIG_QCOM_LLCC=y \ - --replace CONFIG_QCOM_OCMEM=m CONFIG_QCOM_OCMEM=y - ''; - stdenv = lib.recursiveUpdate pkgs.stdenv { hostPlatform.linux-kernel.extraConfig = ""; }; diff --git a/system/hardware/radxa-rock5a/default.nix b/system/hardware/radxa-rock5a/default.nix index bbb7394..d1d7cb7 100644 --- a/system/hardware/radxa-rock5a/default.nix +++ b/system/hardware/radxa-rock5a/default.nix @@ -3,17 +3,13 @@ , ... }: { - boot.initrd.availableKernelModules = [ "ahci" "usbhid" "usb_storage" ]; - - # TODO: switch to mainline when PCIe support works - boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.buildLinuxWithCcache pkgs.linux_testing); - boot.kernelPatches = [ - { - name = "linux_6.7.patch"; - patch = ./linux_6.7.patch; - } + boot.initrd.availableKernelModules = [ + "ahci" "usbhid" "usb_storage" + "phy-rockchip-naneng-combphy" ]; + boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux_6_7; + boot.kernelParams = [ "dtb=/${config.hardware.deviceTree.name}" ]; hardware.deviceTree.enable = true; hardware.deviceTree.name = "rockchip/rk3588s-rock-5a.dtb"; diff --git a/system/hardware/radxa-rock5a/linux_6.7.patch b/system/hardware/radxa-rock5a/linux_6.7.patch deleted file mode 100644 index 4094026..0000000 --- a/system/hardware/radxa-rock5a/linux_6.7.patch +++ /dev/null @@ -1,17516 +0,0 @@ -diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml -new file mode 100644 -index 000000000..dcca84d57 ---- /dev/null -+++ b/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml -@@ -0,0 +1,166 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/phy/phy-rockchip-usbdp.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Rockchip USBDP Combo PHY with Samsung IP block -+ -+maintainers: -+ - Frank Wang -+ - Zhang Yubing -+ -+properties: -+ compatible: -+ enum: -+ - rockchip,rk3588-usbdp-phy -+ -+ reg: -+ maxItems: 1 -+ -+ clocks: -+ maxItems: 4 -+ -+ clock-names: -+ items: -+ - const: refclk -+ - const: immortal -+ - const: pclk -+ - const: utmi -+ -+ resets: -+ maxItems: 5 -+ -+ reset-names: -+ items: -+ - const: init -+ - const: cmn -+ - const: lane -+ - const: pcs_apb -+ - const: pma_apb -+ -+ rockchip,dp-lane-mux: -+ $ref: /schemas/types.yaml#/definitions/uint32-array -+ minItems: 2 -+ maxItems: 4 -+ description: -+ An array of physical Tyep-C lanes indexes. Position of an entry determines -+ the dp lane index, while the value of an entry indicater physical Type-C lane. -+ The support dp lanes number are 2 or 4. e.g. for 2 lanes dp lanes map, we could -+ have "rockchip,dp-lane-mux = <2, 3>;", assuming dp lane0 on Type-C phy lane2, -+ dp lane1 on Type-C phy lane3. For 4 lanes dp lanes map, we could have -+ "rockchip,dp-lane-mux = <0, 1, 2, 3>;", assuming dp lane0 on Type-C phy lane0, -+ dp lane1 on Type-C phy lane1, dp lane2 on Type-C phy lane2, dp lane3 on Type-C -+ phy lane3. If dp lane map by DisplayPort Alt mode, this property is not need. -+ -+ rockchip,u2phy-grf: -+ $ref: /schemas/types.yaml#/definitions/phandle -+ description: -+ Phandle to the syscon managing the 'usb2 phy general register files'. -+ -+ rockchip,usb-grf: -+ $ref: /schemas/types.yaml#/definitions/phandle -+ description: -+ Phandle to the syscon managing the 'usb general register files'. -+ -+ rockchip,usbdpphy-grf: -+ $ref: /schemas/types.yaml#/definitions/phandle -+ description: -+ Phandle to the syscon managing the 'usbdp phy general register files'. -+ -+ rockchip,vo-grf: -+ $ref: /schemas/types.yaml#/definitions/phandle -+ description: -+ Phandle to the syscon managing the 'video output general register files'. -+ When select the dp lane mapping will request its phandle. -+ -+ sbu1-dc-gpios: -+ description: -+ GPIO connected to the SBU1 line of the USB-C connector via a big resistor -+ (~100K) to apply a DC offset for signalling the connector orientation. -+ -+ sbu2-dc-gpios: -+ description: -+ GPIO connected to the SBU2 line of the USB-C connector via a big resistor -+ (~100K) to apply a DC offset for signalling the connector orientation. -+ -+ orientation-switch: -+ description: Flag the port as possible handler of orientation switching -+ type: boolean -+ -+ mode-switch: -+ description: Flag the port as possible handle of altmode switching -+ type: boolean -+ -+ dp-port: -+ type: object -+ additionalProperties: false -+ -+ properties: -+ "#phy-cells": -+ const: 0 -+ -+ required: -+ - "#phy-cells" -+ -+ usb3-port: -+ type: object -+ additionalProperties: false -+ -+ properties: -+ "#phy-cells": -+ const: 0 -+ -+ required: -+ - "#phy-cells" -+ -+ port: -+ $ref: /schemas/graph.yaml#/properties/port -+ description: -+ A port node to link the PHY to a TypeC controller for the purpose of -+ handling orientation switching. -+ -+required: -+ - compatible -+ - reg -+ - clocks -+ - clock-names -+ - resets -+ - reset-names -+ - dp-port -+ - usb3-port -+ -+additionalProperties: false -+ -+examples: -+ - | -+ #include -+ -+ usbdp_phy0: phy@fed80000 { -+ compatible = "rockchip,rk3588-usbdp-phy"; -+ reg = <0x0 0xfed80000 0x0 0x10000>; -+ rockchip,u2phy-grf = <&usb2phy0_grf>; -+ rockchip,usb-grf = <&usb_grf>; -+ rockchip,usbdpphy-grf = <&usbdpphy0_grf>; -+ rockchip,vo-grf = <&vo0_grf>; -+ clocks = <&cru CLK_USBDPPHY_MIPIDCPPHY_REF>, -+ <&cru CLK_USBDP_PHY0_IMMORTAL>, -+ <&cru PCLK_USBDPPHY0>; -+ clock-names = "refclk", "immortal", "pclk"; -+ resets = <&cru SRST_USBDP_COMBO_PHY0_INIT>, -+ <&cru SRST_USBDP_COMBO_PHY0_CMN>, -+ <&cru SRST_USBDP_COMBO_PHY0_LANE>, -+ <&cru SRST_USBDP_COMBO_PHY0_PCS>, -+ <&cru SRST_P_USBDPPHY0>; -+ reset-names = "init", "cmn", "lane", "pcs_apb", "pma_apb"; -+ status = "disabled"; -+ -+ usbdp_phy0_dp: dp-port { -+ #phy-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ usbdp_phy0_u3: usb3-port { -+ #phy-cells = <0>; -+ status = "disabled"; -+ }; -diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml -index e4fa6a07b..ce1fd5b0d 100644 ---- a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml -+++ b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml -@@ -28,6 +28,9 @@ properties: - - rockchip,rk3588-sys-grf - - rockchip,rk3588-pcie3-phy-grf - - rockchip,rk3588-pcie3-pipe-grf -+ - rockchip,rk3588-usb-grf -+ - rockchip,rk3588-usbdpphy-grf -+ - rockchip,rk3588-vo-grf - - rockchip,rv1108-usbgrf - - const: syscon - - items: -@@ -64,6 +67,9 @@ properties: - reg: - maxItems: 1 - -+ clocks: -+ maxItems: 1 -+ - "#address-cells": - const: 1 - -@@ -245,6 +251,22 @@ allOf: - - unevaluatedProperties: false - -+ - if: -+ properties: -+ compatible: -+ contains: -+ enum: -+ - rockchip,rk3588-vo-grf -+ -+ then: -+ required: -+ - clocks -+ -+ else: -+ properties: -+ clocks: false -+ -+ - examples: - - | - #include -diff --git a/Documentation/devicetree/bindings/sound/es8328.txt b/Documentation/devicetree/bindings/sound/es8328.txt -deleted file mode 100644 -index 33fbf058c..000000000 ---- a/Documentation/devicetree/bindings/sound/es8328.txt -+++ /dev/null -@@ -1,38 +0,0 @@ --Everest ES8328 audio CODEC -- --This device supports both I2C and SPI. -- --Required properties: -- -- - compatible : Should be "everest,es8328" or "everest,es8388" -- - DVDD-supply : Regulator providing digital core supply voltage 1.8 - 3.6V -- - AVDD-supply : Regulator providing analog supply voltage 3.3V -- - PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V -- - IPVDD-supply : Regulator providing analog output voltage 3.3V -- - clocks : A 22.5792 or 11.2896 MHz clock -- - reg : the I2C address of the device for I2C, the chip select number for SPI -- --Pins on the device (for linking into audio routes): -- -- * LOUT1 -- * LOUT2 -- * ROUT1 -- * ROUT2 -- * LINPUT1 -- * RINPUT1 -- * LINPUT2 -- * RINPUT2 -- * Mic Bias -- -- --Example: -- --codec: es8328@11 { -- compatible = "everest,es8328"; -- DVDD-supply = <®_3p3v>; -- AVDD-supply = <®_3p3v>; -- PVDD-supply = <®_3p3v>; -- HPVDD-supply = <®_3p3v>; -- clocks = <&clks 169>; -- reg = <0x11>; --}; -diff --git a/Documentation/devicetree/bindings/sound/everest,es8328.yaml b/Documentation/devicetree/bindings/sound/everest,es8328.yaml -new file mode 100644 -index 000000000..a0f4670fa ---- /dev/null -+++ b/Documentation/devicetree/bindings/sound/everest,es8328.yaml -@@ -0,0 +1,77 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/sound/everest,es8328.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Everest ES8328 audio CODEC -+ -+description: -+ Everest Audio Codec, which can be connected via I2C or SPI. -+ Pins on the device (for linking into audio routes) are -+ * LOUT1 -+ * LOUT2 -+ * ROUT1 -+ * ROUT2 -+ * LINPUT1 -+ * RINPUT1 -+ * LINPUT2 -+ * RINPUT2 -+ * Mic Bias -+ -+maintainers: -+ - David Yang -+ -+properties: -+ compatible: -+ enum: -+ - everest,es8328 -+ - everest,es8388 -+ -+ reg: -+ maxItems: 1 -+ -+ "#sound-dai-cells": -+ const: 0 -+ -+ clocks: -+ items: -+ - description: A 22.5792 or 11.2896 MHz clock -+ -+ DVDD-supply: -+ description: Regulator providing digital core supply voltage 1.8 - 3.6V -+ -+ AVDD-supply: -+ description: Regulator providing analog supply voltage 3.3V -+ -+ PVDD-supply: -+ description: Regulator providing digital IO supply voltage 1.8 - 3.6V -+ -+ HPVDD-supply: -+ description: Regulator providing analog output voltage 3.3V -+ -+required: -+ - compatible -+ - clocks -+ - DVDD-supply -+ - AVDD-supply -+ - PVDD-supply -+ - HPVDD-supply -+ -+additionalProperties: false -+ -+examples: -+ - | -+ i2c { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ es8328: codec@11 { -+ compatible = "everest,es8328"; -+ reg = <0x11>; -+ AVDD-supply = <®_3p3v>; -+ DVDD-supply = <®_3p3v>; -+ HPVDD-supply = <®_3p3v>; -+ PVDD-supply = <®_3p3v>; -+ clocks = <&clks 169>; -+ }; -+ }; -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -index b9d789d57..2ef5c98c4 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 "rk3588.dtsi" - - / { -@@ -56,12 +57,78 @@ button-escape { - }; - }; - -+ analog-sound { -+ compatible = "simple-audio-card"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&hp_detect>; -+ simple-audio-card,name = "RK3588 EVB1 Audio"; -+ simple-audio-card,aux-devs = <&_headphone>, <&_speaker>; -+ simple-audio-card,bitclock-master = <&masterdai>; -+ simple-audio-card,format = "i2s"; -+ simple-audio-card,frame-master = <&masterdai>; -+ simple-audio-card,hp-det-gpio = <&gpio1 RK_PD5 GPIO_ACTIVE_LOW>; -+ simple-audio-card,mclk-fs = <256>; -+ simple-audio-card,pin-switches = "Headphones", "Speaker"; -+ simple-audio-card,routing = -+ "Speaker Amplifier INL", "LOUT2", -+ "Speaker Amplifier INR", "ROUT2", -+ "Speaker", "Speaker Amplifier OUTL", -+ "Speaker", "Speaker Amplifier OUTR", -+ "Headphones Amplifier INL", "LOUT1", -+ "Headphones Amplifier INR", "ROUT1", -+ "Headphones", "Headphones Amplifier OUTL", -+ "Headphones", "Headphones Amplifier OUTR", -+ "LINPUT1", "Onboard Microphone", -+ "RINPUT1", "Onboard Microphone", -+ "LINPUT2", "Microphone Jack", -+ "RINPUT2", "Microphone Jack"; -+ simple-audio-card,widgets = -+ "Microphone", "Microphone Jack", -+ "Microphone", "Onboard Microphone", -+ "Headphone", "Headphones", -+ "Speaker", "Speaker"; -+ -+ simple-audio-card,cpu { -+ sound-dai = <&i2s0_8ch>; -+ }; -+ -+ masterdai: simple-audio-card,codec { -+ sound-dai = <&es8388>; -+ system-clock-frequency = <12288000>; -+ }; -+ }; -+ -+ amp_headphone: headphone-amplifier { -+ compatible = "simple-audio-amplifier"; -+ enable-gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&headphone_amplifier_en>; -+ sound-name-prefix = "Headphones Amplifier"; -+ }; -+ -+ amp_speaker: speaker-amplifier { -+ compatible = "simple-audio-amplifier"; -+ enable-gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&speaker_amplifier_en>; -+ sound-name-prefix = "Speaker Amplifier"; -+ }; -+ - backlight: backlight { - compatible = "pwm-backlight"; - power-supply = <&vcc12v_dcin>; - 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>, <&wifi_host_wake_irq>; -+ }; -+ - pcie20_avdd0v85: pcie20-avdd0v85-regulator { - compatible = "regulator-fixed"; - regulator-name = "pcie20_avdd0v85"; -@@ -167,46 +234,75 @@ vcc5v0_usb: vcc5v0-usb-regulator { - regulator-max-microvolt = <5000000>; - vin-supply = <&vcc5v0_usbdcin>; - }; -+ -+ vbus5v0_typec: vbus5v0-typec { -+ compatible = "regulator-fixed"; -+ regulator-name = "vbus5v0_typec"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ enable-active-high; -+ gpio = <&gpio4 RK_PD0 GPIO_ACTIVE_HIGH>; -+ vin-supply = <&vcc5v0_usb>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&typec5v_pwren>; -+ }; - }; - - &combphy0_ps { - status = "okay"; - }; - -+&combphy1_ps { -+ status = "okay"; -+}; -+ - &combphy2_psu { - status = "okay"; - }; - - &cpu_b0 { - cpu-supply = <&vdd_cpu_big0_s0>; -+ mem-supply = <&vdd_cpu_big0_mem_s0>; - }; - - &cpu_b1 { - cpu-supply = <&vdd_cpu_big0_s0>; -+ mem-supply = <&vdd_cpu_big0_mem_s0>; - }; - - &cpu_b2 { - cpu-supply = <&vdd_cpu_big1_s0>; -+ mem-supply = <&vdd_cpu_big1_mem_s0>; - }; - - &cpu_b3 { - cpu-supply = <&vdd_cpu_big1_s0>; -+ mem-supply = <&vdd_cpu_big1_mem_s0>; - }; - - &cpu_l0 { - cpu-supply = <&vdd_cpu_lit_s0>; -+ mem-supply = <&vdd_cpu_lit_mem_s0>; - }; - - &cpu_l1 { - cpu-supply = <&vdd_cpu_lit_s0>; -+ mem-supply = <&vdd_cpu_lit_mem_s0>; - }; - - &cpu_l2 { - cpu-supply = <&vdd_cpu_lit_s0>; -+ mem-supply = <&vdd_cpu_lit_mem_s0>; - }; - - &cpu_l3 { - cpu-supply = <&vdd_cpu_lit_s0>; -+ mem-supply = <&vdd_cpu_lit_mem_s0>; -+}; -+ -+&display_subsystem { -+ clocks = <&hdptxphy_hdmi_clk0>; -+ clock-names = "hdmi0_phy_pll"; - }; - - &gmac0 { -@@ -227,6 +323,56 @@ &gmac0_rgmii_clk - &i2c2 { - status = "okay"; - -+ usbc0: usb-typec@22 { -+ compatible = "fcs,fusb302"; -+ reg = <0x22>; -+ interrupt-parent = <&gpio3>; -+ interrupts = ; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&usbc0_int>; -+ vbus-supply = <&vbus5v0_typec>; -+ status = "okay"; -+ -+ usb_con: connector { -+ compatible = "usb-c-connector"; -+ label = "USB-C"; -+ data-role = "dual"; -+ power-role = "dual"; -+ try-power-role = "sink"; -+ op-sink-microwatt = <1000000>; -+ sink-pdos = -+ ; -+ source-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>; -+ }; -+ }; -+ }; -+ }; -+ }; -+ - hym8563: rtc@51 { - compatible = "haoyu,hym8563"; - reg = <0x51>; -@@ -240,6 +386,32 @@ hym8563: rtc@51 { - }; - }; - -+&i2c7 { -+ status = "okay"; -+ -+ es8388: audio-codec@11 { -+ compatible = "everest,es8388"; -+ reg = <0x11>; -+ clocks = <&cru I2S0_8CH_MCLKOUT>; -+ assigned-clocks = <&cru I2S0_8CH_MCLKOUT>; -+ assigned-clock-rates = <12288000>; -+ AVDD-supply = <&avcc_1v8_codec_s0>; -+ DVDD-supply = <&avcc_1v8_codec_s0>; -+ HPVDD-supply = <&vcc_3v3_s0>; -+ PVDD-supply = <&vcc_3v3_s0>; -+ #sound-dai-cells = <0>; -+ }; -+}; -+ -+&i2s0_8ch { -+ pinctrl-0 = <&i2s0_lrck -+ &i2s0_mclk -+ &i2s0_sclk -+ &i2s0_sdi0 -+ &i2s0_sdo0>; -+ status = "okay"; -+}; -+ - &mdio0 { - rgmii_phy: ethernet-phy@1 { - /* RTL8211F */ -@@ -253,6 +425,12 @@ rgmii_phy: ethernet-phy@1 { - }; - }; - -+&pcie2x1l0 { -+ reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>; -+ pinctrl-0 = <&pcie2_0_rst>; -+ status = "okay"; -+}; -+ - &pcie2x1l1 { - reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; -@@ -273,6 +451,20 @@ &pcie3x4 { - }; - - &pinctrl { -+ audio { -+ hp_detect: headphone-detect { -+ rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ -+ headphone_amplifier_en: headphone-amplifier-en { -+ rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ -+ speaker_amplifier_en: speaker-amplifier-en { -+ rockchip,pins = <1 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ - rtl8111 { - rtl8111_isolate: rtl8111-isolate { - rockchip,pins = <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>; -@@ -293,6 +485,10 @@ hym8563_int: hym8563-int { - }; - - pcie2 { -+ pcie2_0_rst: pcie2-0-rst { -+ rockchip,pins = <4 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ - pcie2_1_rst: pcie2-1-rst { - rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; - }; -@@ -313,6 +509,26 @@ vcc5v0_host_en: vcc5v0-host-en { - rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; -+ -+ usb-typec { -+ usbc0_int: usbc0-int { -+ rockchip,pins = <3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>; -+ }; -+ -+ typec5v_pwren: typec5v-pwren { -+ rockchip,pins = <4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ 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 { -@@ -943,6 +1159,22 @@ &sata0 { - status = "okay"; - }; - -+&u2phy0 { -+ status = "okay"; -+}; -+ -+&u2phy0_otg { -+ status = "okay"; -+}; -+ -+&u2phy1 { -+ status = "okay"; -+}; -+ -+&u2phy1_otg { -+ status = "okay"; -+}; -+ - &u2phy2 { - status = "okay"; - }; -@@ -981,3 +1213,82 @@ &usb_host1_ehci { - &usb_host1_ohci { - status = "okay"; - }; -+ -+&usbdp_phy0 { -+ orientation-switch; -+ mode-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>; -+ }; -+ }; -+}; -+ -+&usbdp_phy0_u3 { -+ status = "okay"; -+}; -+ -+&usbdp_phy1 { -+ rockchip,dp-lane-mux = <2 3>; -+ status = "okay"; -+}; -+ -+&usbdp_phy1_u3 { -+ status = "okay"; -+}; -+ -+&usb_host0_xhci { -+ dr_mode = "otg"; -+ usb-role-switch; -+ status = "okay"; -+ -+ port { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ dwc3_0_role_switch: endpoint@0 { -+ reg = <0>; -+ remote-endpoint = <&usbc0_role_sw>; -+ }; -+ }; -+}; -+ -+&usb_host1_xhci { -+ status = "okay"; -+}; -+ -+&hdmi0 { -+ status = "okay"; -+}; -+ -+&hdmi0_in_vp0 { -+ status = "okay"; -+}; -+ -+&hdptxphy_hdmi0 { -+ status = "okay"; -+}; -+ -+&hdptxphy_hdmi_clk0 { -+ status = "okay"; -+}; -+ -+&vop_mmu { -+ status = "okay"; -+}; -+ -+&vop { -+ status = "okay"; -+}; -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -index 741f631db..dacf6a4d8 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" - - / { -@@ -59,6 +60,15 @@ fan: pwm-fan { - #cooling-cells = <2>; - }; - -+ 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; -@@ -117,6 +127,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 { -@@ -138,36 +149,53 @@ &combphy1_ps { - status = "okay"; - }; - -+&combphy2_psu { -+ status = "okay"; -+}; -+ - &cpu_b0 { - cpu-supply = <&vdd_cpu_big0_s0>; -+ mem-supply = <&vdd_cpu_big0_s0>; - }; - - &cpu_b1 { - cpu-supply = <&vdd_cpu_big0_s0>; -+ mem-supply = <&vdd_cpu_big0_s0>; - }; - - &cpu_b2 { - cpu-supply = <&vdd_cpu_big1_s0>; -+ mem-supply = <&vdd_cpu_big1_s0>; - }; - - &cpu_b3 { - cpu-supply = <&vdd_cpu_big1_s0>; -+ mem-supply = <&vdd_cpu_big1_s0>; - }; - - &cpu_l0 { - cpu-supply = <&vdd_cpu_lit_s0>; -+ mem-supply = <&vdd_cpu_lit_mem_s0>; - }; - - &cpu_l1 { - cpu-supply = <&vdd_cpu_lit_s0>; -+ mem-supply = <&vdd_cpu_lit_mem_s0>; - }; - - &cpu_l2 { - cpu-supply = <&vdd_cpu_lit_s0>; -+ mem-supply = <&vdd_cpu_lit_mem_s0>; - }; - - &cpu_l3 { - cpu-supply = <&vdd_cpu_lit_s0>; -+ mem-supply = <&vdd_cpu_lit_mem_s0>; -+}; -+ -+&display_subsystem { -+ clocks = <&hdptxphy_hdmi_clk0>; -+ clock-names = "hdmi0_phy_pll"; - }; - - &i2c0 { -@@ -210,6 +238,61 @@ 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>; -+ status = "okay"; -+ -+ 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_hs: endpoint { -+ remote-endpoint = <&usb_host0_xhci_drd_sw>; -+ }; -+ }; -+ -+ port@1 { -+ reg = <1>; -+ usbc0_ss: endpoint { -+ remote-endpoint = <&usbdp_phy0_typec_ss>; -+ }; -+ }; -+ -+ port@2 { -+ reg = <2>; -+ usbc0_sbu: endpoint { -+ remote-endpoint = <&usbdp_phy0_typec_sbu>; -+ }; -+ }; -+ }; -+ }; -+ }; -+}; -+ - &i2c6 { - status = "okay"; - -@@ -339,6 +422,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>; -+ }; - }; - }; - -@@ -731,6 +818,22 @@ &uart2 { - status = "okay"; - }; - -+&u2phy0 { -+ status = "okay"; -+}; -+ -+&u2phy0_otg { -+ status = "okay"; -+}; -+ -+&u2phy1 { -+ status = "okay"; -+}; -+ -+&u2phy1_otg { -+ status = "okay"; -+}; -+ - &u2phy2 { - status = "okay"; - }; -@@ -750,6 +853,41 @@ &u2phy3_host { - status = "okay"; - }; - -+&usbdp_phy1 { -+ status = "okay"; -+}; -+ -+&usbdp_phy1_u3 { -+ status = "okay"; -+}; -+ -+&usbdp_phy0 { -+ orientation-switch; -+ mode-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_typec_ss: endpoint@0 { -+ reg = <0>; -+ remote-endpoint = <&usbc0_ss>; -+ }; -+ -+ usbdp_phy0_typec_sbu: endpoint@1 { -+ reg = <1>; -+ remote-endpoint = <&usbc0_sbu>; -+ }; -+ }; -+}; -+ -+&usbdp_phy0_u3 { -+ status = "okay"; -+}; -+ - &usb_host0_ehci { - status = "okay"; - }; -@@ -758,6 +896,20 @@ &usb_host0_ohci { - status = "okay"; - }; - -+&usb_host0_xhci { -+ usb-role-switch; -+ status = "okay"; -+ -+ port { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ usb_host0_xhci_drd_sw: endpoint { -+ remote-endpoint = <&usbc0_hs>; -+ }; -+ }; -+}; -+ - &usb_host1_ehci { - status = "okay"; - }; -@@ -765,3 +917,35 @@ &usb_host1_ehci { - &usb_host1_ohci { - status = "okay"; - }; -+ -+&usb_host1_xhci { -+ status = "okay"; -+}; -+ -+&usb_host2_xhci { -+ status = "okay"; -+}; -+ -+&hdmi0 { -+ status = "okay"; -+}; -+ -+&hdmi0_in_vp0 { -+ status = "okay"; -+}; -+ -+&hdptxphy_hdmi0 { -+ status = "okay"; -+}; -+ -+&hdptxphy_hdmi_clk0 { -+ status = "okay"; -+}; -+ -+&vop_mmu { -+ status = "okay"; -+}; -+ -+&vop { -+ status = "okay"; -+}; -diff --git a/arch/arm64/boot/dts/rockchip/rk3588.dtsi b/arch/arm64/boot/dts/rockchip/rk3588.dtsi -index 5519c1430..900ac0300 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588.dtsi -@@ -7,6 +7,26 @@ - #include "rk3588-pinctrl.dtsi" - - / { -+ usb_host1_xhci: usb@fc400000 { -+ compatible = "rockchip,rk3588-dwc3", "snps,dwc3"; -+ reg = <0x0 0xfc400000 0x0 0x400000>; -+ interrupts = ; -+ clocks = <&cru REF_CLK_USB3OTG1>, <&cru SUSPEND_CLK_USB3OTG1>, -+ <&cru ACLK_USB3OTG1>; -+ clock-names = "ref_clk", "suspend_clk", "bus_clk"; -+ dr_mode = "host"; -+ phys = <&u2phy1_otg>, <&usbdp_phy1_u3>; -+ phy-names = "usb2-phy", "usb3-phy"; -+ phy_type = "utmi_wide"; -+ power-domains = <&power RK3588_PD_USB>; -+ resets = <&cru SRST_A_USB3OTG1>; -+ snps,dis_enblslpm_quirk; -+ snps,dis-u2-freeclk-exists-quirk; -+ snps,dis-del-phy-power-chg-quirk; -+ snps,dis-tx-ipgap-linecheck-quirk; -+ status = "disabled"; -+ }; -+ - pcie30_phy_grf: syscon@fd5b8000 { - compatible = "rockchip,rk3588-pcie3-phy-grf", "syscon"; - reg = <0x0 0xfd5b8000 0x0 0x10000>; -@@ -17,6 +37,37 @@ pipe_phy1_grf: syscon@fd5c0000 { - reg = <0x0 0xfd5c0000 0x0 0x100>; - }; - -+ usbdpphy1_grf: syscon@fd5cc000 { -+ compatible = "rockchip,rk3588-usbdpphy-grf", "syscon"; -+ reg = <0x0 0xfd5cc000 0x0 0x4000>; -+ }; -+ -+ usb2phy1_grf: syscon@fd5d4000 { -+ compatible = "rockchip,rk3588-usb2phy-grf", "syscon", -+ "simple-mfd"; -+ reg = <0x0 0xfd5d4000 0x0 0x4000>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ u2phy1: usb2-phy@4000 { -+ compatible = "rockchip,rk3588-usb2phy"; -+ reg = <0x4000 0x10>; -+ interrupts = ; -+ resets = <&cru SRST_OTGPHY_U3_1>, <&cru SRST_P_USB2PHY_U3_1_GRF0>; -+ reset-names = "phy", "apb"; -+ clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>; -+ clock-names = "phyclk"; -+ clock-output-names = "usb480m_phy1"; -+ #clock-cells = <0>; -+ status = "disabled"; -+ -+ u2phy1_otg: otg-port { -+ #phy-cells = <0>; -+ status = "disabled"; -+ }; -+ }; -+ }; -+ - i2s8_8ch: i2s@fddc8000 { - compatible = "rockchip,rk3588-i2s-tdm"; - reg = <0x0 0xfddc8000 0x0 0x1000>; -@@ -310,6 +361,37 @@ sata-port@0 { - }; - }; - -+ usbdp_phy1: phy@fed90000 { -+ compatible = "rockchip,rk3588-usbdp-phy"; -+ reg = <0x0 0xfed90000 0x0 0x10000>; -+ rockchip,u2phy-grf = <&usb2phy1_grf>; -+ rockchip,usb-grf = <&usb_grf>; -+ rockchip,usbdpphy-grf = <&usbdpphy1_grf>; -+ rockchip,vo-grf = <&vo0_grf>; -+ clocks = <&cru CLK_USBDPPHY_MIPIDCPPHY_REF>, -+ <&cru CLK_USBDP_PHY1_IMMORTAL>, -+ <&cru PCLK_USBDPPHY1>, -+ <&u2phy1>; -+ clock-names = "refclk", "immortal", "pclk", "utmi"; -+ resets = <&cru SRST_USBDP_COMBO_PHY1_INIT>, -+ <&cru SRST_USBDP_COMBO_PHY1_CMN>, -+ <&cru SRST_USBDP_COMBO_PHY1_LANE>, -+ <&cru SRST_USBDP_COMBO_PHY1_PCS>, -+ <&cru SRST_P_USBDPPHY1>; -+ reset-names = "init", "cmn", "lane", "pcs_apb", "pma_apb"; -+ status = "disabled"; -+ -+ usbdp_phy1_dp: dp-port { -+ #phy-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ usbdp_phy1_u3: usb3-port { -+ #phy-cells = <0>; -+ status = "disabled"; -+ }; -+ }; -+ - combphy1_ps: phy@fee10000 { - compatible = "rockchip,rk3588-naneng-combphy"; - reg = <0x0 0xfee10000 0x0 0x100>; -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts -index 8347adcbd..58c58ec03 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts -@@ -114,36 +114,48 @@ vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { - }; - }; - -+&combphy2_psu { -+ status = "okay"; -+}; -+ - &cpu_b0 { - cpu-supply = <&vdd_cpu_big0_s0>; -+ mem-supply = <&vdd_cpu_big0_s0>; - }; - - &cpu_b1 { - cpu-supply = <&vdd_cpu_big0_s0>; -+ mem-supply = <&vdd_cpu_big0_s0>; - }; - - &cpu_b2 { - cpu-supply = <&vdd_cpu_big1_s0>; -+ mem-supply = <&vdd_cpu_big1_s0>; - }; - - &cpu_b3 { - cpu-supply = <&vdd_cpu_big1_s0>; -+ mem-supply = <&vdd_cpu_big1_s0>; - }; - - &cpu_l0 { - cpu-supply = <&vdd_cpu_lit_s0>; -+ mem-supply = <&vdd_cpu_lit_mem_s0>; - }; - - &cpu_l1 { - cpu-supply = <&vdd_cpu_lit_s0>; -+ mem-supply = <&vdd_cpu_lit_mem_s0>; - }; - - &cpu_l2 { - cpu-supply = <&vdd_cpu_lit_s0>; -+ mem-supply = <&vdd_cpu_lit_mem_s0>; - }; - - &cpu_l3 { - cpu-supply = <&vdd_cpu_lit_s0>; -+ mem-supply = <&vdd_cpu_lit_mem_s0>; - }; - - &i2c0 { -@@ -694,6 +706,14 @@ regulator-state-mem { - }; - }; - -+&u2phy0 { -+ status = "okay"; -+}; -+ -+&u2phy0_otg { -+ status = "okay"; -+}; -+ - &u2phy2 { - status = "okay"; - }; -@@ -717,6 +737,15 @@ &uart2 { - status = "okay"; - }; - -+&usbdp_phy0 { -+ status = "okay"; -+ rockchip,dp-lane-mux = <2 3>; -+}; -+ -+&usbdp_phy0_u3 { -+ status = "okay"; -+}; -+ - &usb_host0_ehci { - status = "okay"; - pinctrl-names = "default"; -@@ -727,6 +756,11 @@ &usb_host0_ohci { - status = "okay"; - }; - -+&usb_host0_xhci { -+ dr_mode = "host"; -+ status = "okay"; -+}; -+ - &usb_host1_ehci { - status = "okay"; - }; -@@ -734,3 +768,7 @@ &usb_host1_ehci { - &usb_host1_ohci { - status = "okay"; - }; -+ -+&usb_host2_xhci { -+ status = "okay"; -+}; -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -index 7064c0e91..4481a2e57 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi -@@ -8,8 +8,10 @@ - #include - #include - #include -+#include - #include - #include -+#include - - / { - compatible = "rockchip,rk3588"; -@@ -18,6 +20,215 @@ / { - #address-cells = <2>; - #size-cells = <2>; - -+ cluster0_opp_table: opp-table-cluster0 { -+ compatible = "operating-points-v2"; -+ opp-shared; -+ -+ opp-408000000 { -+ opp-hz = /bits/ 64 <408000000>; -+ opp-microvolt = <750000 750000 950000>, -+ <750000 750000 950000>; -+ clock-latency-ns = <40000>; -+ opp-suspend; -+ }; -+ opp-600000000 { -+ opp-hz = /bits/ 64 <600000000>; -+ opp-microvolt = <750000 750000 950000>, -+ <750000 750000 950000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-816000000 { -+ opp-hz = /bits/ 64 <816000000>; -+ opp-microvolt = <750000 750000 950000>, -+ <750000 750000 950000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1008000000 { -+ opp-hz = /bits/ 64 <1008000000>; -+ opp-microvolt = <750000 750000 950000>, -+ <750000 750000 950000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1200000000 { -+ opp-hz = /bits/ 64 <1200000000>; -+ opp-microvolt = <775000 775000 950000>, -+ <775000 775000 950000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1416000000 { -+ opp-hz = /bits/ 64 <1416000000>; -+ opp-microvolt = <825000 825000 950000>, -+ <825000 825000 950000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1608000000 { -+ opp-hz = /bits/ 64 <1608000000>; -+ opp-microvolt = <875000 875000 950000>, -+ <875000 875000 950000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1800000000 { -+ opp-hz = /bits/ 64 <1800000000>; -+ opp-microvolt = <950000 950000 950000>, -+ <950000 950000 950000>; -+ clock-latency-ns = <40000>; -+ }; -+ }; -+ -+ cluster1_opp_table: opp-table-cluster1 { -+ compatible = "operating-points-v2"; -+ opp-shared; -+ -+ rockchip,grf = <&bigcore0_grf>; -+ rockchip,volt-mem-read-margin = < -+ 855000 1 -+ 765000 2 -+ 675000 3 -+ 495000 4 -+ >; -+ -+ rockchip,reboot-freq = <1800000000>; -+ -+ opp-408000000 { -+ opp-hz = /bits/ 64 <408000000>; -+ opp-microvolt = <600000 600000 1000000>, -+ <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ opp-suspend; -+ }; -+ opp-600000000 { -+ opp-hz = /bits/ 64 <600000000>; -+ opp-microvolt = <600000 600000 1000000>, -+ <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-816000000 { -+ opp-hz = /bits/ 64 <816000000>; -+ opp-microvolt = <600000 600000 1000000>, -+ <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1008000000 { -+ opp-hz = /bits/ 64 <1008000000>; -+ opp-microvolt = <625000 625000 1000000>, -+ <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1200000000 { -+ opp-hz = /bits/ 64 <1200000000>; -+ opp-microvolt = <650000 650000 1000000>, -+ <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1416000000 { -+ opp-hz = /bits/ 64 <1416000000>; -+ opp-microvolt = <675000 675000 1000000>, -+ <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1608000000 { -+ opp-hz = /bits/ 64 <1608000000>; -+ opp-microvolt = <700000 700000 1000000>, -+ <700000 700000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1800000000 { -+ opp-hz = /bits/ 64 <1800000000>; -+ opp-microvolt = <775000 775000 1000000>, -+ <775000 775000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2016000000 { -+ opp-hz = /bits/ 64 <2016000000>; -+ opp-microvolt = <850000 850000 1000000>, -+ <850000 850000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2208000000 { -+ opp-hz = /bits/ 64 <2208000000>; -+ opp-microvolt = <925000 925000 1000000>, -+ <925000 925000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ }; -+ -+ cluster2_opp_table: opp-table-cluster2 { -+ compatible = "operating-points-v2"; -+ opp-shared; -+ -+ rockchip,grf = <&bigcore1_grf>; -+ rockchip,volt-mem-read-margin = < -+ 855000 1 -+ 765000 2 -+ 675000 3 -+ 495000 4 -+ >; -+ -+ rockchip,reboot-freq = <1800000000>; -+ -+ opp-408000000 { -+ opp-hz = /bits/ 64 <408000000>; -+ opp-microvolt = <600000 600000 1000000>, -+ <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ opp-suspend; -+ }; -+ opp-600000000 { -+ opp-hz = /bits/ 64 <600000000>; -+ opp-microvolt = <600000 600000 1000000>, -+ <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-816000000 { -+ opp-hz = /bits/ 64 <816000000>; -+ opp-microvolt = <600000 600000 1000000>, -+ <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1008000000 { -+ opp-hz = /bits/ 64 <1008000000>; -+ opp-microvolt = <625000 625000 1000000>, -+ <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1200000000 { -+ opp-hz = /bits/ 64 <1200000000>; -+ opp-microvolt = <650000 650000 1000000>, -+ <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1416000000 { -+ opp-hz = /bits/ 64 <1416000000>; -+ opp-microvolt = <675000 675000 1000000>, -+ <675000 675000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1608000000 { -+ opp-hz = /bits/ 64 <1608000000>; -+ opp-microvolt = <700000 700000 1000000>, -+ <700000 700000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-1800000000 { -+ opp-hz = /bits/ 64 <1800000000>; -+ opp-microvolt = <775000 775000 1000000>, -+ <775000 775000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2016000000 { -+ opp-hz = /bits/ 64 <2016000000>; -+ opp-microvolt = <850000 850000 1000000>, -+ <850000 850000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ opp-2208000000 { -+ opp-hz = /bits/ 64 <2208000000>; -+ opp-microvolt = <925000 925000 1000000>, -+ <925000 925000 1000000>; -+ clock-latency-ns = <40000>; -+ }; -+ }; -+ - cpus { - #address-cells = <1>; - #size-cells = <0>; -@@ -64,6 +275,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>; -@@ -83,6 +295,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>; -@@ -102,6 +315,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>; -@@ -121,6 +335,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>; -@@ -142,6 +357,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>; -@@ -161,6 +377,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>; -@@ -182,6 +399,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>; -@@ -201,6 +419,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>; -@@ -362,6 +581,235 @@ spll: clock-0 { - #clock-cells = <0>; - }; - -+ display_subsystem: display-subsystem { -+ compatible = "rockchip,display-subsystem"; -+ ports = <&vop_out>; -+ }; -+ -+ thermal_zones: thermal-zones { -+ soc_thermal: soc-thermal { -+ polling-delay-passive = <20>; /* milliseconds */ -+ polling-delay = <1000>; /* milliseconds */ -+ sustainable-power = <2100>; /* milliwatts */ -+ -+ thermal-sensors = <&tsadc 0>; -+ trips { -+ trip-point-0 { -+ temperature = <75000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ soc_target: trip-point-1 { -+ temperature = <85000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ trip-point-2 { -+ /* millicelsius */ -+ temperature = <115000>; -+ /* millicelsius */ -+ hysteresis = <2000>; -+ type = "critical"; -+ }; -+ }; -+ -+ cooling-maps { -+ map0 { -+ trip = <&soc_target>; -+ 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>, -+ <&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, -+ <&cpu_b1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, -+ <&cpu_b2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, -+ <&cpu_b3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; -+ contribution = <1024>; -+ }; -+ }; -+ }; -+ -+ bigcore0_thermal: bigcore0-thermal { -+ polling-delay-passive = <20>; /* milliseconds */ -+ polling-delay = <1000>; /* milliseconds */ -+ thermal-sensors = <&tsadc 1>; -+ -+ trips { -+ trip-point-0 { -+ temperature = <75000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ b0_target: trip-point-1 { -+ temperature = <85000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ trip-point-2 { -+ /* millicelsius */ -+ temperature = <115000>; -+ /* millicelsius */ -+ hysteresis = <2000>; -+ type = "critical"; -+ }; -+ }; -+ -+ cooling-maps { -+ map0 { -+ trip = <&b0_target>; -+ cooling-device = <&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, -+ <&cpu_b1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; -+ contribution = <1024>; -+ }; -+ }; -+ }; -+ -+ bigcore1_thermal: bigcore1-thermal { -+ polling-delay-passive = <20>; /* milliseconds */ -+ polling-delay = <1000>; /* milliseconds */ -+ thermal-sensors = <&tsadc 2>; -+ trips { -+ trip-point-0 { -+ temperature = <75000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ b1_target: trip-point-1 { -+ temperature = <85000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ trip-point-2 { -+ /* millicelsius */ -+ temperature = <115000>; -+ /* millicelsius */ -+ hysteresis = <2000>; -+ type = "critical"; -+ }; -+ }; -+ -+ cooling-maps { -+ map0 { -+ trip = <&b1_target>; -+ cooling-device = <&cpu_b2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, -+ <&cpu_b3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; -+ contribution = <1024>; -+ }; -+ }; -+ }; -+ -+ little_core_thermal: littlecore-thermal { -+ polling-delay-passive = <20>; /* milliseconds */ -+ polling-delay = <1000>; /* milliseconds */ -+ thermal-sensors = <&tsadc 3>; -+ trips { -+ trip-point-0 { -+ temperature = <75000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ l0_target: trip-point-1 { -+ temperature = <85000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ trip-point-2 { -+ /* millicelsius */ -+ temperature = <115000>; -+ /* millicelsius */ -+ hysteresis = <2000>; -+ type = "critical"; -+ }; -+ }; -+ -+ cooling-maps { -+ map0 { -+ trip = <&l0_target>; -+ 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>; -+ contribution = <1024>; -+ }; -+ }; -+ }; -+ -+ center_thermal: center-thermal { -+ polling-delay-passive = <20>; /* milliseconds */ -+ polling-delay = <1000>; /* milliseconds */ -+ thermal-sensors = <&tsadc 4>; -+ trips { -+ trip-point-0 { -+ temperature = <75000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ trip-point-1 { -+ temperature = <85000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ trip-point-2 { -+ /* millicelsius */ -+ temperature = <115000>; -+ /* millicelsius */ -+ hysteresis = <2000>; -+ type = "critical"; -+ }; -+ }; -+ }; -+ -+ gpu_thermal: gpu-thermal { -+ polling-delay-passive = <20>; /* milliseconds */ -+ polling-delay = <1000>; /* milliseconds */ -+ thermal-sensors = <&tsadc 5>; -+ trips { -+ trip-point-0 { -+ temperature = <75000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ trip-point-1 { -+ temperature = <85000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ trip-point-2 { -+ /* millicelsius */ -+ temperature = <115000>; -+ /* millicelsius */ -+ hysteresis = <2000>; -+ type = "critical"; -+ }; -+ }; -+ }; -+ -+ npu_thermal: npu-thermal { -+ polling-delay-passive = <20>; /* milliseconds */ -+ polling-delay = <1000>; /* milliseconds */ -+ thermal-sensors = <&tsadc 6>; -+ trips { -+ trip-point-0 { -+ temperature = <75000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ trip-point-1 { -+ temperature = <85000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ trip-point-2 { -+ /* millicelsius */ -+ temperature = <115000>; -+ /* millicelsius */ -+ hysteresis = <2000>; -+ type = "critical"; -+ }; -+ }; -+ }; -+ }; -+ - timer { - compatible = "arm,armv8-timer"; - interrupts = , -@@ -399,6 +847,28 @@ scmi_shmem: sram@0 { - }; - }; - -+ usb_host0_xhci: usb@fc000000 { -+ compatible = "rockchip,rk3588-dwc3", "snps,dwc3"; -+ reg = <0x0 0xfc000000 0x0 0x400000>; -+ interrupts = ; -+ clocks = <&cru REF_CLK_USB3OTG0>, <&cru SUSPEND_CLK_USB3OTG0>, -+ <&cru ACLK_USB3OTG0>; -+ clock-names = "ref_clk", "suspend_clk", "bus_clk"; -+ dr_mode = "otg"; -+ phys = <&u2phy0_otg>, <&usbdp_phy0_u3>; -+ phy-names = "usb2-phy", "usb3-phy"; -+ phy_type = "utmi_wide"; -+ power-domains = <&power RK3588_PD_USB>; -+ resets = <&cru SRST_A_USB3OTG0>; -+ snps,dis_enblslpm_quirk; -+ snps,dis-u1-entry-quirk; -+ snps,dis-u2-entry-quirk; -+ snps,dis-u2-freeclk-exists-quirk; -+ snps,dis-del-phy-power-chg-quirk; -+ snps,dis-tx-ipgap-linecheck-quirk; -+ status = "disabled"; -+ }; -+ - usb_host0_ehci: usb@fc800000 { - compatible = "rockchip,rk3588-ehci", "generic-ehci"; - reg = <0x0 0xfc800000 0x0 0x40000>; -@@ -474,6 +944,16 @@ sys_grf: syscon@fd58c000 { - reg = <0x0 0xfd58c000 0x0 0x1000>; - }; - -+ bigcore0_grf: syscon@fd590000 { -+ compatible = "rockchip,rk3588-bigcore0-grf", "syscon"; -+ reg = <0x0 0xfd590000 0x0 0x100>; -+ }; -+ -+ bigcore1_grf: syscon@fd592000 { -+ compatible = "rockchip,rk3588-bigcore1-grf", "syscon"; -+ reg = <0x0 0xfd592000 0x0 0x100>; -+ }; -+ - php_grf: syscon@fd5b0000 { - compatible = "rockchip,rk3588-php-grf", "syscon"; - reg = <0x0 0xfd5b0000 0x0 0x1000>; -@@ -489,6 +969,37 @@ pipe_phy2_grf: syscon@fd5c4000 { - reg = <0x0 0xfd5c4000 0x0 0x100>; - }; - -+ usbdpphy0_grf: syscon@fd5c8000 { -+ compatible = "rockchip,rk3588-usbdpphy-grf", "syscon"; -+ reg = <0x0 0xfd5c8000 0x0 0x4000>; -+ }; -+ -+ usb2phy0_grf: syscon@fd5d0000 { -+ compatible = "rockchip,rk3588-usb2phy-grf", "syscon", -+ "simple-mfd"; -+ reg = <0x0 0xfd5d0000 0x0 0x4000>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ u2phy0: usb2-phy@0 { -+ compatible = "rockchip,rk3588-usb2phy"; -+ reg = <0x0 0x10>; -+ interrupts = ; -+ resets = <&cru SRST_OTGPHY_U3_0>, <&cru SRST_P_USB2PHY_U3_0_GRF0>; -+ reset-names = "phy", "apb"; -+ clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>; -+ clock-names = "phyclk"; -+ clock-output-names = "usb480m_phy0"; -+ #clock-cells = <0>; -+ status = "disabled"; -+ -+ u2phy0_otg: otg-port { -+ #phy-cells = <0>; -+ status = "disabled"; -+ }; -+ }; -+ }; -+ - usb2phy2_grf: syscon@fd5d8000 { - compatible = "rockchip,rk3588-usb2phy-grf", "syscon", "simple-mfd"; - reg = <0x0 0xfd5d8000 0x0 0x4000>; -@@ -514,6 +1025,28 @@ u2phy2_host: host-port { - }; - }; - -+ vop_grf: syscon@fd5a4000 { -+ compatible = "rockchip,rk3588-vop-grf", "syscon"; -+ reg = <0x0 0xfd5a4000 0x0 0x2000>; -+ }; -+ -+ vo0_grf: syscon@fd5a6000 { -+ compatible = "rockchip,rk3588-vo-grf", "syscon"; -+ reg = <0x0 0xfd5a6000 0x0 0x2000>; -+ clocks = <&cru PCLK_VO0GRF>; -+ }; -+ -+ vo1_grf: syscon@fd5a8000 { -+ compatible = "rockchip,rk3588-vo-grf", "syscon"; -+ reg = <0x0 0xfd5a8000 0x0 0x100>; -+ clocks = <&cru PCLK_VO1GRF>; -+ }; -+ -+ usb_grf: syscon@fd5ac000 { -+ compatible = "rockchip,rk3588-usb-grf", "syscon"; -+ reg = <0x0 0xfd5ac000 0x0 0x4000>; -+ }; -+ - usb2phy3_grf: syscon@fd5dc000 { - compatible = "rockchip,rk3588-usb2phy-grf", "syscon", "simple-mfd"; - reg = <0x0 0xfd5dc000 0x0 0x4000>; -@@ -539,6 +1072,11 @@ u2phy3_host: host-port { - }; - }; - -+ hdptxphy0_grf: syscon@fd5e0000 { -+ compatible = "rockchip,rk3588-hdptxphy-grf", "syscon"; -+ reg = <0x0 0xfd5e0000 0x0 0x100>; -+ }; -+ - ioc: syscon@fd5f0000 { - compatible = "rockchip,rk3588-ioc", "syscon"; - reg = <0x0 0xfd5f0000 0x0 0x10000>; -@@ -962,6 +1500,112 @@ power-domain@RK3588_PD_SDMMC { - }; - }; - -+ vop: vop@fdd90000 { -+ compatible = "rockchip,rk3588-vop"; -+ reg = <0x0 0xfdd90000 0x0 0x4200>, <0x0 0xfdd95000 0x0 0x1000>; -+ reg-names = "vop", "gamma_lut"; -+ interrupts = ; -+ clocks = <&cru ACLK_VOP>, -+ <&cru HCLK_VOP>, -+ <&cru DCLK_VOP0>, -+ <&cru DCLK_VOP1>, -+ <&cru DCLK_VOP2>, -+ <&cru DCLK_VOP3>, -+ <&cru PCLK_VOP_ROOT>, -+ <&cru DCLK_VOP0_SRC>, -+ <&cru DCLK_VOP1_SRC>, -+ <&cru DCLK_VOP2_SRC>; -+ clock-names = "aclk", -+ "hclk", -+ "dclk_vp0", -+ "dclk_vp1", -+ "dclk_vp2", -+ "dclk_vp3", -+ "pclk", -+ "dclk_src_vp0", -+ "dclk_src_vp1", -+ "dclk_src_vp2"; -+ resets = <&cru SRST_A_VOP>, -+ <&cru SRST_H_VOP>, -+ <&cru SRST_D_VOP0>, -+ <&cru SRST_D_VOP1>, -+ <&cru SRST_D_VOP2>, -+ <&cru SRST_D_VOP3>; -+ reset-names = "axi", -+ "ahb", -+ "dclk_vp0", -+ "dclk_vp1", -+ "dclk_vp2", -+ "dclk_vp3"; -+ iommus = <&vop_mmu>; -+ power-domains = <&power RK3588_PD_VOP>; -+ rockchip,grf = <&sys_grf>; -+ rockchip,vop-grf = <&vop_grf>; -+ rockchip,vo1-grf = <&vo1_grf>; -+ rockchip,pmu = <&pmu>; -+ -+ status = "disabled"; -+ -+ // [CC: move endpoints to rock5b dts, see rock-3a] -+ vop_out: ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ vp0: port@0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ reg = <0>; -+ -+ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { -+ reg = ; -+ remote-endpoint = <&hdmi0_in_vp0>; -+ }; -+ }; -+ -+ vp1: port@1 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ reg = <1>; -+ -+ vp1_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { -+ reg = ; -+ remote-endpoint = <&hdmi0_in_vp1>; -+ }; -+ }; -+ -+ vp2: port@2 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ reg = <2>; -+ -+ assigned-clocks = <&cru DCLK_VOP2_SRC>; -+ assigned-clock-parents = <&cru PLL_V0PLL>; -+ -+ vp2_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { -+ reg = ; -+ remote-endpoint = <&hdmi0_in_vp2>; -+ }; -+ }; -+ -+ vp3: port@3 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ reg = <3>; -+ }; -+ }; -+ }; -+ -+ vop_mmu: iommu@fdd97e00 { -+ compatible = "rockchip,rk3568-iommu"; -+ reg = <0x0 0xfdd97e00 0x0 0x100>, <0x0 0xfdd97f00 0x0 0x100>; -+ interrupts = ; -+ interrupt-names = "vop_mmu"; -+ clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>; -+ clock-names = "aclk", "iface"; -+ #iommu-cells = <0>; -+ status = "disabled"; -+ }; -+ - i2s4_8ch: i2s@fddc0000 { - compatible = "rockchip,rk3588-i2s-tdm"; - reg = <0x0 0xfddc0000 0x0 0x1000>; -@@ -1013,6 +1657,77 @@ 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 DCLK_VOP0>, -+ <&cru DCLK_VOP1>, -+ <&cru DCLK_VOP2>, -+ <&cru DCLK_VOP3>, -+ <&cru HCLK_VO1>; -+ clock-names = "pclk", -+ "hpd", -+ "earc", -+ "hdmitx_ref", -+ "aud", -+ "dclk_vp0", -+ "dclk_vp1", -+ "dclk_vp2", -+ "dclk_vp3", -+ "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>; -+ reg-io-width = <4>; -+ rockchip,grf = <&sys_grf>; -+ rockchip,vo1_grf = <&vo1_grf>; -+ phys = <&hdptxphy_hdmi0>; -+ phy-names = "hdmi"; -+ #sound-dai-cells = <0>; -+ status = "disabled"; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ hdmi0_in: port@0 { -+ reg = <0>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ hdmi0_in_vp0: endpoint@0 { -+ reg = <0>; -+ remote-endpoint = <&vp0_out_hdmi0>; -+ status = "disabled"; -+ }; -+ -+ hdmi0_in_vp1: endpoint@1 { -+ reg = <1>; -+ remote-endpoint = <&vp1_out_hdmi0>; -+ status = "disabled"; -+ }; -+ -+ hdmi0_in_vp2: endpoint@2 { -+ reg = <2>; -+ remote-endpoint = <&vp2_out_hdmi0>; -+ status = "disabled"; -+ }; -+ }; -+ }; -+ }; -+ - qos_gpu_m0: qos@fdf35000 { - compatible = "rockchip,rk3588-qos", "syscon"; - reg = <0x0 0xfdf35000 0x0 0x20>; -@@ -2110,7 +2825,6 @@ tsadc: tsadc@fec00000 { - pinctrl-1 = <&tsadc_shut>; - pinctrl-names = "gpio", "otpout"; - #thermal-sensor-cells = <1>; -- status = "disabled"; - }; - - saradc: adc@fec10000 { -@@ -2245,6 +2959,58 @@ dmac2: dma-controller@fed10000 { - #dma-cells = <1>; - }; - -+ hdptxphy_hdmi0: hdmiphy@fed60000 { -+ compatible = "rockchip,rk3588-hdptx-phy-hdmi"; -+ reg = <0x0 0xfed60000 0x0 0x2000>; -+ clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>, <&cru PCLK_HDPTX0>; -+ clock-names = "ref", "apb"; -+ resets = <&cru SRST_HDPTX0>, <&cru SRST_P_HDPTX0>, -+ <&cru SRST_HDPTX0_INIT>, <&cru SRST_HDPTX0_CMN>, -+ <&cru SRST_HDPTX0_LANE>, <&cru SRST_HDPTX0_ROPLL>, -+ <&cru SRST_HDPTX0_LCPLL>; -+ reset-names = "phy", "apb", "init", "cmn", "lane", "ropll", -+ "lcpll"; -+ rockchip,grf = <&hdptxphy0_grf>; -+ #phy-cells = <0>; -+ status = "disabled"; -+ -+ hdptxphy_hdmi_clk0: clk-port { -+ #clock-cells = <0>; -+ status = "disabled"; -+ }; -+ }; -+ -+ usbdp_phy0: phy@fed80000 { -+ compatible = "rockchip,rk3588-usbdp-phy"; -+ reg = <0x0 0xfed80000 0x0 0x10000>; -+ rockchip,u2phy-grf = <&usb2phy0_grf>; -+ rockchip,usb-grf = <&usb_grf>; -+ rockchip,usbdpphy-grf = <&usbdpphy0_grf>; -+ rockchip,vo-grf = <&vo0_grf>; -+ clocks = <&cru CLK_USBDPPHY_MIPIDCPPHY_REF>, -+ <&cru CLK_USBDP_PHY0_IMMORTAL>, -+ <&cru PCLK_USBDPPHY0>, -+ <&u2phy0>; -+ clock-names = "refclk", "immortal", "pclk", "utmi"; -+ resets = <&cru SRST_USBDP_COMBO_PHY0_INIT>, -+ <&cru SRST_USBDP_COMBO_PHY0_CMN>, -+ <&cru SRST_USBDP_COMBO_PHY0_LANE>, -+ <&cru SRST_USBDP_COMBO_PHY0_PCS>, -+ <&cru SRST_P_USBDPPHY0>; -+ reset-names = "init", "cmn", "lane", "pcs_apb", "pma_apb"; -+ status = "disabled"; -+ -+ usbdp_phy0_dp: dp-port { -+ #phy-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ usbdp_phy0_u3: usb3-port { -+ #phy-cells = <0>; -+ status = "disabled"; -+ }; -+ }; -+ - combphy0_ps: phy@fee00000 { - compatible = "rockchip,rk3588-naneng-combphy"; - reg = <0x0 0xfee00000 0x0 0x100>; -diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig -index b60aa1f89..906f2f21a 100644 ---- a/arch/arm64/configs/defconfig -+++ b/arch/arm64/configs/defconfig -@@ -1449,8 +1449,9 @@ CONFIG_PHY_ROCKCHIP_EMMC=y - CONFIG_PHY_ROCKCHIP_INNO_HDMI=m - CONFIG_PHY_ROCKCHIP_INNO_USB2=y - CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY=m --CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY=m -+CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY=y - CONFIG_PHY_ROCKCHIP_PCIE=m -+CONFIG_PHY_ROCKCHIP_SAMSUNG_HDPTX_HDMI=m - CONFIG_PHY_ROCKCHIP_SNPS_PCIE3=y - CONFIG_PHY_ROCKCHIP_TYPEC=y - CONFIG_PHY_SAMSUNG_UFS=y -diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c -index 66759fe28..478a4e594 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) { -diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c -index a2c2b5203..94b4fb66a 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; -diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c -index 6994165e0..c6b605d6d 100644 ---- a/drivers/clk/rockchip/clk-rk3588.c -+++ b/drivers/clk/rockchip/clk-rk3588.c -@@ -1851,8 +1851,6 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { - RK3588_CLKGATE_CON(56), 0, GFLAGS), - GATE(PCLK_TRNG0, "pclk_trng0", "pclk_vo0_root", 0, - RK3588_CLKGATE_CON(56), 1, GFLAGS), -- GATE(PCLK_VO0GRF, "pclk_vo0grf", "pclk_vo0_root", CLK_IGNORE_UNUSED, -- RK3588_CLKGATE_CON(55), 10, GFLAGS), - COMPOSITE(CLK_I2S4_8CH_TX_SRC, "clk_i2s4_8ch_tx_src", gpll_aupll_p, 0, - RK3588_CLKSEL_CON(118), 5, 1, MFLAGS, 0, 5, DFLAGS, - RK3588_CLKGATE_CON(56), 11, GFLAGS), -@@ -1998,8 +1996,6 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { - RK3588_CLKGATE_CON(60), 9, GFLAGS), - GATE(PCLK_TRNG1, "pclk_trng1", "pclk_vo1_root", 0, - RK3588_CLKGATE_CON(60), 10, GFLAGS), -- GATE(0, "pclk_vo1grf", "pclk_vo1_root", CLK_IGNORE_UNUSED, -- RK3588_CLKGATE_CON(59), 12, GFLAGS), - GATE(PCLK_S_EDP0, "pclk_s_edp0", "pclk_vo1_s_root", 0, - RK3588_CLKGATE_CON(59), 14, GFLAGS), - GATE(PCLK_S_EDP1, "pclk_s_edp1", "pclk_vo1_s_root", 0, -@@ -2447,12 +2443,15 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { - 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", 0, RK3588_CLKGATE_CON(55), 5, GFLAGS), -+ GATE_LINK(HCLK_VO0, "hclk_vo0", "hclk_vo0_root", "hclk_vop_root", RK3588_LINKED_CLK, 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", 0, RK3588_CLKGATE_CON(59), 9, 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(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), -+ GATE_LINK(PCLK_VO0GRF, "pclk_vo0grf", "pclk_vo0_root", "hclk_vo0", CLK_IGNORE_UNUSED, RK3588_CLKGATE_CON(55), 10, GFLAGS), -+ 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) -diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm -index f91160689..1e2552108 100644 ---- a/drivers/cpufreq/Kconfig.arm -+++ b/drivers/cpufreq/Kconfig.arm -@@ -189,6 +189,16 @@ config ARM_RASPBERRYPI_CPUFREQ - - If in doubt, say N. - -+config ARM_ROCKCHIP_CPUFREQ -+ tristate "Rockchip CPUfreq driver" -+ depends on ARCH_ROCKCHIP && CPUFREQ_DT -+ select PM_OPP -+ help -+ This adds the CPUFreq driver support for Rockchip SoCs, -+ based on cpufreq-dt. -+ -+ If in doubt, say N. -+ - config ARM_S3C64XX_CPUFREQ - bool "Samsung S3C64XX" - depends on CPU_S3C6410 -diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile -index 8d141c71b..14fb48863 100644 ---- a/drivers/cpufreq/Makefile -+++ b/drivers/cpufreq/Makefile -@@ -71,6 +71,7 @@ obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o - obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o - obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.o - obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o -+obj-$(CONFIG_ARM_ROCKCHIP_CPUFREQ) += rockchip-cpufreq.o - obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o - obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o - obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o -diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c -index bd1e1357c..cfd35aa52 100644 ---- a/drivers/cpufreq/cpufreq-dt-platdev.c -+++ b/drivers/cpufreq/cpufreq-dt-platdev.c -@@ -168,6 +168,8 @@ static const struct of_device_id blocklist[] __initconst = { - { .compatible = "qcom,sm8450", }, - { .compatible = "qcom,sm8550", }, - -+ { .compatible = "rockchip,rk3588", }, -+ - { .compatible = "st,stih407", }, - { .compatible = "st,stih410", }, - { .compatible = "st,stih418", }, -diff --git a/drivers/cpufreq/rockchip-cpufreq.c b/drivers/cpufreq/rockchip-cpufreq.c -new file mode 100644 -index 000000000..0bf57ac85 ---- /dev/null -+++ b/drivers/cpufreq/rockchip-cpufreq.c -@@ -0,0 +1,645 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Rockchip CPUFreq Driver. This is similar to the generic DT -+ * cpufreq driver, but handles the following platform specific -+ * quirks: -+ * -+ * * support for two regulators - one for the CPU core and one -+ * for the memory interface -+ * * reboot handler to setup the reboot frequency -+ * * handling of read margin registers -+ * -+ * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd -+ * Copyright (C) 2023 Collabora Ltd. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "cpufreq-dt.h" -+ -+#define RK3588_MEMCFG_HSSPRF_LOW 0x20 -+#define RK3588_MEMCFG_HSDPRF_LOW 0x28 -+#define RK3588_MEMCFG_HSDPRF_HIGH 0x2c -+#define RK3588_CPU_CTRL 0x30 -+ -+#define VOLT_RM_TABLE_END ~1 -+ -+static struct platform_device *cpufreq_pdev; -+static LIST_HEAD(priv_list); -+ -+struct volt_rm_table { -+ uint32_t volt; -+ uint32_t rm; -+}; -+ -+struct rockchip_opp_info { -+ const struct rockchip_opp_data *data; -+ struct volt_rm_table *volt_rm_tbl; -+ struct regmap *grf; -+ u32 current_rm; -+ u32 reboot_freq; -+}; -+ -+struct private_data { -+ struct list_head node; -+ -+ cpumask_var_t cpus; -+ struct device *cpu_dev; -+ struct cpufreq_frequency_table *freq_table; -+}; -+ -+struct rockchip_opp_data { -+ int (*set_read_margin)(struct device *dev, struct rockchip_opp_info *opp_info, -+ unsigned long volt); -+}; -+ -+struct cluster_info { -+ struct list_head list_head; -+ struct rockchip_opp_info opp_info; -+ cpumask_t cpus; -+}; -+static LIST_HEAD(cluster_info_list); -+ -+static int rk3588_cpu_set_read_margin(struct device *dev, struct rockchip_opp_info *opp_info, -+ unsigned long volt) -+{ -+ bool is_found = false; -+ u32 rm; -+ int i; -+ -+ if (!opp_info->volt_rm_tbl) -+ return 0; -+ -+ for (i = 0; opp_info->volt_rm_tbl[i].rm != VOLT_RM_TABLE_END; i++) { -+ if (volt >= opp_info->volt_rm_tbl[i].volt) { -+ rm = opp_info->volt_rm_tbl[i].rm; -+ is_found = true; -+ break; -+ } -+ } -+ -+ if (!is_found) -+ return 0; -+ if (rm == opp_info->current_rm) -+ return 0; -+ if (!opp_info->grf) -+ return 0; -+ -+ dev_dbg(dev, "set rm to %d\n", rm); -+ regmap_write(opp_info->grf, RK3588_MEMCFG_HSSPRF_LOW, 0x001c0000 | (rm << 2)); -+ regmap_write(opp_info->grf, RK3588_MEMCFG_HSDPRF_LOW, 0x003c0000 | (rm << 2)); -+ regmap_write(opp_info->grf, RK3588_MEMCFG_HSDPRF_HIGH, 0x003c0000 | (rm << 2)); -+ regmap_write(opp_info->grf, RK3588_CPU_CTRL, 0x00200020); -+ udelay(1); -+ regmap_write(opp_info->grf, RK3588_CPU_CTRL, 0x00200000); -+ -+ opp_info->current_rm = rm; -+ -+ return 0; -+} -+ -+static const struct rockchip_opp_data rk3588_cpu_opp_data = { -+ .set_read_margin = rk3588_cpu_set_read_margin, -+}; -+ -+static const struct of_device_id rockchip_cpufreq_of_match[] = { -+ { -+ .compatible = "rockchip,rk3588", -+ .data = (void *)&rk3588_cpu_opp_data, -+ }, -+ {}, -+}; -+ -+static struct cluster_info *rockchip_cluster_info_lookup(int cpu) -+{ -+ struct cluster_info *cluster; -+ -+ list_for_each_entry(cluster, &cluster_info_list, list_head) { -+ if (cpumask_test_cpu(cpu, &cluster->cpus)) -+ return cluster; -+ } -+ -+ return NULL; -+} -+ -+static int rockchip_cpufreq_set_volt(struct device *dev, -+ struct regulator *reg, -+ struct dev_pm_opp_supply *supply) -+{ -+ int ret; -+ -+ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min, -+ supply->u_volt, supply->u_volt_max); -+ if (ret) -+ dev_err(dev, "%s: failed to set voltage (%lu %lu %lu uV): %d\n", -+ __func__, supply->u_volt_min, supply->u_volt, -+ supply->u_volt_max, ret); -+ -+ return ret; -+} -+ -+static int rockchip_cpufreq_set_read_margin(struct device *dev, -+ struct rockchip_opp_info *opp_info, -+ unsigned long volt) -+{ -+ if (opp_info->data && opp_info->data->set_read_margin) { -+ opp_info->data->set_read_margin(dev, opp_info, volt); -+ } -+ -+ return 0; -+} -+ -+static int rk_opp_config_regulators(struct device *dev, -+ struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp, -+ struct regulator **regulators, unsigned int count) -+{ -+ struct dev_pm_opp_supply old_supplies[2]; -+ struct dev_pm_opp_supply new_supplies[2]; -+ struct regulator *vdd_reg = regulators[0]; -+ struct regulator *mem_reg = regulators[1]; -+ struct rockchip_opp_info *opp_info; -+ struct cluster_info *cluster; -+ int ret = 0; -+ unsigned long old_freq = dev_pm_opp_get_freq(old_opp); -+ unsigned long new_freq = dev_pm_opp_get_freq(new_opp); -+ -+ /* We must have two regulators here */ -+ WARN_ON(count != 2); -+ -+ ret = dev_pm_opp_get_supplies(old_opp, old_supplies); -+ if (ret) -+ return ret; -+ -+ ret = dev_pm_opp_get_supplies(new_opp, new_supplies); -+ if (ret) -+ return ret; -+ -+ cluster = rockchip_cluster_info_lookup(dev->id); -+ if (!cluster) -+ return -EINVAL; -+ opp_info = &cluster->opp_info; -+ -+ if (new_freq >= old_freq) { -+ ret = rockchip_cpufreq_set_volt(dev, mem_reg, &new_supplies[1]); -+ if (ret) -+ goto error; -+ ret = rockchip_cpufreq_set_volt(dev, vdd_reg, &new_supplies[0]); -+ if (ret) -+ goto error; -+ rockchip_cpufreq_set_read_margin(dev, opp_info, new_supplies[0].u_volt); -+ } else { -+ rockchip_cpufreq_set_read_margin(dev, opp_info, new_supplies[0].u_volt); -+ ret = rockchip_cpufreq_set_volt(dev, vdd_reg, &new_supplies[0]); -+ if (ret) -+ goto error; -+ ret = rockchip_cpufreq_set_volt(dev, mem_reg, &new_supplies[1]); -+ if (ret) -+ goto error; -+ } -+ -+ return 0; -+ -+error: -+ rockchip_cpufreq_set_read_margin(dev, opp_info, old_supplies[0].u_volt); -+ rockchip_cpufreq_set_volt(dev, mem_reg, &old_supplies[1]); -+ rockchip_cpufreq_set_volt(dev, vdd_reg, &old_supplies[0]); -+ return ret; -+} -+ -+static void rockchip_get_opp_data(const struct of_device_id *matches, -+ struct rockchip_opp_info *info) -+{ -+ const struct of_device_id *match; -+ struct device_node *node; -+ -+ node = of_find_node_by_path("/"); -+ match = of_match_node(matches, node); -+ if (match && match->data) -+ info->data = match->data; -+ of_node_put(node); -+} -+ -+static int rockchip_get_volt_rm_table(struct device *dev, struct device_node *np, -+ char *porp_name, struct volt_rm_table **table) -+{ -+ struct volt_rm_table *rm_table; -+ const struct property *prop; -+ int count, i; -+ -+ prop = of_find_property(np, porp_name, NULL); -+ if (!prop) -+ return -EINVAL; -+ -+ if (!prop->value) -+ return -ENODATA; -+ -+ count = of_property_count_u32_elems(np, porp_name); -+ if (count < 0) -+ return -EINVAL; -+ -+ if (count % 2) -+ return -EINVAL; -+ -+ rm_table = devm_kzalloc(dev, sizeof(*rm_table) * (count / 2 + 1), -+ GFP_KERNEL); -+ if (!rm_table) -+ return -ENOMEM; -+ -+ for (i = 0; i < count / 2; i++) { -+ of_property_read_u32_index(np, porp_name, 2 * i, -+ &rm_table[i].volt); -+ of_property_read_u32_index(np, porp_name, 2 * i + 1, -+ &rm_table[i].rm); -+ } -+ -+ rm_table[i].volt = 0; -+ rm_table[i].rm = VOLT_RM_TABLE_END; -+ -+ *table = rm_table; -+ -+ return 0; -+} -+ -+static int rockchip_cpufreq_reboot(struct notifier_block *notifier, unsigned long event, void *cmd) -+{ -+ struct cluster_info *cluster; -+ struct device *dev; -+ int freq, ret, cpu; -+ -+ if (event != SYS_RESTART) -+ return NOTIFY_DONE; -+ -+ for_each_possible_cpu(cpu) { -+ cluster = rockchip_cluster_info_lookup(cpu); -+ if (!cluster) -+ continue; -+ -+ dev = get_cpu_device(cpu); -+ if (!dev) -+ continue; -+ -+ freq = cluster->opp_info.reboot_freq; -+ -+ if (freq) { -+ ret = dev_pm_opp_set_rate(dev, freq); -+ if (ret) -+ dev_err(dev, "Failed setting reboot freq for cpu %d to %d: %d\n", -+ cpu, freq, ret); -+ dev_pm_opp_remove_table(dev); -+ } -+ } -+ -+ return NOTIFY_DONE; -+} -+ -+static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster) -+{ -+ struct rockchip_opp_info *opp_info = &cluster->opp_info; -+ int reg_table_token = -EINVAL; -+ int opp_table_token = -EINVAL; -+ struct device_node *np; -+ struct device *dev; -+ const char * const reg_names[] = { "cpu", "mem", NULL }; -+ int ret = 0; -+ -+ dev = get_cpu_device(cpu); -+ if (!dev) -+ return -ENODEV; -+ -+ if (!of_find_property(dev->of_node, "cpu-supply", NULL)) -+ return -ENOENT; -+ -+ np = of_parse_phandle(dev->of_node, "operating-points-v2", 0); -+ if (!np) { -+ dev_warn(dev, "OPP-v2 not supported\n"); -+ return -ENOENT; -+ } -+ -+ reg_table_token = dev_pm_opp_set_regulators(dev, reg_names); -+ if (reg_table_token < 0) { -+ ret = reg_table_token; -+ dev_err_probe(dev, ret, "Failed to set opp regulators\n"); -+ goto np_err; -+ } -+ -+ ret = dev_pm_opp_of_get_sharing_cpus(dev, &cluster->cpus); -+ if (ret) { -+ dev_err_probe(dev, ret, "Failed to get sharing cpus\n"); -+ goto np_err; -+ } -+ -+ rockchip_get_opp_data(rockchip_cpufreq_of_match, opp_info); -+ if (opp_info->data && opp_info->data->set_read_margin) { -+ opp_info->current_rm = UINT_MAX; -+ opp_info->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); -+ if (IS_ERR(opp_info->grf)) -+ opp_info->grf = NULL; -+ rockchip_get_volt_rm_table(dev, np, "rockchip,volt-mem-read-margin", &opp_info->volt_rm_tbl); -+ -+ of_property_read_u32(np, "rockchip,reboot-freq", &opp_info->reboot_freq); -+ } -+ -+ opp_table_token = dev_pm_opp_set_config_regulators(dev, rk_opp_config_regulators); -+ if (opp_table_token < 0) { -+ ret = opp_table_token; -+ dev_err(dev, "Failed to set opp config regulators\n"); -+ goto reg_opp_table; -+ } -+ -+ of_node_put(np); -+ -+ return 0; -+ -+reg_opp_table: -+ if (reg_table_token >= 0) -+ dev_pm_opp_put_regulators(reg_table_token); -+np_err: -+ of_node_put(np); -+ -+ return ret; -+} -+ -+static struct notifier_block rockchip_cpufreq_reboot_notifier = { -+ .notifier_call = rockchip_cpufreq_reboot, -+ .priority = 0, -+}; -+ -+static struct freq_attr *cpufreq_rockchip_attr[] = { -+ &cpufreq_freq_attr_scaling_available_freqs, -+ NULL, -+}; -+ -+static int cpufreq_online(struct cpufreq_policy *policy) -+{ -+ /* We did light-weight tear down earlier, nothing to do here */ -+ return 0; -+} -+ -+static int cpufreq_offline(struct cpufreq_policy *policy) -+{ -+ /* -+ * Preserve policy->driver_data and don't free resources on light-weight -+ * tear down. -+ */ -+ return 0; -+} -+ -+static struct private_data *rockchip_cpufreq_find_data(int cpu) -+{ -+ struct private_data *priv; -+ -+ list_for_each_entry(priv, &priv_list, node) { -+ if (cpumask_test_cpu(cpu, priv->cpus)) -+ return priv; -+ } -+ -+ return NULL; -+} -+ -+static int cpufreq_init(struct cpufreq_policy *policy) -+{ -+ struct private_data *priv; -+ struct device *cpu_dev; -+ struct clk *cpu_clk; -+ unsigned int transition_latency; -+ int ret; -+ -+ priv = rockchip_cpufreq_find_data(policy->cpu); -+ if (!priv) { -+ pr_err("failed to find data for cpu%d\n", policy->cpu); -+ return -ENODEV; -+ } -+ cpu_dev = priv->cpu_dev; -+ -+ cpu_clk = clk_get(cpu_dev, NULL); -+ if (IS_ERR(cpu_clk)) { -+ ret = PTR_ERR(cpu_clk); -+ dev_err(cpu_dev, "%s: failed to get clk: %d\n", __func__, ret); -+ return ret; -+ } -+ -+ transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev); -+ if (!transition_latency) -+ transition_latency = CPUFREQ_ETERNAL; -+ -+ cpumask_copy(policy->cpus, priv->cpus); -+ policy->driver_data = priv; -+ policy->clk = cpu_clk; -+ policy->freq_table = priv->freq_table; -+ policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000; -+ policy->cpuinfo.transition_latency = transition_latency; -+ policy->dvfs_possible_from_any_cpu = true; -+ -+ return 0; -+} -+ -+static int cpufreq_exit(struct cpufreq_policy *policy) -+{ -+ clk_put(policy->clk); -+ return 0; -+} -+ -+static int set_target(struct cpufreq_policy *policy, unsigned int index) -+{ -+ struct private_data *priv = policy->driver_data; -+ unsigned long freq = policy->freq_table[index].frequency; -+ -+ return dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000); -+} -+ -+static struct cpufreq_driver rockchip_cpufreq_driver = { -+ .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK | -+ CPUFREQ_IS_COOLING_DEV | -+ CPUFREQ_HAVE_GOVERNOR_PER_POLICY, -+ .verify = cpufreq_generic_frequency_table_verify, -+ .target_index = set_target, -+ .get = cpufreq_generic_get, -+ .init = cpufreq_init, -+ .exit = cpufreq_exit, -+ .online = cpufreq_online, -+ .offline = cpufreq_offline, -+ .register_em = cpufreq_register_em_with_opp, -+ .name = "rockchip-cpufreq", -+ .attr = cpufreq_rockchip_attr, -+ .suspend = cpufreq_generic_suspend, -+}; -+ -+static int rockchip_cpufreq_init(struct device *dev, int cpu) -+{ -+ struct private_data *priv; -+ struct device *cpu_dev; -+ int ret; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ if (!alloc_cpumask_var(&priv->cpus, GFP_KERNEL)) -+ return -ENOMEM; -+ -+ cpumask_set_cpu(cpu, priv->cpus); -+ -+ cpu_dev = get_cpu_device(cpu); -+ if (!cpu_dev) -+ return -EPROBE_DEFER; -+ priv->cpu_dev = cpu_dev; -+ -+ ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, priv->cpus); -+ if (ret) -+ return ret; -+ -+ ret = dev_pm_opp_of_cpumask_add_table(priv->cpus); -+ if (ret) -+ return ret; -+ -+ ret = dev_pm_opp_get_opp_count(cpu_dev); -+ if (ret <= 0) -+ return dev_err_probe(cpu_dev, -ENODEV, "OPP table can't be empty\n"); -+ -+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &priv->freq_table); -+ if (ret) -+ return dev_err_probe(cpu_dev, ret, "failed to init cpufreq table\n"); -+ -+ list_add(&priv->node, &priv_list); -+ -+ return 0; -+} -+ -+static void rockchip_cpufreq_free_list(void *data) -+{ -+ struct cluster_info *cluster, *pos; -+ -+ list_for_each_entry_safe(cluster, pos, &cluster_info_list, list_head) { -+ list_del(&cluster->list_head); -+ } -+} -+ -+static int rockchip_cpufreq_init_list(struct device *dev) -+{ -+ struct cluster_info *cluster; -+ int cpu, ret; -+ -+ for_each_possible_cpu(cpu) { -+ cluster = rockchip_cluster_info_lookup(cpu); -+ if (cluster) -+ continue; -+ -+ cluster = devm_kzalloc(dev, sizeof(*cluster), GFP_KERNEL); -+ if (!cluster) { -+ ret = -ENOMEM; -+ goto release_cluster_info; -+ } -+ -+ ret = rockchip_cpufreq_cluster_init(cpu, cluster); -+ if (ret) { -+ dev_err_probe(dev, ret, "Failed to initialize dvfs info cpu%d\n", cpu); -+ goto release_cluster_info; -+ } -+ list_add(&cluster->list_head, &cluster_info_list); -+ } -+ -+ return 0; -+ -+release_cluster_info: -+ rockchip_cpufreq_free_list(NULL); -+ return ret; -+} -+ -+static void rockchip_cpufreq_unregister(void *data) -+{ -+ cpufreq_unregister_driver(&rockchip_cpufreq_driver); -+} -+ -+static int rockchip_cpufreq_probe(struct platform_device *pdev) -+{ -+ int ret, cpu; -+ -+ ret = rockchip_cpufreq_init_list(&pdev->dev); -+ if (ret) -+ return ret; -+ -+ ret = devm_add_action_or_reset(&pdev->dev, rockchip_cpufreq_free_list, NULL); -+ if (ret) -+ return ret; -+ -+ ret = devm_register_reboot_notifier(&pdev->dev, &rockchip_cpufreq_reboot_notifier); -+ if (ret) -+ return dev_err_probe(&pdev->dev, ret, "Failed to register reboot handler\n"); -+ -+ for_each_possible_cpu(cpu) { -+ ret = rockchip_cpufreq_init(&pdev->dev, cpu); -+ if (ret) -+ return ret; -+ } -+ -+ ret = cpufreq_register_driver(&rockchip_cpufreq_driver); -+ if (ret) -+ return dev_err_probe(&pdev->dev, ret, "failed register driver\n"); -+ -+ ret = devm_add_action_or_reset(&pdev->dev, rockchip_cpufreq_unregister, NULL); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static struct platform_driver rockchip_cpufreq_platdrv = { -+ .driver = { -+ .name = "rockchip-cpufreq", -+ }, -+ .probe = rockchip_cpufreq_probe, -+}; -+ -+static int __init rockchip_cpufreq_driver_init(void) -+{ -+ int ret; -+ -+ if (!of_machine_is_compatible("rockchip,rk3588") && -+ !of_machine_is_compatible("rockchip,rk3588s")) { -+ return -ENODEV; -+ } -+ -+ ret = platform_driver_register(&rockchip_cpufreq_platdrv); -+ if (ret) -+ return ret; -+ -+ cpufreq_pdev = platform_device_register_data(NULL, "rockchip-cpufreq", -1, -+ NULL, 0); -+ if (IS_ERR(cpufreq_pdev)) { -+ pr_err("failed to register rockchip-cpufreq platform device\n"); -+ ret = PTR_ERR(cpufreq_pdev); -+ goto unregister_platform_driver; -+ } -+ -+ return 0; -+ -+unregister_platform_driver: -+ platform_driver_unregister(&rockchip_cpufreq_platdrv); -+ return ret; -+} -+module_init(rockchip_cpufreq_driver_init); -+ -+static void __exit rockchip_cpufreq_driver_exit(void) -+{ -+ platform_device_unregister(cpufreq_pdev); -+ platform_driver_unregister(&rockchip_cpufreq_platdrv); -+} -+module_exit(rockchip_cpufreq_driver_exit) -+ -+MODULE_AUTHOR("Finley Xiao "); -+MODULE_DESCRIPTION("Rockchip cpufreq driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile b/drivers/gpu/drm/bridge/synopsys/Makefile -index ce715562e..8354e4879 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 000000000..935b116c2 ---- /dev/null -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c -@@ -0,0 +1,2997 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) Rockchip Electronics Co.Ltd -+ * Author: -+ * Algea Cao -+ */ -+#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 "dw-hdmi-qp.h" -+// #include "dw-hdmi-qp-audio.h" -+// #include "dw-hdmi-qp-cec.h" -+ -+#include -+ -+#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 -+#define HDMI20_MAX_TMDSCLK_KHZ 600000 -+ -+static const unsigned int dw_hdmi_cable[] = { -+ EXTCON_DISP_HDMI, -+ EXTCON_NONE, -+}; -+ -+static const struct drm_display_mode dw_hdmi_default_modes[] = { -+ /* 16 - 1920x1080@60Hz 16:9 */ -+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, -+ 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, -+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), -+ .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, -+ /* 2 - 720x480@60Hz 4:3 */ -+ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, -+ 798, 858, 0, 480, 489, 495, 525, 0, -+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), -+ .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, -+ /* 4 - 1280x720@60Hz 16:9 */ -+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, -+ 1430, 1650, 0, 720, 725, 730, 750, 0, -+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), -+ .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, -+ /* 31 - 1920x1080@50Hz 16:9 */ -+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, -+ 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, -+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), -+ .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, -+ /* 19 - 1280x720@50Hz 16:9 */ -+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, -+ 1760, 1980, 0, 720, 725, 730, 750, 0, -+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), -+ .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, -+ /* 17 - 720x576@50Hz 4:3 */ -+ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, -+ 796, 864, 0, 576, 581, 586, 625, 0, -+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), -+ .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, -+ /* 2 - 720x480@60Hz 4:3 */ -+ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, -+ 798, 858, 0, 480, 489, 495, 525, 0, -+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), -+ .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, -+}; -+ -+enum frl_mask { -+ FRL_3GBPS_3LANE = 1, -+ FRL_6GBPS_3LANE, -+ FRL_6GBPS_4LANE, -+ FRL_8GBPS_4LANE, -+ FRL_10GBPS_4LANE, -+ FRL_12GBPS_4LANE, -+}; -+ -+struct hdmi_vmode_qp { -+ bool mdataenablepolarity; -+ -+ unsigned int previous_pixelclock; -+ unsigned long mpixelclock; -+ unsigned int mpixelrepetitioninput; -+ unsigned int mpixelrepetitionoutput; -+ unsigned long previous_tmdsclock; -+ unsigned int mtmdsclock; -+}; -+ -+struct hdmi_qp_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 quant_range; -+ unsigned int pix_repet_factor; -+ struct hdmi_vmode_qp video_mode; -+ bool update; -+}; -+ -+struct dw_hdmi_qp_i2c { -+ struct i2c_adapter adap; -+ -+ struct mutex lock; /* used to serialize data transfers */ -+ struct completion cmp; -+ u32 stat; -+ -+ u8 slave_reg; -+ bool is_regaddr; -+ bool is_segment; -+ -+ unsigned int scl_high_ns; -+ unsigned int scl_low_ns; -+}; -+ -+// 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_qp *hdmi, -+// const struct dw_hdmi_plat_data *pdata, -+// unsigned long mpixelclock); -+// }; -+ -+struct dw_hdmi_qp { -+ struct drm_connector connector; -+ struct drm_bridge bridge; -+ struct platform_device *hdcp_dev; -+ struct platform_device *audio; -+ struct platform_device *cec; -+ struct device *dev; -+ struct dw_hdmi_qp_i2c *i2c; -+ -+ struct hdmi_qp_data_info hdmi_data; -+ const struct dw_hdmi_plat_data *plat_data; -+ -+ int vic; -+ int main_irq; -+ int avp_irq; -+ int earc_irq; -+ -+ u8 edid[HDMI_EDID_LEN]; -+ -+ struct { -+ const struct dw_hdmi_qp_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; -+ bool dclk_en; -+ -+ struct mutex mutex; /* for state below and previous_mode */ -+ //[CC:] curr_conn should be removed -+ struct drm_connector *curr_conn;/* current connector (only valid when !disabled) */ -+ enum drm_connector_force force; /* mutex-protected force state */ -+ 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 */ -+ -+ u32 scdc_intr; -+ u32 flt_intr; -+ u32 earc_intr; -+ -+ struct mutex audio_mutex; -+ unsigned int sample_rate; -+ unsigned int audio_cts; -+ unsigned int audio_n; -+ bool audio_enable; -+ void (*enable_audio)(struct dw_hdmi_qp *hdmi); -+ void (*disable_audio)(struct dw_hdmi_qp *hdmi); -+ -+ struct dentry *debugfs_dir; -+ bool scramble_low_rates; -+ -+ struct extcon_dev *extcon; -+ -+ struct regmap *regm; -+ -+ bool initialized; /* hdmi is enabled before bind */ -+ struct completion flt_cmp; -+ struct completion earc_cmp; -+ -+ struct cec_notifier *cec_notifier; -+ struct cec_adapter *cec_adap; -+ struct mutex cec_notifier_mutex; -+ -+ hdmi_codec_plugged_cb plugged_cb; -+ struct device *codec_dev; -+ enum drm_connector_status last_connector_result; -+}; -+ -+static inline void hdmi_writel(struct dw_hdmi_qp *hdmi, u32 val, int offset) -+{ -+ regmap_write(hdmi->regm, offset, val); -+} -+ -+static inline u32 hdmi_readl(struct dw_hdmi_qp *hdmi, int offset) -+{ -+ unsigned int val = 0; -+ -+ regmap_read(hdmi->regm, offset, &val); -+ -+ return val; -+} -+ -+static void handle_plugged_change(struct dw_hdmi_qp *hdmi, bool plugged) -+{ -+ if (hdmi->plugged_cb && hdmi->codec_dev) -+ hdmi->plugged_cb(hdmi->codec_dev, plugged); -+} -+ -+int dw_hdmi_qp_set_plugged_cb(struct dw_hdmi_qp *hdmi, hdmi_codec_plugged_cb fn, -+ struct device *codec_dev) -+{ -+ bool plugged; -+ -+ mutex_lock(&hdmi->mutex); -+ hdmi->plugged_cb = fn; -+ hdmi->codec_dev = codec_dev; -+ plugged = hdmi->last_connector_result == connector_status_connected; -+ handle_plugged_change(hdmi, plugged); -+ mutex_unlock(&hdmi->mutex); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_plugged_cb); -+ -+static void hdmi_modb(struct dw_hdmi_qp *hdmi, u32 data, u32 mask, u32 reg) -+{ -+ regmap_update_bits(hdmi->regm, reg, mask, data); -+} -+ -+static void hdmi_set_cts_n(struct dw_hdmi_qp *hdmi, unsigned int cts, -+ unsigned int n) -+{ -+ /* Set N */ -+ hdmi_modb(hdmi, n, AUDPKT_ACR_N_VALUE, AUDPKT_ACR_CONTROL0); -+ -+ /* Set CTS */ -+ if (cts) -+ hdmi_modb(hdmi, AUDPKT_ACR_CTS_OVR_EN, AUDPKT_ACR_CTS_OVR_EN_MSK, -+ AUDPKT_ACR_CONTROL1); -+ else -+ hdmi_modb(hdmi, 0, AUDPKT_ACR_CTS_OVR_EN_MSK, -+ AUDPKT_ACR_CONTROL1); -+ -+ hdmi_modb(hdmi, AUDPKT_ACR_CTS_OVR_VAL(cts), AUDPKT_ACR_CTS_OVR_VAL_MSK, -+ AUDPKT_ACR_CONTROL1); -+} -+ -+// static int hdmi_match_tmds_n_table(struct dw_hdmi_qp *hdmi, -+// unsigned long pixel_clk, -+// unsigned long freq) -+// { -+// const struct dw_hdmi_plat_data *plat_data = hdmi->plat_data; -+// const struct dw_hdmi_audio_tmds_n *tmds_n = NULL; -+// int i; -+// -+// if (plat_data->tmds_n_table) { -+// for (i = 0; plat_data->tmds_n_table[i].tmds != 0; i++) { -+// if (pixel_clk == plat_data->tmds_n_table[i].tmds) { -+// tmds_n = &plat_data->tmds_n_table[i]; -+// break; -+// } -+// } -+// } -+// -+// if (tmds_n == NULL) { -+// for (i = 0; common_tmds_n_table[i].tmds != 0; i++) { -+// if (pixel_clk == common_tmds_n_table[i].tmds) { -+// tmds_n = &common_tmds_n_table[i]; -+// break; -+// } -+// } -+// } -+// -+// if (tmds_n == NULL) -+// return -ENOENT; -+// -+// switch (freq) { -+// case 32000: -+// return tmds_n->n_32k; -+// case 44100: -+// case 88200: -+// case 176400: -+// return (freq / 44100) * tmds_n->n_44k1; -+// case 48000: -+// case 96000: -+// case 192000: -+// return (freq / 48000) * tmds_n->n_48k; -+// default: -+// return -ENOENT; -+// } -+// } -+// -+static u64 hdmi_audio_math_diff(unsigned int freq, unsigned int n, -+ unsigned int pixel_clk) -+{ -+ u64 final, diff; -+ u64 cts; -+ -+ final = (u64)pixel_clk * n; -+ -+ cts = final; -+ do_div(cts, 128 * freq); -+ -+ diff = final - (u64)cts * (128 * freq); -+ -+ return diff; -+} -+ -+static unsigned int hdmi_compute_n(struct dw_hdmi_qp *hdmi, -+ unsigned long pixel_clk, -+ unsigned long freq) -+{ -+ unsigned int min_n = DIV_ROUND_UP((128 * freq), 1500); -+ unsigned int max_n = (128 * freq) / 300; -+ unsigned int ideal_n = (128 * freq) / 1000; -+ unsigned int best_n_distance = ideal_n; -+ unsigned int best_n = 0; -+ u64 best_diff = U64_MAX; -+ int n; -+ -+ /* If the ideal N could satisfy the audio math, then just take it */ -+ if (hdmi_audio_math_diff(freq, ideal_n, pixel_clk) == 0) -+ return ideal_n; -+ -+ for (n = min_n; n <= max_n; n++) { -+ u64 diff = hdmi_audio_math_diff(freq, n, pixel_clk); -+ -+ if (diff < best_diff || (diff == best_diff && -+ abs(n - ideal_n) < best_n_distance)) { -+ best_n = n; -+ best_diff = diff; -+ best_n_distance = abs(best_n - ideal_n); -+ } -+ -+ /* -+ * The best N already satisfy the audio math, and also be -+ * the closest value to ideal N, so just cut the loop. -+ */ -+ if ((best_diff == 0) && (abs(n - ideal_n) > best_n_distance)) -+ break; -+ } -+ -+ return best_n; -+} -+ -+static unsigned int hdmi_find_n(struct dw_hdmi_qp *hdmi, unsigned long pixel_clk, -+ unsigned long sample_rate) -+{ -+ int n; -+ -+ // n = hdmi_match_tmds_n_table(hdmi, pixel_clk, sample_rate); -+ n = 0; -+ if (n > 0) -+ return n; -+ -+ dev_warn(hdmi->dev, "Rate %lu missing; compute N dynamically\n", -+ pixel_clk); -+ -+ return hdmi_compute_n(hdmi, pixel_clk, sample_rate); -+} -+ -+/* -+ * When transmitting IEC60958 linear PCM audio, these registers allow to -+ * configure the channel status information of all the channel status -+ * bits in the IEC60958 frame. For the moment this configuration is only -+ * used when the I2S audio interface, General Purpose Audio (GPA), -+ * or AHB audio DMA (AHBAUDDMA) interface is active -+ * (for S/PDIF interface this information comes from the stream). -+ */ -+void dw_hdmi_qp_set_channel_status(struct dw_hdmi_qp *hdmi, -+ u8 *channel_status, bool ref2stream) -+{ -+ mutex_lock(&hdmi->audio_mutex); -+ if (!hdmi->dclk_en) { -+ mutex_unlock(&hdmi->audio_mutex); -+ return; -+ } -+ -+ /* Set channel status */ -+ hdmi_writel(hdmi, channel_status[3] | (channel_status[4] << 8), -+ AUDPKT_CHSTATUS_OVR1); -+ -+ if (ref2stream) -+ hdmi_modb(hdmi, 0, -+ AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK, -+ AUDPKT_CONTROL0); -+ else -+ hdmi_modb(hdmi, AUDPKT_PBIT_FORCE_EN | AUDPKT_CHSTATUS_OVR_EN, -+ AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK, -+ AUDPKT_CONTROL0); -+ -+ mutex_unlock(&hdmi->audio_mutex); -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_channel_status); -+ -+static void hdmi_set_clk_regenerator(struct dw_hdmi_qp *hdmi, -+ unsigned long pixel_clk, unsigned int sample_rate) -+{ -+ unsigned int n = 0, cts = 0; -+ -+ n = hdmi_find_n(hdmi, pixel_clk, sample_rate); -+ -+ hdmi->audio_n = n; -+ hdmi->audio_cts = cts; -+ hdmi_set_cts_n(hdmi, cts, hdmi->audio_enable ? n : 0); -+} -+ -+static void hdmi_init_clk_regenerator(struct dw_hdmi_qp *hdmi) -+{ -+ mutex_lock(&hdmi->audio_mutex); -+ if (hdmi->dclk_en) -+ hdmi_set_clk_regenerator(hdmi, 74250000, hdmi->sample_rate); -+ mutex_unlock(&hdmi->audio_mutex); -+} -+ -+static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi_qp *hdmi) -+{ -+ mutex_lock(&hdmi->audio_mutex); -+ if (hdmi->dclk_en) -+ hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mtmdsclock, -+ hdmi->sample_rate); -+ mutex_unlock(&hdmi->audio_mutex); -+} -+ -+void dw_hdmi_qp_set_sample_rate(struct dw_hdmi_qp *hdmi, unsigned int rate) -+{ -+ mutex_lock(&hdmi->audio_mutex); -+ if (hdmi->dclk_en) { -+ hdmi->sample_rate = rate; -+ hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mtmdsclock, -+ hdmi->sample_rate); -+ } -+ mutex_unlock(&hdmi->audio_mutex); -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_sample_rate); -+ -+void dw_hdmi_qp_set_channel_count(struct dw_hdmi_qp *hdmi, unsigned int cnt) -+{ -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_channel_count); -+ -+void dw_hdmi_qp_set_channel_allocation(struct dw_hdmi_qp *hdmi, unsigned int ca) -+{ -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_channel_allocation); -+ -+void dw_hdmi_qp_set_audio_infoframe(struct dw_hdmi_qp *hdmi, -+ struct hdmi_codec_params *hparms) -+{ -+ u8 infoframe_buf[HDMI_INFOFRAME_SIZE(AUDIO)]; -+ int ret = 0; -+ -+ ret = hdmi_audio_infoframe_pack(&hparms->cea, infoframe_buf, -+ sizeof(infoframe_buf)); -+ if (!ret) { -+ dev_err(hdmi->dev, "%s: Failed to pack audio infoframe: %d\n", -+ __func__, ret); -+ return; -+ } -+ -+ mutex_lock(&hdmi->audio_mutex); -+ if (!hdmi->dclk_en) { -+ mutex_unlock(&hdmi->audio_mutex); -+ return; -+ } -+ -+ /* -+ * AUDI_CONTENTS0: { RSV, HB2, HB1, RSV } -+ * AUDI_CONTENTS1: { PB3, PB2, PB1, PB0 } -+ * AUDI_CONTENTS2: { PB7, PB6, PB5, PB4 } -+ * -+ * PB0: CheckSum -+ * PB1: | CT3 | CT2 | CT1 | CT0 | F13 | CC2 | CC1 | CC0 | -+ * PB2: | F27 | F26 | F25 | SF2 | SF1 | SF0 | SS1 | SS0 | -+ * PB3: | F37 | F36 | F35 | F34 | F33 | F32 | F31 | F30 | -+ * PB4: | CA7 | CA6 | CA5 | CA4 | CA3 | CA2 | CA1 | CA0 | -+ * PB5: | DM_INH | LSV3 | LSV2 | LSV1 | LSV0 | F52 | F51 | F50 | -+ * PB6~PB10: Reserved -+ * -+ * AUDI_CONTENTS0 default value defined by HDMI specification, -+ * and shall only be changed for debug purposes. -+ * So, we only configure payload byte from PB0~PB7(2 word total). -+ */ -+ regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS1, &infoframe_buf[3], 2); -+ -+ /* Enable ACR, AUDI, AMD */ -+ hdmi_modb(hdmi, -+ PKTSCHED_ACR_TX_EN | PKTSCHED_AUDI_TX_EN | PKTSCHED_AMD_TX_EN, -+ PKTSCHED_ACR_TX_EN | PKTSCHED_AUDI_TX_EN | PKTSCHED_AMD_TX_EN, -+ PKTSCHED_PKT_EN); -+ -+ /* Enable AUDS */ -+ hdmi_modb(hdmi, PKTSCHED_AUDS_TX_EN, PKTSCHED_AUDS_TX_EN, PKTSCHED_PKT_EN); -+ mutex_unlock(&hdmi->audio_mutex); -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_audio_infoframe); -+ -+static void hdmi_enable_audio_clk(struct dw_hdmi_qp *hdmi, bool enable) -+{ -+ if (enable) -+ hdmi_modb(hdmi, 0, -+ AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, GLOBAL_SWDISABLE); -+ else -+ hdmi_modb(hdmi, AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, -+ AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, GLOBAL_SWDISABLE); -+} -+ -+// static void dw_hdmi_i2s_audio_enable(struct dw_hdmi_qp *hdmi) -+// { -+// hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); -+// hdmi_enable_audio_clk(hdmi, true); -+// } -+// -+// static void dw_hdmi_i2s_audio_disable(struct dw_hdmi_qp *hdmi) -+// { -+// /* Disable AUDS, ACR, AUDI, AMD */ -+// hdmi_modb(hdmi, 0, -+// PKTSCHED_ACR_TX_EN | PKTSCHED_AUDS_TX_EN | -+// PKTSCHED_AUDI_TX_EN | PKTSCHED_AMD_TX_EN, -+// PKTSCHED_PKT_EN); -+// -+// hdmi_enable_audio_clk(hdmi, false); -+// } -+ -+void dw_hdmi_qp_audio_enable(struct dw_hdmi_qp *hdmi) -+{ -+ mutex_lock(&hdmi->audio_mutex); -+ if (hdmi->dclk_en) { -+ hdmi->audio_enable = true; -+ if (hdmi->enable_audio) -+ hdmi->enable_audio(hdmi); -+ } -+ mutex_unlock(&hdmi->audio_mutex); -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_audio_enable); -+ -+void dw_hdmi_qp_audio_disable(struct dw_hdmi_qp *hdmi) -+{ -+ mutex_lock(&hdmi->audio_mutex); -+ if (hdmi->dclk_en) { -+ hdmi->audio_enable = false; -+ if (hdmi->disable_audio) -+ hdmi->disable_audio(hdmi); -+ } -+ mutex_unlock(&hdmi->audio_mutex); -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_audio_disable); -+ -+static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format) -+{ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_RGB888_1X24: -+ case MEDIA_BUS_FMT_RGB101010_1X30: -+ case MEDIA_BUS_FMT_RGB121212_1X36: -+ case MEDIA_BUS_FMT_RGB161616_1X48: -+ return true; -+ -+ default: -+ return false; -+ } -+} -+ -+static bool hdmi_bus_fmt_is_yuv444(unsigned int bus_format) -+{ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_YUV8_1X24: -+ case MEDIA_BUS_FMT_YUV10_1X30: -+ case MEDIA_BUS_FMT_YUV12_1X36: -+ case MEDIA_BUS_FMT_YUV16_1X48: -+ return true; -+ -+ default: -+ return false; -+ } -+} -+ -+static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format) -+{ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_UYVY8_1X16: -+ case MEDIA_BUS_FMT_UYVY10_1X20: -+ case MEDIA_BUS_FMT_UYVY12_1X24: -+ return true; -+ -+ default: -+ return false; -+ } -+} -+ -+static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format) -+{ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: -+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: -+ case MEDIA_BUS_FMT_UYYVYY12_0_5X36: -+ case MEDIA_BUS_FMT_UYYVYY16_0_5X48: -+ return true; -+ -+ default: -+ return false; -+ } -+} -+ -+static int hdmi_bus_fmt_color_depth(unsigned int bus_format) -+{ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_RGB888_1X24: -+ case MEDIA_BUS_FMT_YUV8_1X24: -+ case MEDIA_BUS_FMT_UYVY8_1X16: -+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: -+ return 8; -+ -+ case MEDIA_BUS_FMT_RGB101010_1X30: -+ case MEDIA_BUS_FMT_YUV10_1X30: -+ case MEDIA_BUS_FMT_UYVY10_1X20: -+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: -+ return 10; -+ -+ case MEDIA_BUS_FMT_RGB121212_1X36: -+ case MEDIA_BUS_FMT_YUV12_1X36: -+ case MEDIA_BUS_FMT_UYVY12_1X24: -+ case MEDIA_BUS_FMT_UYYVYY12_0_5X36: -+ return 12; -+ -+ case MEDIA_BUS_FMT_RGB161616_1X48: -+ case MEDIA_BUS_FMT_YUV16_1X48: -+ case MEDIA_BUS_FMT_UYYVYY16_0_5X48: -+ return 16; -+ -+ default: -+ return 0; -+ } -+} -+ -+static void dw_hdmi_i2c_init(struct dw_hdmi_qp *hdmi) -+{ -+ /* Software reset */ -+ hdmi_writel(hdmi, 0x01, I2CM_CONTROL0); -+ -+ hdmi_writel(hdmi, 0x085c085c, I2CM_FM_SCL_CONFIG0); -+ -+ hdmi_modb(hdmi, 0, I2CM_FM_EN, I2CM_INTERFACE_CONTROL0); -+ -+ /* Clear DONE and ERROR interrupts */ -+ hdmi_writel(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR, -+ MAINUNIT_1_INT_CLEAR); -+} -+ -+static int dw_hdmi_i2c_read(struct dw_hdmi_qp *hdmi, -+ unsigned char *buf, unsigned int length) -+{ -+ struct dw_hdmi_qp_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); -+ -+ hdmi_modb(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, -+ I2CM_INTERFACE_CONTROL0); -+ -+ hdmi_modb(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 time out!\n"); -+ hdmi_writel(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 err!\n"); -+ hdmi_writel(hdmi, 0x01, I2CM_CONTROL0); -+ return -EIO; -+ } -+ -+ *buf++ = hdmi_readl(hdmi, I2CM_INTERFACE_RDDATA_0_3) & 0xff; -+ // dev_dbg(hdmi->dev, "i2c read done! i2c->stat:%02x 0x%02x\n", -+ // i2c->stat, hdmi_readl(hdmi, I2CM_INTERFACE_RDDATA_0_3)); -+ hdmi_modb(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0); -+ } -+ i2c->is_segment = false; -+ -+ return 0; -+} -+ -+static int dw_hdmi_i2c_write(struct dw_hdmi_qp *hdmi, -+ unsigned char *buf, unsigned int length) -+{ -+ struct dw_hdmi_qp_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); -+ -+ hdmi_writel(hdmi, *buf++, I2CM_INTERFACE_WRDATA_0_3); -+ hdmi_modb(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, -+ I2CM_INTERFACE_CONTROL0); -+ hdmi_modb(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"); -+ hdmi_writel(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"); -+ hdmi_writel(hdmi, 0x01, I2CM_CONTROL0); -+ return -EIO; -+ } -+ hdmi_modb(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0); -+ } -+ // dev_dbg(hdmi->dev, "i2c write done!\n"); -+ return 0; -+} -+ -+static int dw_hdmi_i2c_xfer(struct i2c_adapter *adap, -+ struct i2c_msg *msgs, int num) -+{ -+ struct dw_hdmi_qp *hdmi = i2c_get_adapdata(adap); -+ struct dw_hdmi_qp_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; -+ -+ // dev_dbg(hdmi->dev, "i2c xfer: num: %d, addr: %#x\n", num, addr); -+ -+ 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 */ -+ hdmi_modb(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; -+ -+ hdmi_modb(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++) { -+ // dev_dbg(hdmi->dev, "xfer: num: %d/%d, len: %d, flags: %#x\n", -+ // i + 1, num, msgs[i].len, msgs[i].flags); -+ -+ if (msgs[i].addr == DDC_SEGMENT_ADDR && msgs[i].len == 1) { -+ i2c->is_segment = true; -+ hdmi_modb(hdmi, DDC_SEGMENT_ADDR, I2CM_SEG_ADDR, -+ I2CM_INTERFACE_CONTROL1); -+ hdmi_modb(hdmi, *msgs[i].buf, I2CM_SEG_PTR, -+ I2CM_INTERFACE_CONTROL1); -+ } else { -+ if (msgs[i].flags & I2C_M_RD) -+ ret = dw_hdmi_i2c_read(hdmi, msgs[i].buf, -+ msgs[i].len); -+ else -+ ret = dw_hdmi_i2c_write(hdmi, msgs[i].buf, -+ msgs[i].len); -+ } -+ if (ret < 0) -+ break; -+ } -+ -+ if (!ret) -+ ret = num; -+ -+ /* Mute DONE and ERROR interrupts */ -+ hdmi_modb(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_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_i2c_xfer, -+ .functionality = dw_hdmi_i2c_func, -+}; -+ -+static struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi_qp *hdmi) -+{ -+ struct i2c_adapter *adap; -+ struct dw_hdmi_qp_i2c *i2c; -+ int ret; -+ -+ i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL); -+ if (!i2c) -+ return ERR_PTR(-ENOMEM); -+ -+ mutex_init(&i2c->lock); -+ init_completion(&i2c->cmp); -+ -+ adap = &i2c->adap; -+ adap->class = I2C_CLASS_DDC; -+ adap->owner = THIS_MODULE; -+ adap->dev.parent = hdmi->dev; -+ adap->algo = &dw_hdmi_algorithm; -+ strscpy(adap->name, "ddc", sizeof(adap->name)); -+ i2c_set_adapdata(adap, hdmi); -+ -+ ret = i2c_add_adapter(adap); -+ if (ret) { -+ dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name); -+ devm_kfree(hdmi->dev, i2c); -+ return ERR_PTR(ret); -+ } -+ -+ hdmi->i2c = i2c; -+ -+ dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name); -+ -+ return adap; -+} -+ -+#define HDMI_PHY_EARC_MASK BIT(29) -+ -+int dw_hdmi_qp_set_earc(struct dw_hdmi_qp *hdmi) -+{ -+ u32 stat, ret; -+ -+ /* set hdmi phy earc mode */ -+ hdmi->phy.ops->set_mode(hdmi, hdmi->phy.data, HDMI_PHY_EARC_MASK, -+ true); -+ -+ ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, -+ &hdmi->previous_mode); -+ if (ret) -+ return ret; -+ -+ reinit_completion(&hdmi->earc_cmp); -+ -+ hdmi_modb(hdmi, EARCRX_CMDC_DISCOVERY_TIMEOUT_IRQ | -+ EARCRX_CMDC_DISCOVERY_DONE_IRQ, -+ EARCRX_CMDC_DISCOVERY_TIMEOUT_IRQ | -+ EARCRX_CMDC_DISCOVERY_DONE_IRQ, EARCRX_0_INT_MASK_N); -+ -+ /* start discovery */ -+ hdmi_modb(hdmi, EARCRX_CMDC_DISCOVERY_EN, EARCRX_CMDC_DISCOVERY_EN, -+ EARCRX_CMDC_CONTROL); -+ -+ /* -+ * The eARC TX device drives a logic-high-voltage-level -+ * pulse on the physical HPD connector pin, after -+ * at least 100 ms of low voltage level to start the -+ * eARC Discovery process. -+ */ -+ hdmi_modb(hdmi, EARCRX_CONNECTOR_HPD, EARCRX_CONNECTOR_HPD, -+ EARCRX_CMDC_CONTROL); -+ -+ stat = wait_for_completion_timeout(&hdmi->earc_cmp, HZ / 10); -+ if (!stat) -+ return -EAGAIN; -+ -+ if (hdmi->earc_intr & EARCRX_CMDC_DISCOVERY_TIMEOUT_IRQ) { -+ dev_err(hdmi->dev, "discovery timeout\n"); -+ return -ETIMEDOUT; -+ } else if (hdmi->earc_intr & EARCRX_CMDC_DISCOVERY_DONE_IRQ) { -+ dev_info(hdmi->dev, "discovery done\n"); -+ } else { -+ dev_err(hdmi->dev, "discovery failed\n"); -+ return -EINVAL; -+ } -+ -+ hdmi_writel(hdmi, 1, EARCRX_DMAC_PHY_CONTROL); -+ hdmi_modb(hdmi, EARCRX_CMDC_SWINIT_P, EARCRX_CMDC_SWINIT_P, -+ EARCRX_CMDC_CONFIG0); -+ -+ hdmi_writel(hdmi, 0xf3, EARCRX_DMAC_CONFIG); -+ hdmi_writel(hdmi, 0x63, EARCRX_DMAC_CONTROL0); -+ hdmi_writel(hdmi, 0xff, EARCRX_DMAC_CONTROL1); -+ -+ hdmi_modb(hdmi, EARCRX_XACTREAD_STOP_CFG | EARCRX_XACTREAD_RETRY_CFG | -+ EARCRX_CMDC_DSCVR_EARCVALID0_TO_DISC1 | EARCRX_CMDC_XACT_RESTART_EN, -+ EARCRX_XACTREAD_STOP_CFG | EARCRX_XACTREAD_RETRY_CFG | -+ EARCRX_CMDC_DSCVR_EARCVALID0_TO_DISC1 | EARCRX_CMDC_XACT_RESTART_EN, -+ EARCRX_CMDC_CONFIG0); -+ -+ hdmi_writel(hdmi, 0, EARCRX_DMAC_CHSTATUS_STREAMER0); -+ hdmi_writel(hdmi, 0x1b0e, EARCRX_DMAC_CHSTATUS_STREAMER1); -+ hdmi_writel(hdmi, 0, EARCRX_DMAC_CHSTATUS_STREAMER2); -+ hdmi_writel(hdmi, 0, EARCRX_DMAC_CHSTATUS_STREAMER3); -+ hdmi_writel(hdmi, 0xf2000000, EARCRX_DMAC_CHSTATUS_STREAMER4); -+ hdmi_writel(hdmi, 0, EARCRX_DMAC_CHSTATUS_STREAMER5); -+ hdmi_writel(hdmi, 0, EARCRX_DMAC_CHSTATUS_STREAMER6); -+ hdmi_writel(hdmi, 0, EARCRX_DMAC_CHSTATUS_STREAMER7); -+ hdmi_writel(hdmi, 0, EARCRX_DMAC_CHSTATUS_STREAMER8); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_earc); -+ -+/* ----------------------------------------------------------------------------- -+ * 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_qp *hdmi, -+ const struct drm_connector *connector, -+ const struct drm_display_mode *mode) -+{ -+ struct hdmi_avi_infoframe frame; -+ u32 val, i, j; -+ u8 buff[17]; -+ enum hdmi_quantization_range rgb_quant_range = -+ hdmi->hdmi_data.quant_range; -+ -+ /* Initialise info frame from DRM mode */ -+ drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); -+ -+ /* -+ * Ignore monitor selectable quantization, use quantization set -+ * by the user -+ */ -+ drm_hdmi_avi_infoframe_quant_range(&frame, connector, mode, rgb_quant_range); -+ if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) -+ frame.colorspace = HDMI_COLORSPACE_YUV444; -+ else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) -+ frame.colorspace = HDMI_COLORSPACE_YUV422; -+ else if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) -+ frame.colorspace = HDMI_COLORSPACE_YUV420; -+ else -+ 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; -+ else -+ 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; -+ else -+ frame.colorimetry = HDMI_COLORIMETRY_ITU_709; -+ frame.extended_colorimetry = -+ HDMI_EXTENDED_COLORIMETRY_XV_YCC_709; -+ break; -+ case V4L2_YCBCR_ENC_BT2020: -+ if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_BT2020) -+ frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; -+ else -+ frame.colorimetry = HDMI_COLORIMETRY_ITU_709; -+ frame.extended_colorimetry = -+ HDMI_EXTENDED_COLORIMETRY_BT2020; -+ break; -+ default: /* Carries no data */ -+ frame.colorimetry = HDMI_COLORIMETRY_ITU_601; -+ frame.extended_colorimetry = -+ HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; -+ break; -+ } -+ } else { -+ if (hdmi->hdmi_data.enc_out_encoding == V4L2_YCBCR_ENC_BT2020) { -+ frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; -+ frame.extended_colorimetry = -+ HDMI_EXTENDED_COLORIMETRY_BT2020; -+ } else { -+ frame.colorimetry = HDMI_COLORIMETRY_NONE; -+ frame.extended_colorimetry = -+ HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; -+ } -+ } -+ -+ frame.scan_mode = HDMI_SCAN_MODE_NONE; -+ frame.video_code = hdmi->vic; -+ -+ hdmi_avi_infoframe_pack_only(&frame, buff, 17); -+ -+ /* mode which vic >= 128 must use avi version 3 */ -+ if (hdmi->vic >= 128) { -+ frame.version = 3; -+ buff[1] = frame.version; -+ buff[4] &= 0x1f; -+ buff[4] |= ((frame.colorspace & 0x7) << 5); -+ buff[7] = frame.video_code; -+ hdmi_infoframe_set_checksum(buff, 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); -+ hdmi_writel(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 = buff[i * 4 + j + 3]; -+ val |= buff[i * 4 + j + 3] << (8 * j); -+ } -+ -+ hdmi_writel(hdmi, val, PKT_AVI_CONTENTS1 + i * 4); -+ } -+ -+ hdmi_modb(hdmi, 0, PKTSCHED_AVI_FIELDRATE, PKTSCHED_PKT_CONFIG1); -+ -+ hdmi_modb(hdmi, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, -+ PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, -+ PKTSCHED_PKT_EN); -+} -+ -+static void hdmi_config_CVTEM(struct dw_hdmi_qp *hdmi) -+{ -+ u8 ds_type = 0; -+ u8 sync = 1; -+ u8 vfr = 1; -+ u8 afr = 0; -+ u8 new = 1; -+ u8 end = 0; -+ u8 data_set_length = 136; -+ u8 hb1[6] = { 0x80, 0, 0, 0, 0, 0x40 }; -+ u8 *pps_body; -+ u32 val, i, reg; -+ struct drm_display_mode *mode = &hdmi->previous_mode; -+ int hsync, hfront, hback; -+ struct dw_hdmi_link_config *link_cfg; -+ void *data = hdmi->plat_data->phy_data; -+ -+ hdmi_modb(hdmi, 0, PKTSCHED_EMP_CVTEM_TX_EN, PKTSCHED_PKT_EN); -+ -+ if (hdmi->plat_data->get_link_cfg) { -+ link_cfg = hdmi->plat_data->get_link_cfg(data); -+ } else { -+ dev_err(hdmi->dev, "can't get frl link cfg\n"); -+ return; -+ } -+ -+ if (!link_cfg->dsc_mode) { -+ dev_info(hdmi->dev, "don't use dsc mode\n"); -+ return; -+ } -+ -+ pps_body = link_cfg->pps_payload; -+ -+ hsync = mode->hsync_end - mode->hsync_start; -+ hback = mode->htotal - mode->hsync_end; -+ hfront = mode->hsync_start - mode->hdisplay; -+ -+ for (i = 0; i < 6; i++) { -+ val = i << 16 | hb1[i] << 8; -+ hdmi_writel(hdmi, val, PKT0_EMP_CVTEM_CONTENTS0 + i * 0x20); -+ } -+ -+ val = new << 7 | end << 6 | ds_type << 4 | afr << 3 | -+ vfr << 2 | sync << 1; -+ hdmi_writel(hdmi, val, PKT0_EMP_CVTEM_CONTENTS1); -+ -+ val = data_set_length << 16 | pps_body[0] << 24; -+ hdmi_writel(hdmi, val, PKT0_EMP_CVTEM_CONTENTS2); -+ -+ reg = PKT0_EMP_CVTEM_CONTENTS3; -+ for (i = 1; i < 125; i++) { -+ if (reg == PKT1_EMP_CVTEM_CONTENTS0 || -+ reg == PKT2_EMP_CVTEM_CONTENTS0 || -+ reg == PKT3_EMP_CVTEM_CONTENTS0 || -+ reg == PKT4_EMP_CVTEM_CONTENTS0 || -+ reg == PKT5_EMP_CVTEM_CONTENTS0) { -+ reg += 4; -+ i--; -+ continue; -+ } -+ if (i % 4 == 1) -+ val = pps_body[i]; -+ if (i % 4 == 2) -+ val |= pps_body[i] << 8; -+ if (i % 4 == 3) -+ val |= pps_body[i] << 16; -+ if (!(i % 4)) { -+ val |= pps_body[i] << 24; -+ hdmi_writel(hdmi, val, reg); -+ reg += 4; -+ } -+ } -+ -+ val = (hfront & 0xff) << 24 | pps_body[127] << 16 | -+ pps_body[126] << 8 | pps_body[125]; -+ hdmi_writel(hdmi, val, PKT4_EMP_CVTEM_CONTENTS6); -+ -+ val = (hback & 0xff) << 24 | ((hsync >> 8) & 0xff) << 16 | -+ (hsync & 0xff) << 8 | ((hfront >> 8) & 0xff); -+ hdmi_writel(hdmi, val, PKT4_EMP_CVTEM_CONTENTS7); -+ -+ val = link_cfg->hcactive << 8 | ((hback >> 8) & 0xff); -+ hdmi_writel(hdmi, val, PKT5_EMP_CVTEM_CONTENTS1); -+ -+ for (i = PKT5_EMP_CVTEM_CONTENTS2; i <= PKT5_EMP_CVTEM_CONTENTS7; i += 4) -+ hdmi_writel(hdmi, 0, i); -+ -+ hdmi_modb(hdmi, PKTSCHED_EMP_CVTEM_TX_EN, PKTSCHED_EMP_CVTEM_TX_EN, -+ PKTSCHED_PKT_EN); -+} -+ -+static void hdmi_config_drm_infoframe(struct dw_hdmi_qp *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; -+ -+ hdmi_modb(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); -+ -+ if (!hdmi->connector.hdr_sink_metadata.hdmi_type1.eotf) { -+ DRM_DEBUG("No need to set HDR metadata in infoframe\n"); -+ return; -+ } -+ -+ if (!conn_state->hdr_output_metadata) { -+ DRM_DEBUG("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))) { -+ DRM_ERROR("Not support EOTF %d\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); -+ hdmi_writel(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))) -+ hdmi_writel(hdmi, val, PKT_DRMI_CONTENTS1 + ((i / 4) * 4)); -+ } -+ -+ hdmi_modb(hdmi, 0, PKTSCHED_DRMI_FIELDRATE, PKTSCHED_PKT_CONFIG1); -+ -+ hdmi_modb(hdmi, PKTSCHED_DRMI_TX_EN, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); -+ -+ DRM_DEBUG("%s eotf %d end\n", __func__, -+ hdr_metadata->hdmi_metadata_type1.eotf); -+} -+ -+/* Filter out invalid setups to avoid configuring SCDC and scrambling */ -+static bool dw_hdmi_support_scdc(struct dw_hdmi_qp *hdmi, -+ const struct drm_display_info *display) -+{ -+ /* Disable if no DDC bus */ -+ if (!hdmi->ddc) -+ return false; -+ -+ /* Disable if SCDC is not supported, or if an HF-VSDB block is absent */ -+ if (!display->hdmi.scdc.supported || -+ !display->hdmi.scdc.scrambling.supported) -+ return false; -+ -+ /* -+ * Disable if display only support low TMDS rates and scrambling -+ * for low rates is not supported either -+ */ -+ if (!display->hdmi.scdc.scrambling.low_rates && -+ display->max_tmds_clock <= 340000) -+ return false; -+ -+ return true; -+} -+ -+static int hdmi_set_frl_mask(int frl_rate) -+{ -+ switch (frl_rate) { -+ case 48: -+ return FRL_12GBPS_4LANE; -+ case 40: -+ return FRL_10GBPS_4LANE; -+ case 32: -+ return FRL_8GBPS_4LANE; -+ case 24: -+ return FRL_6GBPS_4LANE; -+ case 18: -+ return FRL_6GBPS_3LANE; -+ case 9: -+ return FRL_3GBPS_3LANE; -+ } -+ -+ return 0; -+} -+ -+static int hdmi_start_flt(struct dw_hdmi_qp *hdmi, u8 rate) -+{ -+ u8 val; -+ u8 ffe_lv = 0; -+ int i = 0, stat; -+ -+ /* FLT_READY & FFE_LEVELS read */ -+ for (i = 0; i < 20; i++) { -+ drm_scdc_readb(hdmi->ddc, SCDC_STATUS_FLAGS_0, &val); -+ if (val & BIT(6)) -+ break; -+ msleep(20); -+ } -+ -+ if (i == 20) { -+ dev_err(hdmi->dev, "sink flt isn't ready\n"); -+ return -EINVAL; -+ } -+ -+ hdmi_modb(hdmi, SCDC_UPD_FLAGS_RD_IRQ, SCDC_UPD_FLAGS_RD_IRQ, -+ MAINUNIT_1_INT_MASK_N); -+ hdmi_modb(hdmi, SCDC_UPD_FLAGS_POLL_EN | SCDC_UPD_FLAGS_AUTO_CLR, -+ SCDC_UPD_FLAGS_POLL_EN | SCDC_UPD_FLAGS_AUTO_CLR, -+ SCDC_CONFIG0); -+ -+ /* max ffe level 3 */ -+ val = 3 << 4 | hdmi_set_frl_mask(rate); -+ drm_scdc_writeb(hdmi->ddc, 0x31, val); -+ -+ /* select FRL_RATE & FFE_LEVELS */ -+ hdmi_writel(hdmi, ffe_lv, FLT_CONFIG0); -+ -+ /* Start LTS_3 state in source DUT */ -+ reinit_completion(&hdmi->flt_cmp); -+ hdmi_modb(hdmi, FLT_EXIT_TO_LTSP_IRQ, FLT_EXIT_TO_LTSP_IRQ, -+ MAINUNIT_1_INT_MASK_N); -+ hdmi_writel(hdmi, 1, FLT_CONTROL0); -+ -+ /* wait for completed link training at source side */ -+ stat = wait_for_completion_timeout(&hdmi->flt_cmp, HZ * 2); -+ if (!stat) { -+ dev_err(hdmi->dev, "wait lts3 finish time out\n"); -+ hdmi_modb(hdmi, 0, SCDC_UPD_FLAGS_POLL_EN | -+ SCDC_UPD_FLAGS_AUTO_CLR, SCDC_CONFIG0); -+ hdmi_modb(hdmi, 0, SCDC_UPD_FLAGS_RD_IRQ, -+ MAINUNIT_1_INT_MASK_N); -+ return -EAGAIN; -+ } -+ -+ if (!(hdmi->flt_intr & FLT_EXIT_TO_LTSP_IRQ)) { -+ dev_err(hdmi->dev, "not to ltsp\n"); -+ hdmi_modb(hdmi, 0, SCDC_UPD_FLAGS_POLL_EN | -+ SCDC_UPD_FLAGS_AUTO_CLR, SCDC_CONFIG0); -+ hdmi_modb(hdmi, 0, SCDC_UPD_FLAGS_RD_IRQ, -+ MAINUNIT_1_INT_MASK_N); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+#define HDMI_MODE_FRL_MASK BIT(30) -+ -+static void hdmi_set_op_mode(struct dw_hdmi_qp *hdmi, -+ struct dw_hdmi_link_config *link_cfg, -+ const struct drm_connector *connector) -+{ -+ int frl_rate; -+ int i; -+ -+ /* set sink frl mode disable and wait sink ready */ -+ hdmi_writel(hdmi, 0, FLT_CONFIG0); -+ if (dw_hdmi_support_scdc(hdmi, &connector->display_info)) -+ drm_scdc_writeb(hdmi->ddc, 0x31, 0); -+ /* -+ * some TVs must wait a while before switching frl mode resolution, -+ * or the signal may not be recognized. -+ */ -+ msleep(200); -+ -+ if (!link_cfg->frl_mode) { -+ dev_info(hdmi->dev, "dw hdmi qp use tmds mode\n"); -+ hdmi_modb(hdmi, 0, OPMODE_FRL, LINK_CONFIG0); -+ hdmi_modb(hdmi, 0, OPMODE_FRL_4LANES, LINK_CONFIG0); -+ return; -+ } -+ -+ if (link_cfg->frl_lanes == 4) -+ hdmi_modb(hdmi, OPMODE_FRL_4LANES, OPMODE_FRL_4LANES, -+ LINK_CONFIG0); -+ else -+ hdmi_modb(hdmi, 0, OPMODE_FRL_4LANES, LINK_CONFIG0); -+ -+ hdmi_modb(hdmi, 1, OPMODE_FRL, LINK_CONFIG0); -+ -+ frl_rate = link_cfg->frl_lanes * link_cfg->rate_per_lane; -+ hdmi_start_flt(hdmi, frl_rate); -+ -+ for (i = 0; i < 50; i++) { -+ hdmi_modb(hdmi, PKTSCHED_NULL_TX_EN, PKTSCHED_NULL_TX_EN, PKTSCHED_PKT_EN); -+ mdelay(1); -+ hdmi_modb(hdmi, 0, PKTSCHED_NULL_TX_EN, PKTSCHED_PKT_EN); -+ } -+} -+ -+static unsigned long -+hdmi_get_tmdsclock(struct dw_hdmi_qp *hdmi, unsigned long mpixelclock) -+{ -+ unsigned long tmdsclock = mpixelclock; -+ unsigned int depth = -+ hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format); -+ -+ if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) { -+ switch (depth) { -+ case 16: -+ tmdsclock = mpixelclock * 2; -+ break; -+ case 12: -+ tmdsclock = mpixelclock * 3 / 2; -+ break; -+ case 10: -+ tmdsclock = mpixelclock * 5 / 4; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ return tmdsclock; -+} -+ -+//[CC:] is connector param different from hdmi->connector? -+//[CC:] probably it possible to hook the whole implementation into dw-hdmi.c -+static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi, -+ struct drm_connector *connector, -+ struct drm_display_mode *mode) -+{ -+ int ret; -+ void *data = hdmi->plat_data->phy_data; -+ struct hdmi_vmode_qp *vmode = &hdmi->hdmi_data.video_mode; -+ struct dw_hdmi_link_config *link_cfg; -+ u8 bytes = 0; -+ -+ hdmi->vic = drm_match_cea_mode(mode); -+ if (!hdmi->vic) -+ dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n"); -+ else -+ dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic); -+ -+ if (hdmi->plat_data->get_enc_out_encoding) -+ hdmi->hdmi_data.enc_out_encoding = -+ hdmi->plat_data->get_enc_out_encoding(data); -+ else if ((hdmi->vic == 6) || (hdmi->vic == 7) || -+ (hdmi->vic == 21) || (hdmi->vic == 22) || -+ (hdmi->vic == 2) || (hdmi->vic == 3) || -+ (hdmi->vic == 17) || (hdmi->vic == 18)) -+ hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_601; -+ else -+ hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_709; -+ -+ if (mode->flags & DRM_MODE_FLAG_DBLCLK) { -+ hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1; -+ hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 1; -+ } else { -+ hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; -+ hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0; -+ } -+ /* Get input format from plat data or fallback to RGB888 */ -+ if (hdmi->plat_data->get_input_bus_format) -+ hdmi->hdmi_data.enc_in_bus_format = -+ hdmi->plat_data->get_input_bus_format(data); -+ else if (hdmi->plat_data->input_bus_format) -+ hdmi->hdmi_data.enc_in_bus_format = -+ hdmi->plat_data->input_bus_format; -+ else -+ hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24; -+ -+ /* Default to RGB888 output format */ -+ if (hdmi->plat_data->get_output_bus_format) -+ hdmi->hdmi_data.enc_out_bus_format = -+ hdmi->plat_data->get_output_bus_format(data); -+ else -+ hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24; -+ -+ /* Get input encoding from plat data or fallback to none */ -+ if (hdmi->plat_data->get_enc_in_encoding) -+ hdmi->hdmi_data.enc_in_encoding = -+ hdmi->plat_data->get_enc_in_encoding(data); -+ else if (hdmi->plat_data->input_bus_encoding) -+ hdmi->hdmi_data.enc_in_encoding = -+ hdmi->plat_data->input_bus_encoding; -+ else -+ hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT; -+ -+ if (hdmi->plat_data->get_quant_range) -+ hdmi->hdmi_data.quant_range = -+ hdmi->plat_data->get_quant_range(data); -+ else -+ hdmi->hdmi_data.quant_range = HDMI_QUANTIZATION_RANGE_DEFAULT; -+ -+ if (hdmi->plat_data->get_link_cfg) -+ link_cfg = hdmi->plat_data->get_link_cfg(data); -+ else -+ return -EINVAL; -+ -+ hdmi->phy.ops->set_mode(hdmi, hdmi->phy.data, HDMI_MODE_FRL_MASK, -+ link_cfg->frl_mode); -+ -+ /* -+ * 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) -+ */ -+ hdmi->hdmi_data.pix_repet_factor = -+ (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 1 : 0; -+ hdmi->hdmi_data.video_mode.mdataenablepolarity = true; -+ -+ vmode->previous_pixelclock = vmode->mpixelclock; -+ //[CC:] no split mode -+ // if (hdmi->plat_data->split_mode) -+ // mode->crtc_clock /= 2; -+ vmode->mpixelclock = mode->crtc_clock * 1000; -+ if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) -+ vmode->mpixelclock *= 2; -+ dev_dbg(hdmi->dev, "final pixclk = %ld\n", vmode->mpixelclock); -+ vmode->previous_tmdsclock = vmode->mtmdsclock; -+ vmode->mtmdsclock = hdmi_get_tmdsclock(hdmi, vmode->mpixelclock); -+ if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) -+ vmode->mtmdsclock /= 2; -+ dev_info(hdmi->dev, "final tmdsclk = %d\n", vmode->mtmdsclock); -+ -+ ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode); -+ if (ret) -+ return ret; -+ -+ if (hdmi->plat_data->set_grf_cfg) -+ hdmi->plat_data->set_grf_cfg(data); -+ -+ if (hdmi->sink_has_audio) { -+ dev_dbg(hdmi->dev, "sink has audio support\n"); -+ -+ /* HDMI Initialization Step E - Configure audio */ -+ hdmi_clk_regenerator_update_pixel_clock(hdmi); -+ hdmi_enable_audio_clk(hdmi, hdmi->audio_enable); -+ } -+ -+ /* not for DVI mode */ -+ if (hdmi->sink_is_hdmi) { -+ dev_dbg(hdmi->dev, "%s HDMI mode\n", __func__); -+ hdmi_modb(hdmi, 0, OPMODE_DVI, LINK_CONFIG0); -+ hdmi_modb(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0); -+ if (!link_cfg->frl_mode) { -+ if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK) { -+ 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)); -+ //[CC:] use dw_hdmi_set_high_tmds_clock_ratio() -+ drm_scdc_set_high_tmds_clock_ratio(connector, 1); -+ drm_scdc_set_scrambling(connector, 1); -+ hdmi_writel(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); -+ } -+ hdmi_writel(hdmi, 0, SCRAMB_CONFIG0); -+ } -+ } -+ /* HDMI Initialization Step F - Configure AVI InfoFrame */ -+ hdmi_config_AVI(hdmi, connector, mode); -+ hdmi_config_CVTEM(hdmi); -+ hdmi_config_drm_infoframe(hdmi, connector); -+ hdmi_set_op_mode(hdmi, link_cfg, connector); -+ } else { -+ hdmi_modb(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0); -+ hdmi_modb(hdmi, OPMODE_DVI, OPMODE_DVI, LINK_CONFIG0); -+ dev_info(hdmi->dev, "%s DVI mode\n", __func__); -+ } -+ -+ return 0; -+} -+ -+static enum drm_connector_status -+dw_hdmi_connector_detect(struct drm_connector *connector, bool force) -+{ -+ struct dw_hdmi_qp *hdmi = -+ container_of(connector, struct dw_hdmi_qp, connector); -+ struct dw_hdmi_qp *secondary = NULL; -+ enum drm_connector_status result, result_secondary; -+ -+ mutex_lock(&hdmi->mutex); -+ hdmi->force = DRM_FORCE_UNSPECIFIED; -+ mutex_unlock(&hdmi->mutex); -+ -+ if (hdmi->plat_data->left) -+ secondary = hdmi->plat_data->left; -+ else if (hdmi->plat_data->right) -+ secondary = hdmi->plat_data->right; -+ -+ result = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); -+ -+ if (secondary) { -+ result_secondary = secondary->phy.ops->read_hpd(secondary, secondary->phy.data); -+ if (result == connector_status_connected && -+ result_secondary == connector_status_connected) -+ result = connector_status_connected; -+ else -+ result = connector_status_disconnected; -+ } -+ -+ mutex_lock(&hdmi->mutex); -+ if (result != hdmi->last_connector_result) { -+ dev_dbg(hdmi->dev, "read_hpd result: %d", result); -+ handle_plugged_change(hdmi, -+ result == connector_status_connected); -+ hdmi->last_connector_result = result; -+ } -+ mutex_unlock(&hdmi->mutex); -+ -+ return result; -+} -+ -+static int -+dw_hdmi_update_hdr_property(struct drm_connector *connector) -+{ -+ struct drm_device *dev = connector->dev; -+ struct dw_hdmi_qp *hdmi = container_of(connector, struct dw_hdmi_qp, -+ connector); -+ void *data = hdmi->plat_data->phy_data; -+ const struct hdr_static_metadata *metadata = -+ &connector->hdr_sink_metadata.hdmi_type1; -+ size_t size = sizeof(*metadata); -+ struct drm_property *property; -+ struct drm_property_blob *blob; -+ int ret; -+ -+ if (hdmi->plat_data->get_hdr_property) -+ property = hdmi->plat_data->get_hdr_property(data); -+ else -+ return -EINVAL; -+ -+ if (hdmi->plat_data->get_hdr_blob) -+ blob = hdmi->plat_data->get_hdr_blob(data); -+ else -+ return -EINVAL; -+ -+ ret = drm_property_replace_global_blob(dev, &blob, size, metadata, -+ &connector->base, property); -+ return ret; -+} -+ -+static int dw_hdmi_connector_get_modes(struct drm_connector *connector) -+{ -+ struct dw_hdmi_qp *hdmi = -+ container_of(connector, struct dw_hdmi_qp, connector); -+ struct hdr_static_metadata *metedata = -+ &connector->hdr_sink_metadata.hdmi_type1; -+ struct edid *edid; -+ struct drm_display_mode *mode; -+ struct drm_display_info *info = &connector->display_info; -+ void *data = hdmi->plat_data->phy_data; -+ int i, ret = 0; -+ -+ if (!hdmi->ddc) -+ return 0; -+ -+ memset(metedata, 0, sizeof(*metedata)); -+ edid = drm_get_edid(connector, hdmi->ddc); -+ if (edid) { -+ dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", -+ edid->width_cm, edid->height_cm); -+ -+ hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); -+ hdmi->sink_has_audio = drm_detect_monitor_audio(edid); -+ drm_connector_update_edid_property(connector, edid); -+ cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); -+ if (hdmi->plat_data->get_edid_dsc_info) -+ hdmi->plat_data->get_edid_dsc_info(data, edid); -+ ret = drm_add_edid_modes(connector, edid); -+ dw_hdmi_update_hdr_property(connector); -+ if (ret > 0 && hdmi->plat_data->split_mode) { -+ struct dw_hdmi_qp *secondary = NULL; -+ void *secondary_data; -+ -+ if (hdmi->plat_data->left) -+ secondary = hdmi->plat_data->left; -+ else if (hdmi->plat_data->right) -+ secondary = hdmi->plat_data->right; -+ -+ if (!secondary) -+ return -ENOMEM; -+ secondary_data = secondary->plat_data->phy_data; -+ -+ list_for_each_entry(mode, &connector->probed_modes, head) -+ hdmi->plat_data->convert_to_split_mode(mode); -+ -+ secondary->sink_is_hdmi = drm_detect_hdmi_monitor(edid); -+ secondary->sink_has_audio = drm_detect_monitor_audio(edid); -+ cec_notifier_set_phys_addr_from_edid(secondary->cec_notifier, edid); -+ if (secondary->plat_data->get_edid_dsc_info) -+ secondary->plat_data->get_edid_dsc_info(secondary_data, edid); -+ } -+ kfree(edid); -+ } else { -+ hdmi->sink_is_hdmi = true; -+ hdmi->sink_has_audio = true; -+ -+ if (hdmi->plat_data->split_mode) { -+ if (hdmi->plat_data->left) { -+ hdmi->plat_data->left->sink_is_hdmi = true; -+ hdmi->plat_data->left->sink_has_audio = true; -+ } else if (hdmi->plat_data->right) { -+ hdmi->plat_data->right->sink_is_hdmi = true; -+ hdmi->plat_data->right->sink_has_audio = true; -+ } -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(dw_hdmi_default_modes); i++) { -+ const struct drm_display_mode *ptr = -+ &dw_hdmi_default_modes[i]; -+ -+ mode = drm_mode_duplicate(connector->dev, ptr); -+ if (mode) { -+ if (!i) -+ mode->type = DRM_MODE_TYPE_PREFERRED; -+ drm_mode_probed_add(connector, mode); -+ ret++; -+ } -+ } -+ if (ret > 0 && hdmi->plat_data->split_mode) { -+ struct drm_display_mode *mode; -+ -+ list_for_each_entry(mode, &connector->probed_modes, head) -+ hdmi->plat_data->convert_to_split_mode(mode); -+ } -+ info->edid_hdmi_rgb444_dc_modes = 0; -+ info->hdmi.y420_dc_modes = 0; -+ info->color_formats = 0; -+ -+ dev_info(hdmi->dev, "failed to get edid\n"); -+ } -+ -+ return ret; -+} -+ -+static int -+dw_hdmi_atomic_connector_set_property(struct drm_connector *connector, -+ struct drm_connector_state *state, -+ struct drm_property *property, -+ uint64_t val) -+{ -+ struct dw_hdmi_qp *hdmi = -+ container_of(connector, struct dw_hdmi_qp, connector); -+ const struct dw_hdmi_property_ops *ops = hdmi->plat_data->property_ops; -+ -+ if (ops && ops->set_property) -+ return ops->set_property(connector, state, property, -+ val, hdmi->plat_data->phy_data); -+ else -+ return -EINVAL; -+} -+ -+static int -+dw_hdmi_atomic_connector_get_property(struct drm_connector *connector, -+ const struct drm_connector_state *state, -+ struct drm_property *property, -+ uint64_t *val) -+{ -+ struct dw_hdmi_qp *hdmi = -+ container_of(connector, struct dw_hdmi_qp, connector); -+ const struct dw_hdmi_property_ops *ops = hdmi->plat_data->property_ops; -+ -+ if (ops && ops->get_property) -+ return ops->get_property(connector, state, property, -+ val, hdmi->plat_data->phy_data); -+ else -+ return -EINVAL; -+} -+ -+static int -+dw_hdmi_connector_set_property(struct drm_connector *connector, -+ struct drm_property *property, uint64_t val) -+{ -+ return dw_hdmi_atomic_connector_set_property(connector, NULL, -+ property, val); -+} -+ -+static void dw_hdmi_attach_properties(struct dw_hdmi_qp *hdmi) -+{ -+ unsigned int color = MEDIA_BUS_FMT_RGB888_1X24; -+ const struct dw_hdmi_property_ops *ops = -+ hdmi->plat_data->property_ops; -+ -+ if (ops && ops->attach_properties) -+ return ops->attach_properties(&hdmi->connector, color, 0, -+ hdmi->plat_data->phy_data); -+} -+ -+static void dw_hdmi_destroy_properties(struct dw_hdmi_qp *hdmi) -+{ -+ const struct dw_hdmi_property_ops *ops = -+ hdmi->plat_data->property_ops; -+ -+ if (ops && ops->destroy_properties) -+ return ops->destroy_properties(&hdmi->connector, -+ hdmi->plat_data->phy_data); -+} -+ -+static struct drm_encoder * -+dw_hdmi_connector_best_encoder(struct drm_connector *connector) -+{ -+ struct dw_hdmi_qp *hdmi = -+ container_of(connector, struct dw_hdmi_qp, connector); -+ -+ return hdmi->bridge.encoder; -+} -+ -+static bool dw_hdmi_color_changed(struct drm_connector *connector, -+ struct drm_atomic_state *state) -+{ -+ struct dw_hdmi_qp *hdmi = -+ container_of(connector, struct dw_hdmi_qp, connector); -+ void *data = hdmi->plat_data->phy_data; -+ struct drm_connector_state *old_state = -+ drm_atomic_get_old_connector_state(state, connector); -+ struct drm_connector_state *new_state = -+ drm_atomic_get_new_connector_state(state, connector); -+ bool ret = false; -+ -+ if (hdmi->plat_data->get_color_changed) -+ ret = hdmi->plat_data->get_color_changed(data); -+ -+ if (new_state->colorspace != old_state->colorspace) -+ ret = true; -+ -+ return ret; -+} -+ -+static bool hdr_metadata_equal(const struct drm_connector_state *old_state, -+ const struct drm_connector_state *new_state) -+{ -+ struct drm_property_blob *old_blob = old_state->hdr_output_metadata; -+ struct drm_property_blob *new_blob = new_state->hdr_output_metadata; -+ -+ if (!old_blob || !new_blob) -+ return old_blob == new_blob; -+ -+ if (old_blob->length != new_blob->length) -+ return false; -+ -+ return !memcmp(old_blob->data, new_blob->data, old_blob->length); -+} -+ -+static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, -+ struct drm_atomic_state *state) -+{ -+ struct drm_connector_state *old_state = -+ drm_atomic_get_old_connector_state(state, connector); -+ struct drm_connector_state *new_state = -+ drm_atomic_get_new_connector_state(state, connector); -+ struct drm_crtc *crtc = new_state->crtc; -+ struct drm_crtc_state *crtc_state; -+ struct dw_hdmi_qp *hdmi = -+ container_of(connector, struct dw_hdmi_qp, connector); -+ struct drm_display_mode *mode = NULL; -+ void *data = hdmi->plat_data->phy_data; -+ struct hdmi_vmode_qp *vmode = &hdmi->hdmi_data.video_mode; -+ -+ if (!crtc) -+ return 0; -+ -+ crtc_state = drm_atomic_get_crtc_state(state, crtc); -+ if (IS_ERR(crtc_state)) -+ return PTR_ERR(crtc_state); -+ -+ /* -+ * If HDMI is enabled in uboot, it's need to record -+ * drm_display_mode and set phy status to enabled. -+ */ -+ if (!vmode->mpixelclock) { -+ crtc_state = drm_atomic_get_crtc_state(state, crtc); -+ if (hdmi->plat_data->get_enc_in_encoding) -+ hdmi->hdmi_data.enc_in_encoding = -+ hdmi->plat_data->get_enc_in_encoding(data); -+ if (hdmi->plat_data->get_enc_out_encoding) -+ hdmi->hdmi_data.enc_out_encoding = -+ hdmi->plat_data->get_enc_out_encoding(data); -+ if (hdmi->plat_data->get_input_bus_format) -+ hdmi->hdmi_data.enc_in_bus_format = -+ hdmi->plat_data->get_input_bus_format(data); -+ if (hdmi->plat_data->get_output_bus_format) -+ hdmi->hdmi_data.enc_out_bus_format = -+ hdmi->plat_data->get_output_bus_format(data); -+ -+ mode = &crtc_state->mode; -+ if (hdmi->plat_data->split_mode) { -+ hdmi->plat_data->convert_to_origin_mode(mode); -+ mode->crtc_clock /= 2; -+ } -+ memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode)); -+ vmode->mpixelclock = mode->crtc_clock * 1000; -+ vmode->previous_pixelclock = mode->clock; -+ vmode->previous_tmdsclock = mode->clock; -+ vmode->mtmdsclock = hdmi_get_tmdsclock(hdmi, -+ vmode->mpixelclock); -+ if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) -+ vmode->mtmdsclock /= 2; -+ -+ /* -+ * If uboot logo enabled, atomic_enable won't be called, -+ * but atomic_disable will be called when hdmi plug out. -+ * That will cause dclk enable count is incorrect. So -+ * we should check ipi/link/video clk to determine whether -+ * uboot logo is enabled. -+ */ -+ if (hdmi->initialized && !hdmi->dclk_en) { -+ mutex_lock(&hdmi->audio_mutex); -+ if (hdmi->plat_data->dclk_set) -+ hdmi->plat_data->dclk_set(data, true); -+ hdmi->dclk_en = true; -+ mutex_unlock(&hdmi->audio_mutex); -+ } -+ } -+ -+ if (!hdr_metadata_equal(old_state, new_state) || -+ dw_hdmi_color_changed(connector, state)) { -+ crtc_state = drm_atomic_get_crtc_state(state, crtc); -+ if (IS_ERR(crtc_state)) -+ return PTR_ERR(crtc_state); -+ -+ crtc_state->mode_changed = true; -+ } -+ -+ return 0; -+} -+ -+static void dw_hdmi_connector_force(struct drm_connector *connector) -+{ -+ struct dw_hdmi_qp *hdmi = -+ container_of(connector, struct dw_hdmi_qp, connector); -+ -+ mutex_lock(&hdmi->mutex); -+ -+ if (hdmi->force != connector->force) { -+ if (!hdmi->disabled && connector->force == DRM_FORCE_OFF) -+ extcon_set_state_sync(hdmi->extcon, EXTCON_DISP_HDMI, -+ false); -+ else if (hdmi->disabled && connector->force == DRM_FORCE_ON) -+ extcon_set_state_sync(hdmi->extcon, EXTCON_DISP_HDMI, -+ true); -+ } -+ -+ hdmi->force = connector->force; -+ mutex_unlock(&hdmi->mutex); -+} -+ -+static int dw_hdmi_qp_fill_modes(struct drm_connector *connector, u32 max_x, -+ u32 max_y) -+{ -+ return drm_helper_probe_single_connector_modes(connector, 9000, 9000); -+} -+ -+static const struct drm_connector_funcs dw_hdmi_connector_funcs = { -+ .fill_modes = dw_hdmi_qp_fill_modes, -+ .detect = dw_hdmi_connector_detect, -+ .destroy = drm_connector_cleanup, -+ .force = dw_hdmi_connector_force, -+ .reset = drm_atomic_helper_connector_reset, -+ .set_property = dw_hdmi_connector_set_property, -+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, -+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -+ .atomic_set_property = dw_hdmi_atomic_connector_set_property, -+ .atomic_get_property = dw_hdmi_atomic_connector_get_property, -+}; -+ -+static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = { -+ .get_modes = dw_hdmi_connector_get_modes, -+ .best_encoder = dw_hdmi_connector_best_encoder, -+ .atomic_check = dw_hdmi_connector_atomic_check, -+}; -+ -+static int dw_hdmi_qp_bridge_attach(struct drm_bridge *bridge, -+ enum drm_bridge_attach_flags flags) -+{ -+ struct dw_hdmi_qp *hdmi = bridge->driver_private; -+ struct drm_encoder *encoder = bridge->encoder; -+ struct drm_connector *connector = &hdmi->connector; -+ struct cec_connector_info conn_info; -+ struct cec_notifier *notifier; -+ -+ if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) -+ return 0; -+ -+ connector->interlace_allowed = 1; -+ connector->polled = DRM_CONNECTOR_POLL_HPD; -+ -+ drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs); -+ -+ // [CC:] use drm_connector_init_with_ddc or drmm_connector_init -+ // to provide ddc reference -+ drm_connector_init_with_ddc(bridge->dev, connector, -+ &dw_hdmi_connector_funcs, -+ DRM_MODE_CONNECTOR_HDMIA, -+ hdmi->ddc); -+ -+ drm_connector_attach_encoder(connector, encoder); -+ dw_hdmi_attach_properties(hdmi); -+ -+ cec_fill_conn_info_from_drm(&conn_info, connector); -+ notifier = cec_notifier_conn_register(hdmi->dev, NULL, &conn_info); -+ if (!notifier) -+ return -ENOMEM; -+ -+ mutex_lock(&hdmi->cec_notifier_mutex); -+ hdmi->cec_notifier = notifier; -+ mutex_unlock(&hdmi->cec_notifier_mutex); -+ -+ return 0; -+} -+ -+static void dw_hdmi_qp_bridge_detach(struct drm_bridge *bridge) -+{ -+ struct dw_hdmi_qp *hdmi = bridge->driver_private; -+ -+ mutex_lock(&hdmi->cec_notifier_mutex); -+ cec_notifier_conn_unregister(hdmi->cec_notifier); -+ hdmi->cec_notifier = NULL; -+ mutex_unlock(&hdmi->cec_notifier_mutex); -+} -+ -+static void dw_hdmi_qp_bridge_mode_set(struct drm_bridge *bridge, -+ const struct drm_display_mode *orig_mode, -+ const struct drm_display_mode *mode) -+{ -+ struct dw_hdmi_qp *hdmi = bridge->driver_private; -+ -+ mutex_lock(&hdmi->mutex); -+ -+ /* Store the display mode for plugin/DKMS poweron events */ -+ memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode)); -+ if (hdmi->plat_data->split_mode) -+ hdmi->plat_data->convert_to_origin_mode(&hdmi->previous_mode); -+ -+ mutex_unlock(&hdmi->mutex); -+} -+ -+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) -+{ -+ return MODE_OK; -+} -+ -+static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge, -+ struct drm_bridge_state *old_state) -+{ -+ struct dw_hdmi_qp *hdmi = bridge->driver_private; -+ struct drm_atomic_state *state = old_state->base.state; -+ struct drm_connector *connector; -+ void *data = hdmi->plat_data->phy_data; -+ -+ connector = drm_atomic_get_new_connector_for_encoder(state, -+ bridge->encoder); -+ -+ mutex_lock(&hdmi->mutex); -+ hdmi->curr_conn = connector; -+ dw_hdmi_qp_setup(hdmi, hdmi->curr_conn, &hdmi->previous_mode); -+ hdmi->disabled = false; -+ mutex_unlock(&hdmi->mutex); -+ -+ if (!hdmi->dclk_en) { -+ mutex_lock(&hdmi->audio_mutex); -+ if (hdmi->plat_data->dclk_set) -+ hdmi->plat_data->dclk_set(data, true); -+ hdmi->dclk_en = true; -+ mutex_unlock(&hdmi->audio_mutex); -+ } -+ -+ extcon_set_state_sync(hdmi->extcon, EXTCON_DISP_HDMI, true); -+ handle_plugged_change(hdmi, true); -+} -+ -+static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge, -+ struct drm_bridge_state *old_state) -+{ -+ struct dw_hdmi_qp *hdmi = bridge->driver_private; -+ void *data = hdmi->plat_data->phy_data; -+ -+ extcon_set_state_sync(hdmi->extcon, EXTCON_DISP_HDMI, false); -+ handle_plugged_change(hdmi, false); -+ mutex_lock(&hdmi->mutex); -+ -+ hdmi->curr_conn = NULL; -+ -+ if (hdmi->dclk_en) { -+ mutex_lock(&hdmi->audio_mutex); -+ if (hdmi->plat_data->dclk_set) -+ hdmi->plat_data->dclk_set(data, false); -+ hdmi->dclk_en = false; -+ mutex_unlock(&hdmi->audio_mutex); -+ }; -+ -+ if (hdmi->phy.ops->disable) -+ hdmi->phy.ops->disable(hdmi, hdmi->phy.data); -+ hdmi->disabled = true; -+ mutex_unlock(&hdmi->mutex); -+} -+ -+static const struct drm_bridge_funcs dw_hdmi_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_qp_bridge_detach, -+ .mode_set = dw_hdmi_qp_bridge_mode_set, -+ .mode_valid = dw_hdmi_qp_bridge_mode_valid, -+ .atomic_enable = dw_hdmi_qp_bridge_atomic_enable, -+ .atomic_disable = dw_hdmi_qp_bridge_atomic_disable, -+}; -+ -+void dw_hdmi_qp_set_cec_adap(struct dw_hdmi_qp *hdmi, struct cec_adapter *adap) -+{ -+ hdmi->cec_adap = adap; -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_cec_adap); -+ -+static irqreturn_t dw_hdmi_qp_main_hardirq(int irq, void *dev_id) -+{ -+ struct dw_hdmi_qp *hdmi = dev_id; -+ struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; -+ u32 stat; -+ -+ stat = hdmi_readl(hdmi, MAINUNIT_1_INT_STATUS); -+ -+ i2c->stat = stat & (I2CM_OP_DONE_IRQ | I2CM_READ_REQUEST_IRQ | -+ I2CM_NACK_RCVD_IRQ); -+ hdmi->scdc_intr = stat & (SCDC_UPD_FLAGS_RD_IRQ | -+ SCDC_UPD_FLAGS_CHG_IRQ | -+ SCDC_UPD_FLAGS_CLR_IRQ | -+ SCDC_RR_REPLY_STOP_IRQ | -+ SCDC_NACK_RCVD_IRQ); -+ hdmi->flt_intr = stat & (FLT_EXIT_TO_LTSP_IRQ | -+ FLT_EXIT_TO_LTS4_IRQ | -+ FLT_EXIT_TO_LTSL_IRQ); -+ -+ // dev_dbg(hdmi->dev, "i2c main unit irq:%#x\n", stat); -+ if (i2c->stat) { -+ hdmi_writel(hdmi, i2c->stat, MAINUNIT_1_INT_CLEAR); -+ complete(&i2c->cmp); -+ } -+ -+ if (hdmi->flt_intr) { -+ dev_dbg(hdmi->dev, "i2c flt irq:%#x\n", hdmi->flt_intr); -+ hdmi_writel(hdmi, hdmi->flt_intr, MAINUNIT_1_INT_CLEAR); -+ complete(&hdmi->flt_cmp); -+ } -+ -+ if (hdmi->scdc_intr) { -+ u8 val; -+ -+ dev_dbg(hdmi->dev, "i2c scdc irq:%#x\n", hdmi->scdc_intr); -+ hdmi_writel(hdmi, hdmi->scdc_intr, MAINUNIT_1_INT_CLEAR); -+ val = hdmi_readl(hdmi, SCDC_STATUS0); -+ -+ /* frl start */ -+ if (val & BIT(4)) { -+ hdmi_modb(hdmi, 0, SCDC_UPD_FLAGS_POLL_EN | -+ SCDC_UPD_FLAGS_AUTO_CLR, SCDC_CONFIG0); -+ hdmi_modb(hdmi, 0, SCDC_UPD_FLAGS_RD_IRQ, -+ MAINUNIT_1_INT_MASK_N); -+ dev_info(hdmi->dev, "frl start\n"); -+ } -+ -+ } -+ -+ if (stat) -+ return IRQ_HANDLED; -+ -+ return IRQ_NONE; -+} -+ -+static irqreturn_t dw_hdmi_qp_avp_hardirq(int irq, void *dev_id) -+{ -+ struct dw_hdmi_qp *hdmi = dev_id; -+ u32 stat; -+ -+ stat = hdmi_readl(hdmi, AVP_1_INT_STATUS); -+ if (stat) { -+ dev_dbg(hdmi->dev, "HDCP irq %#x\n", stat); -+ stat &= ~stat; -+ hdmi_writel(hdmi, stat, AVP_1_INT_MASK_N); -+ return IRQ_WAKE_THREAD; -+ } -+ -+ return IRQ_NONE; -+} -+ -+static irqreturn_t dw_hdmi_qp_earc_hardirq(int irq, void *dev_id) -+{ -+ struct dw_hdmi_qp *hdmi = dev_id; -+ u32 stat; -+ -+ stat = hdmi_readl(hdmi, EARCRX_0_INT_STATUS); -+ if (stat) { -+ dev_dbg(hdmi->dev, "earc irq %#x\n", stat); -+ stat &= ~stat; -+ hdmi_writel(hdmi, stat, EARCRX_0_INT_MASK_N); -+ return IRQ_WAKE_THREAD; -+ } -+ -+ return IRQ_NONE; -+} -+ -+static irqreturn_t dw_hdmi_qp_avp_irq(int irq, void *dev_id) -+{ -+ struct dw_hdmi_qp *hdmi = dev_id; -+ u32 stat; -+ -+ stat = hdmi_readl(hdmi, AVP_1_INT_STATUS); -+ -+ if (!stat) -+ return IRQ_NONE; -+ -+ hdmi_writel(hdmi, stat, AVP_1_INT_CLEAR); -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t dw_hdmi_qp_earc_irq(int irq, void *dev_id) -+{ -+ struct dw_hdmi_qp *hdmi = dev_id; -+ u32 stat; -+ -+ stat = hdmi_readl(hdmi, EARCRX_0_INT_STATUS); -+ -+ if (!stat) -+ return IRQ_NONE; -+ -+ hdmi_writel(hdmi, stat, EARCRX_0_INT_CLEAR); -+ -+ hdmi->earc_intr = stat; -+ complete(&hdmi->earc_cmp); -+ -+ return IRQ_HANDLED; -+} -+ -+static int dw_hdmi_detect_phy(struct dw_hdmi_qp *hdmi) -+{ -+ u8 phy_type; -+ -+ phy_type = hdmi->plat_data->phy_force_vendor ? -+ DW_HDMI_PHY_VENDOR_PHY : 0; -+ -+ if (phy_type == DW_HDMI_PHY_VENDOR_PHY) { -+ /* Vendor PHYs require support from the glue layer. */ -+ if (!hdmi->plat_data->qp_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->qp_phy_ops; -+ hdmi->phy.data = hdmi->plat_data->phy_data; -+ hdmi->phy.name = hdmi->plat_data->phy_name; -+ } -+ -+ return 0; -+} -+ -+void dw_hdmi_qp_cec_set_hpd(struct dw_hdmi_qp *hdmi, bool plug_in, bool change) -+{ -+ enum drm_connector_status status = plug_in ? -+ connector_status_connected : connector_status_disconnected; -+ -+ if (!plug_in) -+ cec_notifier_set_phys_addr(hdmi->cec_notifier, -+ CEC_PHYS_ADDR_INVALID); -+ -+ if (hdmi->bridge.dev) { -+ if (change && hdmi->cec_adap && hdmi->cec_adap->devnode.registered) -+ cec_queue_pin_hpd_event(hdmi->cec_adap, plug_in, ktime_get()); -+ drm_bridge_hpd_notify(&hdmi->bridge, status); -+ } -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_cec_set_hpd); -+ -+// static void dw_hdmi_qp_cec_enable(struct dw_hdmi_qp *hdmi) -+// { -+// mutex_lock(&hdmi->mutex); -+// hdmi_modb(hdmi, 0, CEC_SWDISABLE, GLOBAL_SWDISABLE); -+// mutex_unlock(&hdmi->mutex); -+// } -+// -+// static void dw_hdmi_qp_cec_disable(struct dw_hdmi_qp *hdmi) -+// { -+// mutex_lock(&hdmi->mutex); -+// hdmi_modb(hdmi, CEC_SWDISABLE, CEC_SWDISABLE, GLOBAL_SWDISABLE); -+// mutex_unlock(&hdmi->mutex); -+// } -+// -+// static const struct dw_hdmi_qp_cec_ops dw_hdmi_qp_cec_ops = { -+// .enable = dw_hdmi_qp_cec_enable, -+// .disable = dw_hdmi_qp_cec_disable, -+// .write = hdmi_writel, -+// .read = hdmi_readl, -+// }; -+ -+static const struct regmap_config hdmi_regmap_config = { -+ .reg_bits = 32, -+ .val_bits = 32, -+ .reg_stride = 4, -+ .max_register = EARCRX_1_INT_FORCE, -+}; -+ -+struct dw_hdmi_qp_reg_table { -+ int reg_base; -+ int reg_end; -+}; -+ -+static const struct dw_hdmi_qp_reg_table hdmi_reg_table[] = { -+ {0x0, 0xc}, -+ {0x14, 0x1c}, -+ {0x44, 0x48}, -+ {0x50, 0x58}, -+ {0x80, 0x84}, -+ {0xa0, 0xc4}, -+ {0xe0, 0xe8}, -+ {0xf0, 0x118}, -+ {0x140, 0x140}, -+ {0x150, 0x150}, -+ {0x160, 0x168}, -+ {0x180, 0x180}, -+ {0x800, 0x800}, -+ {0x808, 0x808}, -+ {0x814, 0x814}, -+ {0x81c, 0x824}, -+ {0x834, 0x834}, -+ {0x840, 0x864}, -+ {0x86c, 0x86c}, -+ {0x880, 0x89c}, -+ {0x8e0, 0x8e8}, -+ {0x900, 0x900}, -+ {0x908, 0x90c}, -+ {0x920, 0x938}, -+ {0x920, 0x938}, -+ {0x960, 0x960}, -+ {0x968, 0x968}, -+ {0xa20, 0xa20}, -+ {0xa30, 0xa30}, -+ {0xa40, 0xa40}, -+ {0xa54, 0xa54}, -+ {0xa80, 0xaac}, -+ {0xab4, 0xab8}, -+ {0xb00, 0xcbc}, -+ {0xce0, 0xce0}, -+ {0xd00, 0xddc}, -+ {0xe20, 0xe24}, -+ {0xe40, 0xe44}, -+ {0xe4c, 0xe4c}, -+ {0xe60, 0xe80}, -+ {0xea0, 0xf24}, -+ {0x1004, 0x100c}, -+ {0x1020, 0x1030}, -+ {0x1040, 0x1050}, -+ {0x1060, 0x1068}, -+ {0x1800, 0x1820}, -+ {0x182c, 0x182c}, -+ {0x1840, 0x1940}, -+ {0x1960, 0x1a60}, -+ {0x1b00, 0x1b00}, -+ {0x1c00, 0x1c00}, -+ {0x3000, 0x3000}, -+ {0x3010, 0x3014}, -+ {0x3020, 0x3024}, -+ {0x3800, 0x3800}, -+ {0x3810, 0x3814}, -+ {0x3820, 0x3824}, -+ {0x3830, 0x3834}, -+ {0x3840, 0x3844}, -+ {0x3850, 0x3854}, -+ {0x3860, 0x3864}, -+ {0x3870, 0x3874}, -+ {0x4000, 0x4004}, -+ {0x4800, 0x4800}, -+ {0x4810, 0x4814}, -+}; -+ -+static int dw_hdmi_ctrl_show(struct seq_file *s, void *v) -+{ -+ struct dw_hdmi_qp *hdmi = s->private; -+ u32 i = 0, j = 0, val = 0; -+ -+ seq_puts(s, "\n---------------------------------------------------"); -+ -+ for (i = 0; i < ARRAY_SIZE(hdmi_reg_table); i++) { -+ for (j = hdmi_reg_table[i].reg_base; -+ j <= hdmi_reg_table[i].reg_end; j += 4) { -+ val = hdmi_readl(hdmi, j); -+ -+ if ((j - hdmi_reg_table[i].reg_base) % 16 == 0) -+ seq_printf(s, "\n>>>hdmi_ctl %04x:", j); -+ seq_printf(s, " %08x", val); -+ } -+ } -+ seq_puts(s, "\n---------------------------------------------------\n"); -+ -+ return 0; -+} -+ -+static int dw_hdmi_ctrl_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, dw_hdmi_ctrl_show, inode->i_private); -+} -+ -+static ssize_t -+dw_hdmi_ctrl_write(struct file *file, const char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ struct dw_hdmi_qp *hdmi = -+ ((struct seq_file *)file->private_data)->private; -+ u32 reg, val; -+ char kbuf[25]; -+ -+ if (count > 24) { -+ dev_err(hdmi->dev, "out of buf range\n"); -+ return count; -+ } -+ -+ if (copy_from_user(kbuf, buf, count)) -+ return -EFAULT; -+ kbuf[count - 1] = '\0'; -+ -+ if (sscanf(kbuf, "%x %x", ®, &val) == -1) -+ return -EFAULT; -+ if (reg > EARCRX_1_INT_FORCE) { -+ dev_err(hdmi->dev, "it is no a hdmi register\n"); -+ return count; -+ } -+ dev_info(hdmi->dev, "/**********hdmi register config******/"); -+ dev_info(hdmi->dev, "\n reg=%x val=%x\n", reg, val); -+ hdmi_writel(hdmi, val, reg); -+ return count; -+} -+ -+static const struct file_operations dw_hdmi_ctrl_fops = { -+ .owner = THIS_MODULE, -+ .open = dw_hdmi_ctrl_open, -+ .read = seq_read, -+ .write = dw_hdmi_ctrl_write, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static int dw_hdmi_status_show(struct seq_file *s, void *v) -+{ -+ struct dw_hdmi_qp *hdmi = s->private; -+ u32 val; -+ -+ seq_puts(s, "PHY: "); -+ if (hdmi->disabled) { -+ seq_puts(s, "disabled\n"); -+ return 0; -+ } -+ seq_puts(s, "enabled\t\t\tMode: "); -+ if (hdmi->sink_is_hdmi) -+ seq_puts(s, "HDMI\n"); -+ else -+ seq_puts(s, "DVI\n"); -+ -+ if (hdmi->hdmi_data.video_mode.mpixelclock > 600000000) { -+ seq_printf(s, "FRL Mode Pixel Clk: %luHz\n", -+ hdmi->hdmi_data.video_mode.mpixelclock); -+ } else { -+ if (hdmi->hdmi_data.video_mode.mtmdsclock > 340000000) -+ val = hdmi->hdmi_data.video_mode.mtmdsclock / 4; -+ else -+ val = hdmi->hdmi_data.video_mode.mtmdsclock; -+ seq_printf(s, "TMDS Mode Pixel Clk: %luHz\t\tTMDS Clk: %uHz\n", -+ hdmi->hdmi_data.video_mode.mpixelclock, val); -+ } -+ -+ seq_puts(s, "Color Format: "); -+ if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) -+ seq_puts(s, "RGB"); -+ else if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) -+ seq_puts(s, "YUV444"); -+ else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) -+ seq_puts(s, "YUV422"); -+ else if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) -+ seq_puts(s, "YUV420"); -+ else -+ seq_puts(s, "UNKNOWN"); -+ val = hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format); -+ seq_printf(s, "\t\tColor Depth: %d bit\n", val); -+ seq_puts(s, "Colorimetry: "); -+ switch (hdmi->hdmi_data.enc_out_encoding) { -+ case V4L2_YCBCR_ENC_601: -+ seq_puts(s, "ITU.BT601"); -+ break; -+ case V4L2_YCBCR_ENC_709: -+ seq_puts(s, "ITU.BT709"); -+ break; -+ case V4L2_YCBCR_ENC_BT2020: -+ seq_puts(s, "ITU.BT2020"); -+ break; -+ default: /* Carries no data */ -+ seq_puts(s, "ITU.BT601"); -+ break; -+ } -+ -+ seq_puts(s, "\t\tEOTF: "); -+ -+ val = hdmi_readl(hdmi, PKTSCHED_PKT_EN); -+ if (!(val & PKTSCHED_DRMI_TX_EN)) { -+ seq_puts(s, "Off\n"); -+ return 0; -+ } -+ -+ val = hdmi_readl(hdmi, PKT_DRMI_CONTENTS1); -+ val = (val >> 8) & 0x7; -+ switch (val) { -+ case HDMI_EOTF_TRADITIONAL_GAMMA_SDR: -+ seq_puts(s, "SDR"); -+ break; -+ case HDMI_EOTF_TRADITIONAL_GAMMA_HDR: -+ seq_puts(s, "HDR"); -+ break; -+ case HDMI_EOTF_SMPTE_ST2084: -+ seq_puts(s, "ST2084"); -+ break; -+ case HDMI_EOTF_BT_2100_HLG: -+ seq_puts(s, "HLG"); -+ break; -+ default: -+ seq_puts(s, "Not Defined\n"); -+ return 0; -+ } -+ -+ val = hdmi_readl(hdmi, PKT_DRMI_CONTENTS1); -+ val = (val >> 16) & 0xffff; -+ seq_printf(s, "\nx0: %d", val); -+ val = hdmi_readl(hdmi, PKT_DRMI_CONTENTS2); -+ val = val & 0xffff; -+ seq_printf(s, "\t\t\t\ty0: %d\n", val); -+ val = hdmi_readl(hdmi, PKT_DRMI_CONTENTS2); -+ val = (val >> 16) & 0xffff; -+ seq_printf(s, "x1: %d", val); -+ val = hdmi_readl(hdmi, PKT_DRMI_CONTENTS3); -+ val = val & 0xffff; -+ seq_printf(s, "\t\t\t\ty1: %d\n", val); -+ val = hdmi_readl(hdmi, PKT_DRMI_CONTENTS3); -+ val = (val >> 16) & 0xffff; -+ seq_printf(s, "x2: %d", val); -+ val = hdmi_readl(hdmi, PKT_DRMI_CONTENTS4); -+ val = val & 0xffff; -+ seq_printf(s, "\t\t\t\ty2: %d\n", val); -+ val = hdmi_readl(hdmi, PKT_DRMI_CONTENTS4); -+ val = (val >> 16) & 0xffff; -+ seq_printf(s, "white x: %d", val); -+ val = hdmi_readl(hdmi, PKT_DRMI_CONTENTS5); -+ val = val & 0xffff; -+ seq_printf(s, "\t\t\twhite y: %d\n", val); -+ val = hdmi_readl(hdmi, PKT_DRMI_CONTENTS5); -+ val = (val >> 16) & 0xffff; -+ seq_printf(s, "max lum: %d", val); -+ val = hdmi_readl(hdmi, PKT_DRMI_CONTENTS6); -+ val = val & 0xffff; -+ seq_printf(s, "\t\t\tmin lum: %d\n", val); -+ val = hdmi_readl(hdmi, PKT_DRMI_CONTENTS6); -+ val = (val >> 16) & 0xffff; -+ seq_printf(s, "max cll: %d", val); -+ val = hdmi_readl(hdmi, PKT_DRMI_CONTENTS7); -+ val = val & 0xffff; -+ seq_printf(s, "\t\t\tmax fall: %d\n", val); -+ return 0; -+} -+ -+static int dw_hdmi_status_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, dw_hdmi_status_show, inode->i_private); -+} -+ -+static const struct file_operations dw_hdmi_status_fops = { -+ .owner = THIS_MODULE, -+ .open = dw_hdmi_status_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static void dw_hdmi_register_debugfs(struct device *dev, struct dw_hdmi_qp *hdmi) -+{ -+ u8 buf[11]; -+ -+ snprintf(buf, sizeof(buf), "dw-hdmi%d", hdmi->plat_data->id); -+ hdmi->debugfs_dir = debugfs_create_dir(buf, NULL); -+ if (IS_ERR(hdmi->debugfs_dir)) { -+ dev_err(dev, "failed to create debugfs dir!\n"); -+ return; -+ } -+ -+ debugfs_create_file("status", 0400, hdmi->debugfs_dir, -+ hdmi, &dw_hdmi_status_fops); -+ debugfs_create_file("ctrl", 0600, hdmi->debugfs_dir, -+ hdmi, &dw_hdmi_ctrl_fops); -+} -+ -+static struct dw_hdmi_qp * -+__dw_hdmi_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_qp *hdmi; -+ // struct dw_hdmi_qp_i2s_audio_data audio; -+ // struct platform_device_info pdevinfo; -+ // struct dw_hdmi_qp_cec_data cec; -+ struct resource *iores = NULL; -+ int irq; -+ int ret; -+ -+ hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); -+ if (!hdmi) -+ return ERR_PTR(-ENOMEM); -+ -+ hdmi->connector.stereo_allowed = 1; -+ hdmi->plat_data = plat_data; -+ hdmi->dev = dev; -+ hdmi->sample_rate = 48000; -+ hdmi->disabled = true; -+ -+ mutex_init(&hdmi->mutex); -+ mutex_init(&hdmi->audio_mutex); -+ mutex_init(&hdmi->cec_notifier_mutex); -+ -+ 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 = &hdmi_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; -+ } -+ -+ ret = dw_hdmi_detect_phy(hdmi); -+ if (ret < 0) -+ goto err_res; -+ -+ hdmi_writel(hdmi, 0, MAINUNIT_0_INT_MASK_N); -+ hdmi_writel(hdmi, 0, MAINUNIT_1_INT_MASK_N); -+ hdmi_writel(hdmi, 428571429, TIMER_BASE_CONFIG0); -+ if ((hdmi_readl(hdmi, CMU_STATUS) & DISPLAY_CLK_MONITOR) == DISPLAY_CLK_LOCKED) { -+ hdmi->initialized = true; -+ hdmi->disabled = false; -+ } -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) { -+ ret = irq; -+ goto err_res; -+ } -+ -+ hdmi->avp_irq = irq; -+ ret = devm_request_threaded_irq(dev, hdmi->avp_irq, -+ dw_hdmi_qp_avp_hardirq, -+ dw_hdmi_qp_avp_irq, IRQF_SHARED, -+ dev_name(dev), hdmi); -+ if (ret) -+ goto err_res; -+ -+ irq = platform_get_irq(pdev, 1); -+ if (irq < 0) { -+ ret = irq; -+ goto err_res; -+ } -+ -+ // cec.irq = irq; -+ -+ irq = platform_get_irq(pdev, 2); -+ if (irq < 0) { -+ ret = irq; -+ goto err_res; -+ } -+ -+ hdmi->earc_irq = irq; -+ ret = devm_request_threaded_irq(dev, hdmi->earc_irq, -+ dw_hdmi_qp_earc_hardirq, -+ dw_hdmi_qp_earc_irq, IRQF_SHARED, -+ dev_name(dev), hdmi); -+ if (ret) -+ goto err_res; -+ -+ irq = platform_get_irq(pdev, 3); -+ if (irq < 0) { -+ ret = irq; -+ goto err_res; -+ } -+ -+ hdmi->main_irq = irq; -+ ret = devm_request_threaded_irq(dev, hdmi->main_irq, -+ dw_hdmi_qp_main_hardirq, NULL, -+ IRQF_SHARED, dev_name(dev), hdmi); -+ if (ret) -+ goto err_res; -+ -+ hdmi_init_clk_regenerator(hdmi); -+ -+ /* If DDC bus is not specified, try to register HDMI I2C bus */ -+ if (!hdmi->ddc) { -+ hdmi->ddc = dw_hdmi_i2c_adapter(hdmi); -+ if (IS_ERR(hdmi->ddc)) -+ hdmi->ddc = NULL; -+ /* -+ * Read high and low time from device tree. If not available use -+ * the default timing scl clock rate is about 99.6KHz. -+ */ -+ if (of_property_read_u32(np, "ddc-i2c-scl-high-time-ns", -+ &hdmi->i2c->scl_high_ns)) -+ hdmi->i2c->scl_high_ns = 4708; -+ if (of_property_read_u32(np, "ddc-i2c-scl-low-time-ns", -+ &hdmi->i2c->scl_low_ns)) -+ hdmi->i2c->scl_low_ns = 4916; -+ } -+ -+ hdmi->bridge.driver_private = hdmi; -+ hdmi->bridge.funcs = &dw_hdmi_bridge_funcs; -+#ifdef CONFIG_OF -+ hdmi->bridge.of_node = pdev->dev.of_node; -+#endif -+ -+ if (hdmi->phy.ops->setup_hpd) -+ hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); -+ -+ hdmi->connector.ycbcr_420_allowed = hdmi->plat_data->ycbcr_420_allowed; -+ -+ // audio.hdmi = hdmi; -+ // audio.eld = hdmi->connector.eld; -+ // audio.write = hdmi_writel; -+ // audio.read = hdmi_readl; -+ // audio.mod = hdmi_modb; -+ // hdmi->enable_audio = dw_hdmi_i2s_audio_enable; -+ // hdmi->disable_audio = dw_hdmi_i2s_audio_disable; -+ -+ // memset(&pdevinfo, 0, sizeof(pdevinfo)); -+ // pdevinfo.parent = dev; -+ // pdevinfo.id = PLATFORM_DEVID_AUTO; -+ // pdevinfo.name = "dw-hdmi-qp-i2s-audio"; -+ // pdevinfo.data = &audio; -+ // pdevinfo.size_data = sizeof(audio); -+ // pdevinfo.dma_mask = DMA_BIT_MASK(32); -+ // hdmi->audio = platform_device_register_full(&pdevinfo); -+ -+ hdmi->extcon = devm_extcon_dev_allocate(hdmi->dev, dw_hdmi_cable); -+ if (IS_ERR(hdmi->extcon)) { -+ dev_err(hdmi->dev, "allocate extcon failed\n"); -+ ret = PTR_ERR(hdmi->extcon); -+ goto err_res; -+ } -+ -+ ret = devm_extcon_dev_register(hdmi->dev, hdmi->extcon); -+ if (ret) { -+ dev_err(hdmi->dev, "failed to register extcon: %d\n", ret); -+ goto err_res; -+ } -+ -+ ret = extcon_set_property_capability(hdmi->extcon, EXTCON_DISP_HDMI, -+ EXTCON_PROP_DISP_HPD); -+ if (ret) { -+ dev_err(hdmi->dev, -+ "failed to set USB property capability: %d\n", ret); -+ goto err_res; -+ } -+ -+ // cec.hdmi = hdmi; -+ // cec.ops = &dw_hdmi_qp_cec_ops; -+ // pdevinfo.name = "dw-hdmi-qp-cec"; -+ // pdevinfo.data = &cec; -+ // pdevinfo.size_data = sizeof(cec); -+ // pdevinfo.dma_mask = 0; -+ // hdmi->cec = platform_device_register_full(&pdevinfo); -+ -+ /* Reset HDMI DDC I2C master controller and mute I2CM interrupts */ -+ if (hdmi->i2c) -+ dw_hdmi_i2c_init(hdmi); -+ -+ init_completion(&hdmi->flt_cmp); -+ init_completion(&hdmi->earc_cmp); -+ -+ if (of_property_read_bool(np, "scramble-low-rates")) -+ hdmi->scramble_low_rates = true; -+ -+ dw_hdmi_register_debugfs(dev, hdmi); -+ -+ return hdmi; -+ -+err_res: -+ if (hdmi->i2c) -+ i2c_del_adapter(&hdmi->i2c->adap); -+ else -+ i2c_put_adapter(hdmi->ddc); -+ -+ return ERR_PTR(ret); -+} -+ -+static void __dw_hdmi_remove(struct dw_hdmi_qp *hdmi) -+{ -+ if (hdmi->avp_irq) -+ disable_irq(hdmi->avp_irq); -+ -+ if (hdmi->main_irq) -+ disable_irq(hdmi->main_irq); -+ -+ if (hdmi->earc_irq) -+ disable_irq(hdmi->earc_irq); -+ -+ debugfs_remove_recursive(hdmi->debugfs_dir); -+ -+ if (!hdmi->plat_data->first_screen) { -+ dw_hdmi_destroy_properties(hdmi); -+ hdmi->connector.funcs->destroy(&hdmi->connector); -+ } -+ -+ if (hdmi->audio && !IS_ERR(hdmi->audio)) -+ platform_device_unregister(hdmi->audio); -+ -+ // [CC:] dw_hdmi_rockchip_unbind() also calls drm_encoder_cleanup() -+ // and causes a seg fault due to NULL ptr dererence -+ // if (hdmi->bridge.encoder && !hdmi->plat_data->first_screen) -+ // hdmi->bridge.encoder->funcs->destroy(hdmi->bridge.encoder); -+ // -+ 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); -+} -+ -+/* ----------------------------------------------------------------------------- -+ * Bind/unbind API, used from platforms based on the component framework. -+ */ -+struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, -+ struct drm_encoder *encoder, -+ struct dw_hdmi_plat_data *plat_data) -+{ -+ struct dw_hdmi_qp *hdmi; -+ int ret; -+ -+ hdmi = __dw_hdmi_probe(pdev, plat_data); -+ if (IS_ERR(hdmi)) -+ return hdmi; -+ -+ if (!plat_data->first_screen) { -+ ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, 0); -+ if (ret) { -+ __dw_hdmi_remove(hdmi); -+ dev_err(hdmi->dev, "Failed to initialize bridge with drm\n"); -+ return ERR_PTR(ret); -+ } -+ -+ plat_data->connector = &hdmi->connector; -+ } -+ -+ if (plat_data->split_mode && !hdmi->plat_data->first_screen) { -+ struct dw_hdmi_qp *secondary = NULL; -+ -+ if (hdmi->plat_data->left) -+ secondary = hdmi->plat_data->left; -+ else if (hdmi->plat_data->right) -+ secondary = hdmi->plat_data->right; -+ -+ if (!secondary) -+ return ERR_PTR(-ENOMEM); -+ ret = drm_bridge_attach(encoder, &secondary->bridge, &hdmi->bridge, -+ DRM_BRIDGE_ATTACH_NO_CONNECTOR); -+ if (ret) -+ return ERR_PTR(ret); -+ } -+ -+ return hdmi; -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind); -+ -+void dw_hdmi_qp_unbind(struct dw_hdmi_qp *hdmi) -+{ -+ __dw_hdmi_remove(hdmi); -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_unbind); -+ -+void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi) -+{ -+ if (!hdmi) { -+ dev_warn(dev, "Hdmi has not been initialized\n"); -+ return; -+ } -+ -+ mutex_lock(&hdmi->mutex); -+ -+ /* -+ * When system shutdown, hdmi should be disabled. -+ * When system suspend, dw_hdmi_qp_bridge_disable will disable hdmi first. -+ * To prevent duplicate operation, we should determine whether hdmi -+ * has been disabled. -+ */ -+ if (!hdmi->disabled) -+ hdmi->disabled = true; -+ mutex_unlock(&hdmi->mutex); -+ -+ if (hdmi->avp_irq) -+ disable_irq(hdmi->avp_irq); -+ -+ if (hdmi->main_irq) -+ disable_irq(hdmi->main_irq); -+ -+ if (hdmi->earc_irq) -+ disable_irq(hdmi->earc_irq); -+ -+ pinctrl_pm_select_sleep_state(dev); -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_suspend); -+ -+void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi) -+{ -+ if (!hdmi) { -+ dev_warn(dev, "Hdmi has not been initialized\n"); -+ return; -+ } -+ -+ hdmi_writel(hdmi, 0, MAINUNIT_0_INT_MASK_N); -+ hdmi_writel(hdmi, 0, MAINUNIT_1_INT_MASK_N); -+ hdmi_writel(hdmi, 428571429, TIMER_BASE_CONFIG0); -+ -+ pinctrl_pm_select_default_state(dev); -+ -+ hdmi->cec_adap->ops->adap_enable(hdmi->cec_adap, true); -+ -+ mutex_lock(&hdmi->mutex); -+ if (hdmi->i2c) -+ dw_hdmi_i2c_init(hdmi); -+ if (hdmi->avp_irq) -+ enable_irq(hdmi->avp_irq); -+ -+ if (hdmi->main_irq) -+ enable_irq(hdmi->main_irq); -+ -+ if (hdmi->earc_irq) -+ enable_irq(hdmi->earc_irq); -+ -+ mutex_unlock(&hdmi->mutex); -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_qp_resume); -+ -+MODULE_AUTHOR("Algea Cao "); -+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 000000000..4cac70f2d ---- /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/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 52d91a0df..0d6fd9578 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -162,6 +162,8 @@ struct dw_hdmi { - void __iomem *regs; - bool sink_is_hdmi; - bool sink_has_audio; -+ bool support_hdmi; -+ int force_output; - - struct pinctrl *pinctrl; - struct pinctrl_state *default_state; -@@ -254,6 +256,25 @@ static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg, - hdmi_modb(hdmi, data << shift, mask, reg); - } - -+static bool dw_hdmi_check_output_type_changed(struct dw_hdmi *hdmi) -+{ -+ bool sink_hdmi; -+ -+ sink_hdmi = hdmi->sink_is_hdmi; -+ -+ if (hdmi->force_output == 1) -+ hdmi->sink_is_hdmi = true; -+ else if (hdmi->force_output == 2) -+ hdmi->sink_is_hdmi = false; -+ else -+ hdmi->sink_is_hdmi = hdmi->support_hdmi; -+ -+ if (sink_hdmi != hdmi->sink_is_hdmi) -+ return true; -+ -+ return false; -+} -+ - static void dw_hdmi_i2c_init(struct dw_hdmi *hdmi) - { - hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL, -@@ -2532,6 +2553,45 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, - return 0; - } - -+void dw_hdmi_set_quant_range(struct dw_hdmi *hdmi) -+{ -+ if (!hdmi->bridge_is_on) -+ return; -+ -+ hdmi_writeb(hdmi, HDMI_FC_GCP_SET_AVMUTE, HDMI_FC_GCP); -+ dw_hdmi_setup(hdmi, hdmi->curr_conn, &hdmi->previous_mode); -+ hdmi_writeb(hdmi, HDMI_FC_GCP_CLEAR_AVMUTE, HDMI_FC_GCP); -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_set_quant_range); -+ -+void dw_hdmi_set_output_type(struct dw_hdmi *hdmi, u64 val) -+{ -+ hdmi->force_output = val; -+ -+ if (!dw_hdmi_check_output_type_changed(hdmi)) -+ return; -+ -+ if (!hdmi->bridge_is_on) -+ return; -+ -+ hdmi_writeb(hdmi, HDMI_FC_GCP_SET_AVMUTE, HDMI_FC_GCP); -+ dw_hdmi_setup(hdmi, hdmi->curr_conn, &hdmi->previous_mode); -+ hdmi_writeb(hdmi, HDMI_FC_GCP_CLEAR_AVMUTE, HDMI_FC_GCP); -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_set_output_type); -+ -+bool dw_hdmi_get_output_whether_hdmi(struct dw_hdmi *hdmi) -+{ -+ return hdmi->sink_is_hdmi; -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_get_output_whether_hdmi); -+ -+int dw_hdmi_get_output_type_cap(struct dw_hdmi *hdmi) -+{ -+ return hdmi->support_hdmi; -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_get_output_type_cap); -+ - static void dw_hdmi_connector_force(struct drm_connector *connector) - { - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, -@@ -3683,6 +3743,35 @@ void dw_hdmi_unbind(struct dw_hdmi *hdmi) - } - EXPORT_SYMBOL_GPL(dw_hdmi_unbind); - -+void dw_hdmi_suspend(struct dw_hdmi *hdmi) -+{ -+ if (!hdmi) -+ return; -+ -+ mutex_lock(&hdmi->mutex); -+ -+ /* -+ * When system shutdown, hdmi should be disabled. -+ * When system suspend, dw_hdmi_bridge_disable will disable hdmi first. -+ * To prevent duplicate operation, we should determine whether hdmi -+ * has been disabled. -+ */ -+ if (!hdmi->disabled) { -+ hdmi->disabled = true; -+ dw_hdmi_update_power(hdmi); -+ dw_hdmi_update_phy_mask(hdmi); -+ } -+ mutex_unlock(&hdmi->mutex); -+ -+ //[CC: needed?] -+ // if (hdmi->irq) -+ // disable_irq(hdmi->irq); -+ // cancel_delayed_work(&hdmi->work); -+ // flush_workqueue(hdmi->workqueue); -+ pinctrl_pm_select_sleep_state(hdmi->dev); -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_suspend); -+ - void dw_hdmi_resume(struct dw_hdmi *hdmi) - { - dw_hdmi_init_hw(hdmi); -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -index af43a0414..8ebdec725 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -@@ -851,6 +851,10 @@ enum { - HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00, - HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04, - -+/* HDMI_FC_GCP */ -+ HDMI_FC_GCP_SET_AVMUTE = 0x2, -+ HDMI_FC_GCP_CLEAR_AVMUTE = 0x1, -+ - /* FC_DBGFORCE field values */ - HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10, - HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1, -diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c -index 9edc111be..a578f918f 100644 ---- a/drivers/gpu/drm/drm_displayid.c -+++ b/drivers/gpu/drm/drm_displayid.c -@@ -3,6 +3,7 @@ - * Copyright © 2021 Intel Corporation - */ - -+#include "linux/export.h" - #include - #include - #include -@@ -79,6 +80,7 @@ void displayid_iter_edid_begin(const struct drm_edid *drm_edid, - - iter->drm_edid = drm_edid; - } -+EXPORT_SYMBOL_GPL(displayid_iter_edid_begin); - - static const struct displayid_block * - displayid_iter_block(const struct displayid_iter *iter) -@@ -154,11 +156,13 @@ __displayid_iter_next(struct displayid_iter *iter) - return block; - } - } -+EXPORT_SYMBOL_GPL(__displayid_iter_next); - - void displayid_iter_end(struct displayid_iter *iter) - { - memset(iter, 0, sizeof(*iter)); - } -+EXPORT_SYMBOL_GPL(displayid_iter_end); - - /* DisplayID Structure Version/Revision from the Base Section. */ - u8 displayid_version(const struct displayid_iter *iter) -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index 341550199..52f457b16 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -4,22 +4,33 @@ - */ - - #include -+#include -+#include - #include - #include - #include - #include -+#include - #include - #include - -+#include -+#include -+#include -+#include - #include - #include - #include - #include - #include - -+#include -+ - #include "rockchip_drm_drv.h" - #include "rockchip_drm_vop.h" - -+#define HIWORD_UPDATE(val, mask) (val | (mask) << 16) -+ - #define RK3228_GRF_SOC_CON2 0x0408 - #define RK3228_HDMI_SDAIN_MSK BIT(14) - #define RK3228_HDMI_SCLIN_MSK BIT(13) -@@ -30,8 +41,11 @@ - - #define RK3288_GRF_SOC_CON6 0x025C - #define RK3288_HDMI_LCDC_SEL BIT(4) --#define RK3328_GRF_SOC_CON2 0x0408 -+#define RK3288_GRF_SOC_CON16 0x03a8 -+#define RK3288_HDMI_LCDC0_YUV420 BIT(2) -+#define RK3288_HDMI_LCDC1_YUV420 BIT(3) - -+#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) -@@ -55,32 +69,154 @@ - #define RK3568_HDMI_SDAIN_MSK BIT(15) - #define RK3568_HDMI_SCLIN_MSK BIT(14) - --#define HIWORD_UPDATE(val, mask) (val | (mask) << 16) -+#define RK3588_GRF_SOC_CON2 0x0308 -+#define RK3588_HDMI1_HPD_INT_MSK BIT(15) -+#define RK3588_HDMI1_HPD_INT_CLR BIT(14) -+#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_LOW_MORETHAN100MS BIT(20) -+#define RK3588_HDMI0_HPD_PORT_LEVEL BIT(19) -+#define RK3588_HDMI0_IHPD_PORT BIT(18) -+#define RK3588_HDMI0_OHPD_INT BIT(17) -+#define RK3588_HDMI0_LEVEL_INT BIT(16) -+#define RK3588_HDMI0_INTR_CHANGE_CNT (0x7 << 13) -+#define RK3588_HDMI1_LOW_MORETHAN100MS BIT(28) -+#define RK3588_HDMI1_HPD_PORT_LEVEL BIT(27) -+#define RK3588_HDMI1_IHPD_PORT BIT(26) -+#define RK3588_HDMI1_OHPD_INT BIT(25) -+#define RK3588_HDMI1_LEVEL_INT BIT(24) -+#define RK3588_HDMI1_INTR_CHANGE_CNT (0x7 << 21) -+ -+#define RK3588_GRF_VO1_CON3 0x000c -+#define RK3588_COLOR_FORMAT_MASK 0xf -+#define RK3588_YUV444 0x2 -+#define RK3588_YUV420 0x3 -+#define RK3588_COMPRESSED_DATA 0xb -+#define RK3588_COLOR_DEPTH_MASK (0xf << 4) -+#define RK3588_8BPC (0x5 << 4) -+#define RK3588_10BPC (0x6 << 4) -+#define RK3588_CECIN_MASK BIT(8) -+#define RK3588_SCLIN_MASK BIT(9) -+#define RK3588_SDAIN_MASK BIT(10) -+#define RK3588_MODE_MASK BIT(11) -+#define RK3588_COMPRESS_MODE_MASK BIT(12) -+#define RK3588_I2S_SEL_MASK BIT(13) -+#define RK3588_SPDIF_SEL_MASK BIT(14) -+#define RK3588_GRF_VO1_CON4 0x0010 -+#define RK3588_HDMI21_MASK BIT(0) -+#define RK3588_GRF_VO1_CON9 0x0024 -+#define RK3588_HDMI0_GRANT_SEL BIT(10) -+#define RK3588_HDMI0_GRANT_SW BIT(11) -+#define RK3588_HDMI1_GRANT_SEL BIT(12) -+#define RK3588_HDMI1_GRANT_SW BIT(13) -+#define RK3588_GRF_VO1_CON6 0x0018 -+#define RK3588_GRF_VO1_CON7 0x001c -+ -+#define COLOR_DEPTH_10BIT BIT(31) -+#define HDMI_FRL_MODE BIT(30) -+#define HDMI_EARC_MODE BIT(29) -+ -+#define HDMI20_MAX_RATE 600000 -+#define HDMI_8K60_RATE 2376000 - - /** - * struct rockchip_hdmi_chip_data - splite the grf setting of kind of chips - * @lcdsel_grf_reg: grf register offset of lcdc select -+ * @ddc_en_reg: grf register offset of hdmi ddc enable - * @lcdsel_big: reg value of selecting vop big for HDMI - * @lcdsel_lit: reg value of selecting vop little for HDMI - */ - struct rockchip_hdmi_chip_data { - int lcdsel_grf_reg; -+ int ddc_en_reg; - u32 lcdsel_big; - u32 lcdsel_lit; -+ bool split_mode; -+}; -+ -+enum hdmi_frl_rate_per_lane { -+ FRL_12G_PER_LANE = 12, -+ FRL_10G_PER_LANE = 10, -+ FRL_8G_PER_LANE = 8, -+ FRL_6G_PER_LANE = 6, -+ FRL_3G_PER_LANE = 3, - }; - - struct rockchip_hdmi { - struct device *dev; - struct regmap *regmap; -+ struct regmap *vo1_regmap; - struct rockchip_encoder encoder; -+ struct drm_device *drm_dev; - const struct rockchip_hdmi_chip_data *chip_data; -- const struct dw_hdmi_plat_data *plat_data; -+ struct dw_hdmi_plat_data *plat_data; -+ struct clk *aud_clk; - struct clk *ref_clk; - struct clk *grf_clk; -+ struct clk *hclk_vio; -+ struct clk *hclk_vo1; -+ struct clk *hclk_vop; -+ struct clk *hpd_clk; -+ struct clk *pclk; -+ struct clk *earc_clk; -+ struct clk *hdmitx_ref; - struct dw_hdmi *hdmi; -+ struct dw_hdmi_qp *hdmi_qp; -+ - struct regulator *avdd_0v9; - struct regulator *avdd_1v8; - struct phy *phy; -+ -+ u32 max_tmdsclk; -+ bool unsupported_yuv_input; -+ bool unsupported_deep_color; -+ bool skip_check_420_mode; -+ u8 force_output; -+ u8 id; -+ bool hpd_stat; -+ bool is_hdmi_qp; -+ bool user_split_mode; -+ -+ unsigned long bus_format; -+ unsigned long output_bus_format; -+ unsigned long enc_out_encoding; -+ int color_changed; -+ int hpd_irq; -+ int vp_id; -+ -+ struct drm_property *color_depth_property; -+ struct drm_property *hdmi_output_property; -+ struct drm_property *colordepth_capacity; -+ struct drm_property *outputmode_capacity; -+ struct drm_property *quant_range; -+ struct drm_property *hdr_panel_metadata_property; -+ struct drm_property *next_hdr_sink_data_property; -+ struct drm_property *output_hdmi_dvi; -+ struct drm_property *output_type_capacity; -+ struct drm_property *user_split_mode_prop; -+ -+ struct drm_property_blob *hdr_panel_blob_ptr; -+ struct drm_property_blob *next_hdr_data_ptr; -+ -+ unsigned int colordepth; -+ unsigned int colorimetry; -+ unsigned int hdmi_quant_range; -+ unsigned int phy_bus_width; -+ enum rk_if_color_format hdmi_output; -+ struct rockchip_drm_sub_dev sub_dev; -+ -+ u8 max_frl_rate_per_lane; -+ u8 max_lanes; -+ struct rockchip_drm_dsc_cap dsc_cap; -+ struct next_hdr_sink_data next_hdr_data; -+ struct dw_hdmi_link_config link_cfg; -+ struct gpio_desc *enable_gpio; -+ -+ struct delayed_work work; -+ struct workqueue_struct *workqueue; - }; - - static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder) -@@ -203,13 +339,834 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = { - /*pixelclk symbol term vlev*/ - { 74250000, 0x8009, 0x0004, 0x0272}, - { 148500000, 0x802b, 0x0004, 0x028d}, -+ { 165000000, 0x802b, 0x0004, 0x0209}, - { 297000000, 0x8039, 0x0005, 0x028d}, -+ { 594000000, 0x8039, 0x0000, 0x019d}, - { ~0UL, 0x0000, 0x0000, 0x0000} - }; - -+enum ROW_INDEX_BPP { -+ ROW_INDEX_6BPP = 0, -+ ROW_INDEX_8BPP, -+ ROW_INDEX_10BPP, -+ ROW_INDEX_12BPP, -+ ROW_INDEX_23BPP, -+ MAX_ROW_INDEX -+}; -+ -+enum COLUMN_INDEX_BPC { -+ COLUMN_INDEX_8BPC = 0, -+ COLUMN_INDEX_10BPC, -+ COLUMN_INDEX_12BPC, -+ COLUMN_INDEX_14BPC, -+ COLUMN_INDEX_16BPC, -+ MAX_COLUMN_INDEX -+}; -+ -+#define PPS_TABLE_LEN 8 -+#define PPS_BPP_LEN 4 -+#define PPS_BPC_LEN 2 -+ -+struct pps_data { -+ u32 pic_width; -+ u32 pic_height; -+ u32 slice_width; -+ u32 slice_height; -+ bool convert_rgb; -+ u8 bpc; -+ u8 bpp; -+ u8 raw_pps[128]; -+}; -+ -+/* -+ * Selected Rate Control Related Parameter Recommended Values -+ * from DSC_v1.11 spec & C Model release: DSC_model_20161212 -+ */ -+static struct pps_data pps_datas[PPS_TABLE_LEN] = { -+ { -+ /* 7680x4320/960X96 rgb 8bpc 12bpp */ -+ 7680, 4320, 960, 96, 1, 8, 192, -+ { -+ 0x12, 0x00, 0x00, 0x8d, 0x30, 0xc0, 0x10, 0xe0, -+ 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0xa0, -+ 0x01, 0x55, 0x03, 0x90, 0x00, 0x0a, 0x05, 0xc9, -+ 0x00, 0xa0, 0x00, 0x0f, 0x01, 0x44, 0x01, 0xaa, -+ 0x08, 0x00, 0x10, 0xf4, 0x03, 0x0c, 0x20, 0x00, -+ 0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38, -+ 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, -+ 0x7d, 0x7e, 0x00, 0x82, 0x00, 0xc0, 0x09, 0x00, -+ 0x09, 0x7e, 0x19, 0xbc, 0x19, 0xba, 0x19, 0xf8, -+ 0x1a, 0x38, 0x1a, 0x38, 0x1a, 0x76, 0x2a, 0x76, -+ 0x2a, 0x76, 0x2a, 0x74, 0x3a, 0xb4, 0x52, 0xf4, -+ 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 -+ }, -+ }, -+ { -+ /* 7680x4320/960X96 rgb 8bpc 11bpp */ -+ 7680, 4320, 960, 96, 1, 8, 176, -+ { -+ 0x12, 0x00, 0x00, 0x8d, 0x30, 0xb0, 0x10, 0xe0, -+ 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0x28, -+ 0x01, 0x74, 0x03, 0x40, 0x00, 0x0f, 0x06, 0xe0, -+ 0x00, 0x2d, 0x00, 0x0f, 0x01, 0x44, 0x01, 0x33, -+ 0x0f, 0x00, 0x10, 0xf4, 0x03, 0x0c, 0x20, 0x00, -+ 0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38, -+ 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, -+ 0x7d, 0x7e, 0x00, 0x82, 0x01, 0x00, 0x09, 0x40, -+ 0x09, 0xbe, 0x19, 0xfc, 0x19, 0xfa, 0x19, 0xf8, -+ 0x1a, 0x38, 0x1a, 0x38, 0x1a, 0x76, 0x2a, 0x76, -+ 0x2a, 0x76, 0x2a, 0xb4, 0x3a, 0xb4, 0x52, 0xf4, -+ 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 -+ }, -+ }, -+ { -+ /* 7680x4320/960X96 rgb 8bpc 10bpp */ -+ 7680, 4320, 960, 96, 1, 8, 160, -+ { -+ 0x12, 0x00, 0x00, 0x8d, 0x30, 0xa0, 0x10, 0xe0, -+ 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0xb0, -+ 0x01, 0x9a, 0x02, 0xe0, 0x00, 0x19, 0x09, 0xb0, -+ 0x00, 0x12, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xbb, -+ 0x16, 0x00, 0x10, 0xec, 0x03, 0x0c, 0x20, 0x00, -+ 0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38, -+ 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, -+ 0x7d, 0x7e, 0x00, 0xc2, 0x01, 0x00, 0x09, 0x40, -+ 0x09, 0xbe, 0x19, 0xfc, 0x19, 0xfa, 0x19, 0xf8, -+ 0x1a, 0x38, 0x1a, 0x78, 0x1a, 0x76, 0x2a, 0xb6, -+ 0x2a, 0xb6, 0x2a, 0xf4, 0x3a, 0xf4, 0x5b, 0x34, -+ 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 -+ }, -+ }, -+ { -+ /* 7680x4320/960X96 rgb 8bpc 9bpp */ -+ 7680, 4320, 960, 96, 1, 8, 144, -+ { -+ 0x12, 0x00, 0x00, 0x8d, 0x30, 0x90, 0x10, 0xe0, -+ 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0x38, -+ 0x01, 0xc7, 0x03, 0x16, 0x00, 0x1c, 0x08, 0xc7, -+ 0x00, 0x10, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xaa, -+ 0x17, 0x00, 0x10, 0xf1, 0x03, 0x0c, 0x20, 0x00, -+ 0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38, -+ 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, -+ 0x7d, 0x7e, 0x00, 0xc2, 0x01, 0x00, 0x09, 0x40, -+ 0x09, 0xbe, 0x19, 0xfc, 0x19, 0xfa, 0x19, 0xf8, -+ 0x1a, 0x38, 0x1a, 0x78, 0x1a, 0x76, 0x2a, 0xb6, -+ 0x2a, 0xb6, 0x2a, 0xf4, 0x3a, 0xf4, 0x63, 0x74, -+ 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 -+ }, -+ }, -+ { -+ /* 7680x4320/960X96 rgb 10bpc 12bpp */ -+ 7680, 4320, 960, 96, 1, 10, 192, -+ { -+ 0x12, 0x00, 0x00, 0xad, 0x30, 0xc0, 0x10, 0xe0, -+ 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0xa0, -+ 0x01, 0x55, 0x03, 0x90, 0x00, 0x0a, 0x05, 0xc9, -+ 0x00, 0xa0, 0x00, 0x0f, 0x01, 0x44, 0x01, 0xaa, -+ 0x08, 0x00, 0x10, 0xf4, 0x07, 0x10, 0x20, 0x00, -+ 0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38, -+ 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, -+ 0x7d, 0x7e, 0x01, 0x02, 0x11, 0x80, 0x22, 0x00, -+ 0x22, 0x7e, 0x32, 0xbc, 0x32, 0xba, 0x3a, 0xf8, -+ 0x3b, 0x38, 0x3b, 0x38, 0x3b, 0x76, 0x4b, 0x76, -+ 0x4b, 0x76, 0x4b, 0x74, 0x5b, 0xb4, 0x73, 0xf4, -+ 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 -+ }, -+ }, -+ { -+ /* 7680x4320/960X96 rgb 10bpc 11bpp */ -+ 7680, 4320, 960, 96, 1, 10, 176, -+ { -+ 0x12, 0x00, 0x00, 0xad, 0x30, 0xb0, 0x10, 0xe0, -+ 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0x28, -+ 0x01, 0x74, 0x03, 0x40, 0x00, 0x0f, 0x06, 0xe0, -+ 0x00, 0x2d, 0x00, 0x0f, 0x01, 0x44, 0x01, 0x33, -+ 0x0f, 0x00, 0x10, 0xf4, 0x07, 0x10, 0x20, 0x00, -+ 0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38, -+ 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, -+ 0x7d, 0x7e, 0x01, 0x42, 0x19, 0xc0, 0x2a, 0x40, -+ 0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8, -+ 0x3b, 0x38, 0x3b, 0x38, 0x3b, 0x76, 0x4b, 0x76, -+ 0x4b, 0x76, 0x4b, 0xb4, 0x5b, 0xb4, 0x73, 0xf4, -+ 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 -+ }, -+ }, -+ { -+ /* 7680x4320/960X96 rgb 10bpc 10bpp */ -+ 7680, 4320, 960, 96, 1, 10, 160, -+ { -+ 0x12, 0x00, 0x00, 0xad, 0x30, 0xa0, 0x10, 0xe0, -+ 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0xb0, -+ 0x01, 0x9a, 0x02, 0xe0, 0x00, 0x19, 0x09, 0xb0, -+ 0x00, 0x12, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xbb, -+ 0x16, 0x00, 0x10, 0xec, 0x07, 0x10, 0x20, 0x00, -+ 0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38, -+ 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, -+ 0x7d, 0x7e, 0x01, 0xc2, 0x22, 0x00, 0x2a, 0x40, -+ 0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8, -+ 0x3b, 0x38, 0x3b, 0x78, 0x3b, 0x76, 0x4b, 0xb6, -+ 0x4b, 0xb6, 0x4b, 0xf4, 0x63, 0xf4, 0x7c, 0x34, -+ 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 -+ }, -+ }, -+ { -+ /* 7680x4320/960X96 rgb 10bpc 9bpp */ -+ 7680, 4320, 960, 96, 1, 10, 144, -+ { -+ 0x12, 0x00, 0x00, 0xad, 0x30, 0x90, 0x10, 0xe0, -+ 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0x38, -+ 0x01, 0xc7, 0x03, 0x16, 0x00, 0x1c, 0x08, 0xc7, -+ 0x00, 0x10, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xaa, -+ 0x17, 0x00, 0x10, 0xf1, 0x07, 0x10, 0x20, 0x00, -+ 0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38, -+ 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, -+ 0x7d, 0x7e, 0x01, 0xc2, 0x22, 0x00, 0x2a, 0x40, -+ 0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8, -+ 0x3b, 0x38, 0x3b, 0x78, 0x3b, 0x76, 0x4b, 0xb6, -+ 0x4b, 0xb6, 0x4b, 0xf4, 0x63, 0xf4, 0x84, 0x74, -+ 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 -+ }, -+ }, -+}; -+ -+static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format) -+{ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_RGB888_1X24: -+ case MEDIA_BUS_FMT_RGB101010_1X30: -+ case MEDIA_BUS_FMT_RGB121212_1X36: -+ case MEDIA_BUS_FMT_RGB161616_1X48: -+ return true; -+ -+ default: -+ return false; -+ } -+} -+ -+static bool hdmi_bus_fmt_is_yuv444(unsigned int bus_format) -+{ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_YUV8_1X24: -+ case MEDIA_BUS_FMT_YUV10_1X30: -+ case MEDIA_BUS_FMT_YUV12_1X36: -+ case MEDIA_BUS_FMT_YUV16_1X48: -+ return true; -+ -+ default: -+ return false; -+ } -+} -+ -+static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format) -+{ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_UYVY8_1X16: -+ case MEDIA_BUS_FMT_UYVY10_1X20: -+ case MEDIA_BUS_FMT_UYVY12_1X24: -+ return true; -+ -+ default: -+ return false; -+ } -+} -+ -+static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format) -+{ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: -+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: -+ case MEDIA_BUS_FMT_UYYVYY12_0_5X36: -+ case MEDIA_BUS_FMT_UYYVYY16_0_5X48: -+ return true; -+ -+ default: -+ return false; -+ } -+} -+ -+static int hdmi_bus_fmt_color_depth(unsigned int bus_format) -+{ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_RGB888_1X24: -+ case MEDIA_BUS_FMT_YUV8_1X24: -+ case MEDIA_BUS_FMT_UYVY8_1X16: -+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: -+ return 8; -+ -+ case MEDIA_BUS_FMT_RGB101010_1X30: -+ case MEDIA_BUS_FMT_YUV10_1X30: -+ case MEDIA_BUS_FMT_UYVY10_1X20: -+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: -+ return 10; -+ -+ case MEDIA_BUS_FMT_RGB121212_1X36: -+ case MEDIA_BUS_FMT_YUV12_1X36: -+ case MEDIA_BUS_FMT_UYVY12_1X24: -+ case MEDIA_BUS_FMT_UYYVYY12_0_5X36: -+ return 12; -+ -+ case MEDIA_BUS_FMT_RGB161616_1X48: -+ case MEDIA_BUS_FMT_YUV16_1X48: -+ case MEDIA_BUS_FMT_UYYVYY16_0_5X48: -+ return 16; -+ -+ default: -+ return 0; -+ } -+} -+ -+static unsigned int -+hdmi_get_tmdsclock(struct rockchip_hdmi *hdmi, unsigned long pixelclock) -+{ -+ unsigned int tmdsclock = pixelclock; -+ unsigned int depth = -+ hdmi_bus_fmt_color_depth(hdmi->output_bus_format); -+ -+ if (!hdmi_bus_fmt_is_yuv422(hdmi->output_bus_format)) { -+ switch (depth) { -+ case 16: -+ tmdsclock = pixelclock * 2; -+ break; -+ case 12: -+ tmdsclock = pixelclock * 3 / 2; -+ break; -+ case 10: -+ tmdsclock = pixelclock * 5 / 4; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ return tmdsclock; -+} -+ -+static int rockchip_hdmi_match_by_id(struct device *dev, const void *data) -+{ -+ struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); -+ const unsigned int *id = data; -+ -+ return hdmi->id == *id; -+} -+ -+static struct rockchip_hdmi * -+rockchip_hdmi_find_by_id(struct device_driver *drv, unsigned int id) -+{ -+ struct device *dev; -+ -+ dev = driver_find_device(drv, NULL, &id, rockchip_hdmi_match_by_id); -+ if (!dev) -+ return NULL; -+ -+ return dev_get_drvdata(dev); -+} -+ -+static void hdmi_select_link_config(struct rockchip_hdmi *hdmi, -+ struct drm_crtc_state *crtc_state, -+ unsigned int tmdsclk) -+{ -+ struct drm_display_mode mode; -+ int max_lanes, max_rate_per_lane; -+ int max_dsc_lanes, max_dsc_rate_per_lane; -+ unsigned long max_frl_rate; -+ -+ drm_mode_copy(&mode, &crtc_state->mode); -+ if (hdmi->plat_data->split_mode) -+ drm_mode_convert_to_origin_mode(&mode); -+ -+ max_lanes = hdmi->max_lanes; -+ max_rate_per_lane = hdmi->max_frl_rate_per_lane; -+ max_frl_rate = max_lanes * max_rate_per_lane * 1000000; -+ -+ hdmi->link_cfg.dsc_mode = false; -+ hdmi->link_cfg.frl_lanes = max_lanes; -+ hdmi->link_cfg.rate_per_lane = max_rate_per_lane; -+ -+ if (!max_frl_rate || (tmdsclk < HDMI20_MAX_RATE && mode.clock < HDMI20_MAX_RATE)) { -+ dev_info(hdmi->dev, "use tmds mode\n"); -+ hdmi->link_cfg.frl_mode = false; -+ return; -+ } -+ -+ hdmi->link_cfg.frl_mode = true; -+ -+ if (!hdmi->dsc_cap.v_1p2) -+ return; -+ -+ max_dsc_lanes = hdmi->dsc_cap.max_lanes; -+ max_dsc_rate_per_lane = -+ hdmi->dsc_cap.max_frl_rate_per_lane; -+ -+ if (mode.clock >= HDMI_8K60_RATE && -+ !hdmi_bus_fmt_is_yuv420(hdmi->bus_format) && -+ !hdmi_bus_fmt_is_yuv422(hdmi->bus_format)) { -+ hdmi->link_cfg.dsc_mode = true; -+ hdmi->link_cfg.frl_lanes = max_dsc_lanes; -+ hdmi->link_cfg.rate_per_lane = max_dsc_rate_per_lane; -+ } else { -+ hdmi->link_cfg.dsc_mode = false; -+ hdmi->link_cfg.frl_lanes = max_lanes; -+ hdmi->link_cfg.rate_per_lane = max_rate_per_lane; -+ } -+} -+ -+///////////////////////////////////////////////////////////////////////////////////// -+ -+static int hdmi_dsc_get_slice_height(int vactive) -+{ -+ int slice_height; -+ -+ /* -+ * Slice Height determination : HDMI2.1 Section 7.7.5.2 -+ * Select smallest slice height >=96, that results in a valid PPS and -+ * requires minimum padding lines required for final slice. -+ * -+ * Assumption : Vactive is even. -+ */ -+ for (slice_height = 96; slice_height <= vactive; slice_height += 2) -+ if (vactive % slice_height == 0) -+ return slice_height; -+ -+ return 0; -+} -+ -+static int hdmi_dsc_get_num_slices(struct rockchip_hdmi *hdmi, -+ struct drm_crtc_state *crtc_state, -+ int src_max_slices, int src_max_slice_width, -+ int hdmi_max_slices, int hdmi_throughput) -+{ -+/* Pixel rates in KPixels/sec */ -+#define HDMI_DSC_PEAK_PIXEL_RATE 2720000 -+/* -+ * Rates at which the source and sink are required to process pixels in each -+ * slice, can be two levels: either at least 340000KHz or at least 40000KHz. -+ */ -+#define HDMI_DSC_MAX_ENC_THROUGHPUT_0 340000 -+#define HDMI_DSC_MAX_ENC_THROUGHPUT_1 400000 -+ -+/* Spec limits the slice width to 2720 pixels */ -+#define MAX_HDMI_SLICE_WIDTH 2720 -+ int kslice_adjust; -+ int adjusted_clk_khz; -+ int min_slices; -+ int target_slices; -+ int max_throughput; /* max clock freq. in khz per slice */ -+ int max_slice_width; -+ int slice_width; -+ int pixel_clock = crtc_state->mode.clock; -+ -+ if (!hdmi_throughput) -+ return 0; -+ -+ /* -+ * Slice Width determination : HDMI2.1 Section 7.7.5.1 -+ * kslice_adjust factor for 4:2:0, and 4:2:2 formats is 0.5, where as -+ * for 4:4:4 is 1.0. Multiplying these factors by 10 and later -+ * dividing adjusted clock value by 10. -+ */ -+ if (hdmi_bus_fmt_is_yuv444(hdmi->output_bus_format) || -+ hdmi_bus_fmt_is_rgb(hdmi->output_bus_format)) -+ kslice_adjust = 10; -+ else -+ kslice_adjust = 5; -+ -+ /* -+ * As per spec, the rate at which the source and the sink process -+ * the pixels per slice are at two levels: at least 340Mhz or 400Mhz. -+ * This depends upon the pixel clock rate and output formats -+ * (kslice adjust). -+ * If pixel clock * kslice adjust >= 2720MHz slices can be processed -+ * at max 340MHz, otherwise they can be processed at max 400MHz. -+ */ -+ -+ adjusted_clk_khz = DIV_ROUND_UP(kslice_adjust * pixel_clock, 10); -+ -+ if (adjusted_clk_khz <= HDMI_DSC_PEAK_PIXEL_RATE) -+ max_throughput = HDMI_DSC_MAX_ENC_THROUGHPUT_0; -+ else -+ max_throughput = HDMI_DSC_MAX_ENC_THROUGHPUT_1; -+ -+ /* -+ * Taking into account the sink's capability for maximum -+ * clock per slice (in MHz) as read from HF-VSDB. -+ */ -+ max_throughput = min(max_throughput, hdmi_throughput * 1000); -+ -+ min_slices = DIV_ROUND_UP(adjusted_clk_khz, max_throughput); -+ max_slice_width = min(MAX_HDMI_SLICE_WIDTH, src_max_slice_width); -+ -+ /* -+ * Keep on increasing the num of slices/line, starting from min_slices -+ * per line till we get such a number, for which the slice_width is -+ * just less than max_slice_width. The slices/line selected should be -+ * less than or equal to the max horizontal slices that the combination -+ * of PCON encoder and HDMI decoder can support. -+ */ -+ do { -+ if (min_slices <= 1 && src_max_slices >= 1 && hdmi_max_slices >= 1) -+ target_slices = 1; -+ else if (min_slices <= 2 && src_max_slices >= 2 && hdmi_max_slices >= 2) -+ target_slices = 2; -+ else if (min_slices <= 4 && src_max_slices >= 4 && hdmi_max_slices >= 4) -+ target_slices = 4; -+ else if (min_slices <= 8 && src_max_slices >= 8 && hdmi_max_slices >= 8) -+ target_slices = 8; -+ else if (min_slices <= 12 && src_max_slices >= 12 && hdmi_max_slices >= 12) -+ target_slices = 12; -+ else if (min_slices <= 16 && src_max_slices >= 16 && hdmi_max_slices >= 16) -+ target_slices = 16; -+ else -+ return 0; -+ -+ slice_width = DIV_ROUND_UP(crtc_state->mode.hdisplay, target_slices); -+ if (slice_width > max_slice_width) -+ min_slices = target_slices + 1; -+ } while (slice_width > max_slice_width); -+ -+ return target_slices; -+} -+ -+static int hdmi_dsc_slices(struct rockchip_hdmi *hdmi, -+ struct drm_crtc_state *crtc_state) -+{ -+ int hdmi_throughput = hdmi->dsc_cap.clk_per_slice; -+ int hdmi_max_slices = hdmi->dsc_cap.max_slices; -+ int rk_max_slices = 8; -+ int rk_max_slice_width = 2048; -+ -+ return hdmi_dsc_get_num_slices(hdmi, crtc_state, rk_max_slices, -+ rk_max_slice_width, -+ hdmi_max_slices, hdmi_throughput); -+} -+ -+static int -+hdmi_dsc_get_bpp(struct rockchip_hdmi *hdmi, int src_fractional_bpp, -+ int slice_width, int num_slices, bool hdmi_all_bpp, -+ int hdmi_max_chunk_bytes) -+{ -+ int max_dsc_bpp, min_dsc_bpp; -+ int target_bytes; -+ bool bpp_found = false; -+ int bpp_decrement_x16; -+ int bpp_target; -+ int bpp_target_x16; -+ -+ /* -+ * Get min bpp and max bpp as per Table 7.23, in HDMI2.1 spec -+ * Start with the max bpp and keep on decrementing with -+ * fractional bpp, if supported by PCON DSC encoder -+ * -+ * for each bpp we check if no of bytes can be supported by HDMI sink -+ */ -+ -+ /* only 9\10\12 bpp was tested */ -+ min_dsc_bpp = 9; -+ max_dsc_bpp = 12; -+ -+ /* -+ * Taking into account if all dsc_all_bpp supported by HDMI2.1 sink -+ * Section 7.7.34 : Source shall not enable compressed Video -+ * Transport with bpp_target settings above 12 bpp unless -+ * DSC_all_bpp is set to 1. -+ */ -+ if (!hdmi_all_bpp) -+ max_dsc_bpp = min(max_dsc_bpp, 12); -+ -+ /* -+ * The Sink has a limit of compressed data in bytes for a scanline, -+ * as described in max_chunk_bytes field in HFVSDB block of edid. -+ * The no. of bytes depend on the target bits per pixel that the -+ * source configures. So we start with the max_bpp and calculate -+ * the target_chunk_bytes. We keep on decrementing the target_bpp, -+ * till we get the target_chunk_bytes just less than what the sink's -+ * max_chunk_bytes, or else till we reach the min_dsc_bpp. -+ * -+ * The decrement is according to the fractional support from PCON DSC -+ * encoder. For fractional BPP we use bpp_target as a multiple of 16. -+ * -+ * bpp_target_x16 = bpp_target * 16 -+ * So we need to decrement by {1, 2, 4, 8, 16} for fractional bpps -+ * {1/16, 1/8, 1/4, 1/2, 1} respectively. -+ */ -+ -+ bpp_target = max_dsc_bpp; -+ -+ /* src does not support fractional bpp implies decrement by 16 for bppx16 */ -+ if (!src_fractional_bpp) -+ src_fractional_bpp = 1; -+ bpp_decrement_x16 = DIV_ROUND_UP(16, src_fractional_bpp); -+ bpp_target_x16 = bpp_target * 16; -+ -+ while (bpp_target_x16 > (min_dsc_bpp * 16)) { -+ int bpp; -+ -+ bpp = DIV_ROUND_UP(bpp_target_x16, 16); -+ target_bytes = DIV_ROUND_UP((num_slices * slice_width * bpp), 8); -+ if (target_bytes <= hdmi_max_chunk_bytes) { -+ bpp_found = true; -+ break; -+ } -+ bpp_target_x16 -= bpp_decrement_x16; -+ } -+ if (bpp_found) -+ return bpp_target_x16; -+ -+ return 0; -+} -+ -+static int -+dw_hdmi_dsc_bpp(struct rockchip_hdmi *hdmi, -+ int num_slices, int slice_width) -+{ -+ bool hdmi_all_bpp = hdmi->dsc_cap.all_bpp; -+ int fractional_bpp = 0; -+ int hdmi_max_chunk_bytes = hdmi->dsc_cap.total_chunk_kbytes * 1024; -+ -+ return hdmi_dsc_get_bpp(hdmi, fractional_bpp, slice_width, -+ num_slices, hdmi_all_bpp, -+ hdmi_max_chunk_bytes); -+} -+ -+static int dw_hdmi_qp_set_link_cfg(struct rockchip_hdmi *hdmi, -+ u16 pic_width, u16 pic_height, -+ u16 slice_width, u16 slice_height, -+ u16 bits_per_pixel, u8 bits_per_component) -+{ -+ int i; -+ -+ for (i = 0; i < PPS_TABLE_LEN; i++) -+ if (pic_width == pps_datas[i].pic_width && -+ pic_height == pps_datas[i].pic_height && -+ slice_width == pps_datas[i].slice_width && -+ slice_height == pps_datas[i].slice_height && -+ bits_per_component == pps_datas[i].bpc && -+ bits_per_pixel == pps_datas[i].bpp && -+ hdmi_bus_fmt_is_rgb(hdmi->output_bus_format) == pps_datas[i].convert_rgb) -+ break; -+ -+ if (i == PPS_TABLE_LEN) { -+ dev_err(hdmi->dev, "can't find pps cfg!\n"); -+ return -EINVAL; -+ } -+ -+ memcpy(hdmi->link_cfg.pps_payload, pps_datas[i].raw_pps, 128); -+ hdmi->link_cfg.hcactive = DIV_ROUND_UP(slice_width * (bits_per_pixel / 16), 8) * -+ (pic_width / slice_width); -+ -+ return 0; -+} -+ -+static void dw_hdmi_qp_dsc_configure(struct rockchip_hdmi *hdmi, -+ struct rockchip_crtc_state *s, -+ struct drm_crtc_state *crtc_state) -+{ -+ int ret; -+ int slice_height; -+ int slice_width; -+ int bits_per_pixel; -+ int slice_count; -+ bool hdmi_is_dsc_1_2; -+ unsigned int depth = hdmi_bus_fmt_color_depth(hdmi->output_bus_format); -+ -+ if (!crtc_state) -+ return; -+ -+ hdmi_is_dsc_1_2 = hdmi->dsc_cap.v_1p2; -+ -+ if (!hdmi_is_dsc_1_2) -+ return; -+ -+ slice_height = hdmi_dsc_get_slice_height(crtc_state->mode.vdisplay); -+ if (!slice_height) -+ return; -+ -+ slice_count = hdmi_dsc_slices(hdmi, crtc_state); -+ if (!slice_count) -+ return; -+ -+ slice_width = DIV_ROUND_UP(crtc_state->mode.hdisplay, slice_count); -+ -+ bits_per_pixel = dw_hdmi_dsc_bpp(hdmi, slice_count, slice_width); -+ if (!bits_per_pixel) -+ return; -+ -+ ret = dw_hdmi_qp_set_link_cfg(hdmi, crtc_state->mode.hdisplay, -+ crtc_state->mode.vdisplay, slice_width, -+ slice_height, bits_per_pixel, depth); -+ -+ if (ret) { -+ dev_err(hdmi->dev, "set vdsc cfg failed\n"); -+ return; -+ } -+ dev_info(hdmi->dev, "dsc_enable\n"); -+ s->dsc_enable = 1; -+ s->dsc_sink_cap.version_major = 1; -+ s->dsc_sink_cap.version_minor = 2; -+ s->dsc_sink_cap.slice_width = slice_width; -+ s->dsc_sink_cap.slice_height = slice_height; -+ s->dsc_sink_cap.target_bits_per_pixel_x16 = bits_per_pixel; -+ s->dsc_sink_cap.block_pred = 1; -+ s->dsc_sink_cap.native_420 = 0; -+ -+ memcpy(&s->pps, hdmi->link_cfg.pps_payload, 128); -+} -+///////////////////////////////////////////////////////////////////////////////////////// -+ -+// static int rockchip_hdmi_update_phy_table(struct rockchip_hdmi *hdmi, -+// u32 *config, -+// int phy_table_size) -+// { -+// int i; -+// -+// if (phy_table_size > ARRAY_SIZE(rockchip_phy_config)) { -+// dev_err(hdmi->dev, "phy table array number is out of range\n"); -+// return -E2BIG; -+// } -+// -+// for (i = 0; i < phy_table_size; i++) { -+// if (config[i * 4] != 0) -+// rockchip_phy_config[i].mpixelclock = (u64)config[i * 4]; -+// else -+// rockchip_phy_config[i].mpixelclock = ~0UL; -+// rockchip_phy_config[i].sym_ctr = (u16)config[i * 4 + 1]; -+// rockchip_phy_config[i].term = (u16)config[i * 4 + 2]; -+// rockchip_phy_config[i].vlev_ctr = (u16)config[i * 4 + 3]; -+// } -+// -+// return 0; -+// } -+ -+static void repo_hpd_event(struct work_struct *p_work) -+{ -+ struct rockchip_hdmi *hdmi = container_of(p_work, struct rockchip_hdmi, work.work); -+ bool change; -+ -+ change = drm_helper_hpd_irq_event(hdmi->drm_dev); -+ if (change) { -+ dev_dbg(hdmi->dev, "hpd stat changed:%d\n", hdmi->hpd_stat); -+ // dw_hdmi_qp_cec_set_hpd(hdmi->hdmi_qp, hdmi->hpd_stat, change); -+ } -+} -+ -+static irqreturn_t rockchip_hdmi_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) { -+ dev_dbg(hdmi->dev, "hpd irq %#x\n", intr_stat); -+ -+ if (!hdmi->id) -+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, -+ RK3588_HDMI0_HPD_INT_MSK); -+ else -+ val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_MSK, -+ RK3588_HDMI1_HPD_INT_MSK); -+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); -+ return IRQ_WAKE_THREAD; -+ } -+ -+ return IRQ_NONE; -+} -+ -+static irqreturn_t rockchip_hdmi_irq(int irq, void *dev_id) -+{ -+ struct rockchip_hdmi *hdmi = dev_id; -+ u32 intr_stat, val; -+ int msecs; -+ bool stat; -+ -+ regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat); -+ -+ if (!intr_stat) -+ return IRQ_NONE; -+ -+ if (!hdmi->id) { -+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, -+ RK3588_HDMI0_HPD_INT_CLR); -+ if (intr_stat & RK3588_HDMI0_LEVEL_INT) -+ stat = true; -+ else -+ stat = false; -+ } else { -+ val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_CLR, -+ RK3588_HDMI1_HPD_INT_CLR); -+ if (intr_stat & RK3588_HDMI1_LEVEL_INT) -+ stat = true; -+ else -+ stat = false; -+ } -+ -+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); -+ -+ if (stat) { -+ hdmi->hpd_stat = true; -+ msecs = 150; -+ } else { -+ hdmi->hpd_stat = false; -+ msecs = 20; -+ } -+ mod_delayed_work(hdmi->workqueue, &hdmi->work, msecs_to_jiffies(msecs)); -+ -+ if (!hdmi->id) { -+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, -+ RK3588_HDMI0_HPD_INT_CLR) | -+ HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK); -+ } else { -+ val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_CLR, -+ RK3588_HDMI1_HPD_INT_CLR) | -+ HIWORD_UPDATE(0, RK3588_HDMI1_HPD_INT_MSK); -+ } -+ -+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); -+ -+ return IRQ_HANDLED; -+} -+ -+static void init_hpd_work(struct rockchip_hdmi *hdmi) -+{ -+ hdmi->workqueue = create_workqueue("hpd_queue"); -+ INIT_DELAYED_WORK(&hdmi->work, repo_hpd_event); -+} -+ - 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)) { -@@ -217,6 +1174,14 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) - return PTR_ERR(hdmi->regmap); - } - -+ if (hdmi->is_hdmi_qp) { -+ hdmi->vo1_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,vo1_grf"); -+ if (IS_ERR(hdmi->vo1_regmap)) { -+ DRM_DEV_ERROR(hdmi->dev, "Unable to get rockchip,vo1_grf\n"); -+ return PTR_ERR(hdmi->vo1_regmap); -+ } -+ } -+ - hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "ref"); - if (!hdmi->ref_clk) - hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "vpll"); -@@ -246,6 +1211,79 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) - if (IS_ERR(hdmi->avdd_1v8)) - return PTR_ERR(hdmi->avdd_1v8); - -+ hdmi->hclk_vio = devm_clk_get(hdmi->dev, "hclk_vio"); -+ if (PTR_ERR(hdmi->hclk_vio) == -ENOENT) { -+ hdmi->hclk_vio = NULL; -+ } else if (PTR_ERR(hdmi->hclk_vio) == -EPROBE_DEFER) { -+ return -EPROBE_DEFER; -+ } else if (IS_ERR(hdmi->hclk_vio)) { -+ dev_err(hdmi->dev, "failed to get hclk_vio clock\n"); -+ return PTR_ERR(hdmi->hclk_vio); -+ } -+ -+ hdmi->hclk_vop = devm_clk_get(hdmi->dev, "hclk"); -+ if (PTR_ERR(hdmi->hclk_vop) == -ENOENT) { -+ hdmi->hclk_vop = NULL; -+ } else if (PTR_ERR(hdmi->hclk_vop) == -EPROBE_DEFER) { -+ return -EPROBE_DEFER; -+ } else if (IS_ERR(hdmi->hclk_vop)) { -+ dev_err(hdmi->dev, "failed to get hclk_vop clock\n"); -+ return PTR_ERR(hdmi->hclk_vop); -+ } -+ -+ hdmi->aud_clk = devm_clk_get_optional(hdmi->dev, "aud"); -+ if (IS_ERR(hdmi->aud_clk)) { -+ dev_err_probe(hdmi->dev, PTR_ERR(hdmi->aud_clk), -+ "failed to get aud_clk clock\n"); -+ return PTR_ERR(hdmi->aud_clk); -+ } -+ -+ hdmi->hpd_clk = devm_clk_get_optional(hdmi->dev, "hpd"); -+ if (IS_ERR(hdmi->hpd_clk)) { -+ dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hpd_clk), -+ "failed to get hpd_clk clock\n"); -+ return PTR_ERR(hdmi->hpd_clk); -+ } -+ -+ hdmi->hclk_vo1 = devm_clk_get_optional(hdmi->dev, "hclk_vo1"); -+ if (IS_ERR(hdmi->hclk_vo1)) { -+ dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hclk_vo1), -+ "failed to get hclk_vo1 clock\n"); -+ return PTR_ERR(hdmi->hclk_vo1); -+ } -+ -+ hdmi->earc_clk = devm_clk_get_optional(hdmi->dev, "earc"); -+ if (IS_ERR(hdmi->earc_clk)) { -+ dev_err_probe(hdmi->dev, PTR_ERR(hdmi->earc_clk), -+ "failed to get earc_clk clock\n"); -+ return PTR_ERR(hdmi->earc_clk); -+ } -+ -+ hdmi->hdmitx_ref = devm_clk_get_optional(hdmi->dev, "hdmitx_ref"); -+ if (IS_ERR(hdmi->hdmitx_ref)) { -+ dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmitx_ref), -+ "failed to get hdmitx_ref clock\n"); -+ return PTR_ERR(hdmi->hdmitx_ref); -+ } -+ -+ hdmi->pclk = devm_clk_get_optional(hdmi->dev, "pclk"); -+ if (IS_ERR(hdmi->pclk)) { -+ dev_err_probe(hdmi->dev, PTR_ERR(hdmi->pclk), -+ "failed to get pclk clock\n"); -+ return PTR_ERR(hdmi->pclk); -+ } -+ -+ hdmi->enable_gpio = devm_gpiod_get_optional(hdmi->dev, "enable", -+ GPIOD_OUT_HIGH); -+ if (IS_ERR(hdmi->enable_gpio)) { -+ ret = PTR_ERR(hdmi->enable_gpio); -+ dev_err(hdmi->dev, "failed to request enable GPIO: %d\n", ret); -+ return ret; -+ } -+ -+ hdmi->skip_check_420_mode = -+ of_property_read_bool(np, "skip-check-420-mode"); -+ - return 0; - } - -@@ -284,9 +1322,114 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *dw_hdmi, void *data, - - return MODE_BAD; - } -+/* [CC:] enable downstream mode_valid() */ -+// static enum drm_mode_status -+// dw_hdmi_rockchip_mode_valid(struct drm_connector *connector, void *data, -+// const struct drm_display_info *info, -+// const struct drm_display_mode *mode) -+// { -+// struct drm_encoder *encoder = connector->encoder; -+// enum drm_mode_status status = MODE_OK; -+// struct drm_device *dev = connector->dev; -+// struct rockchip_drm_private *priv = dev->dev_private; -+// struct drm_crtc *crtc; -+// struct rockchip_hdmi *hdmi; -+// -+// /* -+// * Pixel clocks we support are always < 2GHz and so fit in an -+// * int. We should make sure source rate does too so we don't get -+// * overflow when we multiply by 1000. -+// */ -+// if (mode->clock > INT_MAX / 1000) -+// return MODE_BAD; -+// -+// if (!encoder) { -+// const struct drm_connector_helper_funcs *funcs; -+// -+// funcs = connector->helper_private; -+// if (funcs->atomic_best_encoder) -+// encoder = funcs->atomic_best_encoder(connector, -+// connector->state); -+// else -+// encoder = funcs->best_encoder(connector); -+// } -+// -+// if (!encoder || !encoder->possible_crtcs) -+// return MODE_BAD; -+// -+// hdmi = to_rockchip_hdmi(encoder); -+// -+// /* -+// * If sink max TMDS clock < 340MHz, we should check the mode pixel -+// * clock > 340MHz is YCbCr420 or not and whether the platform supports -+// * YCbCr420. -+// */ -+// if (!hdmi->skip_check_420_mode) { -+// if (mode->clock > 340000 && -+// connector->display_info.max_tmds_clock < 340000 && -+// (!drm_mode_is_420(&connector->display_info, mode) || -+// !connector->ycbcr_420_allowed)) -+// return MODE_BAD; -+// -+// if (hdmi->max_tmdsclk <= 340000 && mode->clock > 340000 && -+// !drm_mode_is_420(&connector->display_info, mode)) -+// return MODE_BAD; -+// }; -+// -+// if (hdmi->phy) { -+// if (hdmi->is_hdmi_qp) -+// phy_set_bus_width(hdmi->phy, mode->clock * 10); -+// else -+// phy_set_bus_width(hdmi->phy, 8); -+// } -+// -+// /* -+// * ensure all drm display mode can work, if someone want support more -+// * resolutions, please limit the possible_crtc, only connect to -+// * needed crtc. -+// */ -+// drm_for_each_crtc(crtc, connector->dev) { -+// int pipe = drm_crtc_index(crtc); -+// const struct rockchip_crtc_funcs *funcs = -+// priv->crtc_funcs[pipe]; -+// -+// if (!(encoder->possible_crtcs & drm_crtc_mask(crtc))) -+// continue; -+// if (!funcs || !funcs->mode_valid) -+// continue; -+// -+// status = funcs->mode_valid(crtc, mode, -+// DRM_MODE_CONNECTOR_HDMIA); -+// if (status != MODE_OK) -+// return status; -+// } -+// -+// return status; -+// } -+// - - static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) - { -+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); -+ struct drm_crtc *crtc = encoder->crtc; -+ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); -+ -+ if (crtc->state->active_changed) { -+ if (hdmi->plat_data->split_mode) { -+ s->output_if &= ~(VOP_OUTPUT_IF_HDMI0 | VOP_OUTPUT_IF_HDMI1); -+ } else { -+ if (!hdmi->id) -+ s->output_if &= ~VOP_OUTPUT_IF_HDMI1; -+ else -+ s->output_if &= ~VOP_OUTPUT_IF_HDMI0; -+ } -+ } -+ /* -+ * when plug out hdmi it will be switch cvbs and then phy bus width -+ * must be set as 8 -+ */ -+ if (hdmi->phy) -+ phy_set_bus_width(hdmi->phy, 8); - } - - static bool -@@ -302,6 +1445,27 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *adj_mode) - { - struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); -+ struct drm_crtc *crtc; -+ struct rockchip_crtc_state *s; -+ -+ if (!encoder->crtc) -+ return; -+ crtc = encoder->crtc; -+ -+ if (!crtc->state) -+ return; -+ s = to_rockchip_crtc_state(crtc->state); -+ -+ if (!s) -+ return; -+ -+ if (hdmi->is_hdmi_qp) { -+ s->dsc_enable = 0; -+ if (hdmi->link_cfg.dsc_mode) -+ dw_hdmi_qp_dsc_configure(hdmi, s, crtc->state); -+ -+ phy_set_bus_width(hdmi->phy, hdmi->phy_bus_width); -+ } - - clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000); - } -@@ -309,14 +1473,25 @@ 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 mux; - int ret; - -+ if (WARN_ON(!crtc || !crtc->state)) -+ return; -+ -+ if (hdmi->phy) -+ phy_set_bus_width(hdmi->phy, hdmi->phy_bus_width); -+ -+ clk_set_rate(hdmi->ref_clk, -+ crtc->state->adjusted_mode.crtc_clock * 1000); -+ - if (hdmi->chip_data->lcdsel_grf_reg < 0) - return; - -- ret = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder); -- if (ret) -+ mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder); -+ if (mux) - val = hdmi->chip_data->lcdsel_lit; - else - val = hdmi->chip_data->lcdsel_big; -@@ -331,24 +1506,1018 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) - if (ret != 0) - DRM_DEV_ERROR(hdmi->dev, "Could not write to GRF: %d\n", ret); - -+ if (hdmi->chip_data->lcdsel_grf_reg == RK3288_GRF_SOC_CON6) { -+ struct rockchip_crtc_state *s = -+ to_rockchip_crtc_state(crtc->state); -+ u32 mode_mask = mux ? RK3288_HDMI_LCDC1_YUV420 : -+ RK3288_HDMI_LCDC0_YUV420; -+ -+ if (s->output_mode == ROCKCHIP_OUT_MODE_YUV420) -+ val = HIWORD_UPDATE(mode_mask, mode_mask); -+ else -+ val = HIWORD_UPDATE(0, mode_mask); -+ -+ regmap_write(hdmi->regmap, RK3288_GRF_SOC_CON16, val); -+ } -+ - clk_disable_unprepare(hdmi->grf_clk); - DRM_DEV_DEBUG(hdmi->dev, "vop %s output to hdmi\n", - ret ? "LIT" : "BIG"); - } - --static int --dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, -- struct drm_crtc_state *crtc_state, -- struct drm_connector_state *conn_state) -+static void rk3588_set_link_mode(struct rockchip_hdmi *hdmi) - { -- struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); -+ int val; -+ bool is_hdmi0; - -- s->output_mode = ROCKCHIP_OUT_MODE_AAAA; -- s->output_type = DRM_MODE_CONNECTOR_HDMIA; -+ if (!hdmi->id) -+ is_hdmi0 = true; -+ else -+ is_hdmi0 = false; -+ -+ if (!hdmi->link_cfg.frl_mode) { -+ val = HIWORD_UPDATE(0, RK3588_HDMI21_MASK); -+ if (is_hdmi0) -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON4, val); -+ else -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON7, val); -+ -+ val = HIWORD_UPDATE(0, RK3588_COMPRESS_MODE_MASK | RK3588_COLOR_FORMAT_MASK); -+ if (is_hdmi0) -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val); -+ else -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, val); -+ -+ return; -+ } -+ -+ val = HIWORD_UPDATE(RK3588_HDMI21_MASK, RK3588_HDMI21_MASK); -+ if (is_hdmi0) -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON4, val); -+ else -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON7, val); -+ -+ if (hdmi->link_cfg.dsc_mode) { -+ val = HIWORD_UPDATE(RK3588_COMPRESS_MODE_MASK | RK3588_COMPRESSED_DATA, -+ RK3588_COMPRESS_MODE_MASK | RK3588_COLOR_FORMAT_MASK); -+ if (is_hdmi0) -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val); -+ else -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, val); -+ } else { -+ val = HIWORD_UPDATE(0, RK3588_COMPRESS_MODE_MASK | RK3588_COLOR_FORMAT_MASK); -+ if (is_hdmi0) -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val); -+ else -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, val); -+ } -+} -+ -+static void rk3588_set_color_format(struct rockchip_hdmi *hdmi, u64 bus_format, -+ u32 depth) -+{ -+ u32 val = 0; -+ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_RGB888_1X24: -+ case MEDIA_BUS_FMT_RGB101010_1X30: -+ val = HIWORD_UPDATE(0, RK3588_COLOR_FORMAT_MASK); -+ break; -+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: -+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: -+ val = HIWORD_UPDATE(RK3588_YUV420, RK3588_COLOR_FORMAT_MASK); -+ break; -+ case MEDIA_BUS_FMT_YUV8_1X24: -+ case MEDIA_BUS_FMT_YUV10_1X30: -+ val = HIWORD_UPDATE(RK3588_YUV444, RK3588_COLOR_FORMAT_MASK); -+ break; -+ default: -+ dev_err(hdmi->dev, "can't set correct color format\n"); -+ return; -+ } -+ -+ if (hdmi->link_cfg.dsc_mode) -+ val = HIWORD_UPDATE(RK3588_COMPRESSED_DATA, RK3588_COLOR_FORMAT_MASK); -+ -+ if (depth == 8) -+ val |= HIWORD_UPDATE(RK3588_8BPC, RK3588_COLOR_DEPTH_MASK); -+ else -+ val |= HIWORD_UPDATE(RK3588_10BPC, RK3588_COLOR_DEPTH_MASK); -+ -+ if (!hdmi->id) -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val); -+ else -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, val); -+} -+ -+static void rk3588_set_grf_cfg(void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ int color_depth; -+ -+ rk3588_set_link_mode(hdmi); -+ color_depth = hdmi_bus_fmt_color_depth(hdmi->bus_format); -+ rk3588_set_color_format(hdmi, hdmi->bus_format, color_depth); -+} -+ -+static void -+dw_hdmi_rockchip_select_output(struct drm_connector_state *conn_state, -+ struct drm_crtc_state *crtc_state, -+ struct rockchip_hdmi *hdmi, -+ unsigned int *color_format, -+ unsigned int *output_mode, -+ unsigned long *bus_format, -+ unsigned int *bus_width, -+ unsigned long *enc_out_encoding, -+ unsigned int *eotf) -+{ -+ struct drm_display_info *info = &conn_state->connector->display_info; -+ struct drm_display_mode mode; -+ struct hdr_output_metadata *hdr_metadata; -+ u32 vic; -+ unsigned long tmdsclock, pixclock; -+ unsigned int color_depth; -+ bool support_dc = false; -+ bool sink_is_hdmi = true; -+ u32 max_tmds_clock = info->max_tmds_clock; -+ int output_eotf; -+ -+ drm_mode_copy(&mode, &crtc_state->mode); -+ pixclock = mode.crtc_clock; -+ if (hdmi->plat_data->split_mode) { -+ drm_mode_convert_to_origin_mode(&mode); -+ pixclock /= 2; -+ } -+ -+ vic = drm_match_cea_mode(&mode); -+ -+ if (!hdmi->is_hdmi_qp) -+ sink_is_hdmi = dw_hdmi_get_output_whether_hdmi(hdmi->hdmi); -+ -+ *color_format = RK_IF_FORMAT_RGB; -+ -+ switch (hdmi->hdmi_output) { -+ case RK_IF_FORMAT_YCBCR_HQ: -+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) -+ *color_format = RK_IF_FORMAT_YCBCR444; -+ else if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) -+ *color_format = RK_IF_FORMAT_YCBCR422; -+ else if (conn_state->connector->ycbcr_420_allowed && -+ drm_mode_is_420(info, &mode) && -+ (pixclock >= 594000 && !hdmi->is_hdmi_qp)) -+ *color_format = RK_IF_FORMAT_YCBCR420; -+ break; -+ case RK_IF_FORMAT_YCBCR_LQ: -+ if (conn_state->connector->ycbcr_420_allowed && -+ drm_mode_is_420(info, &mode) && pixclock >= 594000) -+ *color_format = RK_IF_FORMAT_YCBCR420; -+ else if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) -+ *color_format = RK_IF_FORMAT_YCBCR422; -+ else if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) -+ *color_format = RK_IF_FORMAT_YCBCR444; -+ break; -+ case RK_IF_FORMAT_YCBCR420: -+ if (conn_state->connector->ycbcr_420_allowed && -+ drm_mode_is_420(info, &mode) && pixclock >= 594000) -+ *color_format = RK_IF_FORMAT_YCBCR420; -+ break; -+ case RK_IF_FORMAT_YCBCR422: -+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) -+ *color_format = RK_IF_FORMAT_YCBCR422; -+ break; -+ case RK_IF_FORMAT_YCBCR444: -+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) -+ *color_format = RK_IF_FORMAT_YCBCR444; -+ break; -+ case RK_IF_FORMAT_RGB: -+ default: -+ break; -+ } -+ -+ if (*color_format == RK_IF_FORMAT_RGB && -+ info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) -+ support_dc = true; -+ if (*color_format == RK_IF_FORMAT_YCBCR444 && -+ info->edid_hdmi_rgb444_dc_modes & -+ (DRM_EDID_HDMI_DC_Y444 | DRM_EDID_HDMI_DC_30)) -+ support_dc = true; -+ if (*color_format == RK_IF_FORMAT_YCBCR422) -+ support_dc = true; -+ if (*color_format == RK_IF_FORMAT_YCBCR420 && -+ info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) -+ support_dc = true; -+ -+ if (hdmi->colordepth > 8 && support_dc) -+ color_depth = 10; -+ else -+ color_depth = 8; -+ -+ if (!sink_is_hdmi) { -+ *color_format = RK_IF_FORMAT_RGB; -+ color_depth = 8; -+ } -+ -+ *eotf = HDMI_EOTF_TRADITIONAL_GAMMA_SDR; -+ if (conn_state->hdr_output_metadata) { -+ hdr_metadata = (struct hdr_output_metadata *) -+ conn_state->hdr_output_metadata->data; -+ output_eotf = hdr_metadata->hdmi_metadata_type1.eotf; -+ if (output_eotf > HDMI_EOTF_TRADITIONAL_GAMMA_SDR && -+ output_eotf <= HDMI_EOTF_BT_2100_HLG) -+ *eotf = output_eotf; -+ } -+ -+ hdmi->colorimetry = conn_state->colorspace; -+ -+ if ((*eotf > HDMI_EOTF_TRADITIONAL_GAMMA_SDR && -+ conn_state->connector->hdr_sink_metadata.hdmi_type1.eotf & -+ BIT(*eotf)) || ((hdmi->colorimetry >= DRM_MODE_COLORIMETRY_BT2020_CYCC) && -+ (hdmi->colorimetry <= DRM_MODE_COLORIMETRY_BT2020_YCC))) -+ *enc_out_encoding = V4L2_YCBCR_ENC_BT2020; -+ else if ((vic == 6) || (vic == 7) || (vic == 21) || (vic == 22) || -+ (vic == 2) || (vic == 3) || (vic == 17) || (vic == 18)) -+ *enc_out_encoding = V4L2_YCBCR_ENC_601; -+ else -+ *enc_out_encoding = V4L2_YCBCR_ENC_709; -+ -+ if (*enc_out_encoding == V4L2_YCBCR_ENC_BT2020) { -+ /* BT2020 require color depth at lest 10bit */ -+ color_depth = 10; -+ /* We prefer use YCbCr422 to send 10bit */ -+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) -+ *color_format = RK_IF_FORMAT_YCBCR422; -+ if (hdmi->is_hdmi_qp) { -+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR420) { -+ if (mode.clock >= 340000) -+ *color_format = RK_IF_FORMAT_YCBCR420; -+ else -+ *color_format = RK_IF_FORMAT_RGB; -+ } else { -+ *color_format = RK_IF_FORMAT_RGB; -+ } -+ } -+ } -+ -+ if (mode.flags & DRM_MODE_FLAG_DBLCLK) -+ pixclock *= 2; -+ if ((mode.flags & DRM_MODE_FLAG_3D_MASK) == -+ DRM_MODE_FLAG_3D_FRAME_PACKING) -+ pixclock *= 2; -+ -+ if (*color_format == RK_IF_FORMAT_YCBCR422 || color_depth == 8) -+ tmdsclock = pixclock; -+ else -+ tmdsclock = pixclock * (color_depth) / 8; -+ -+ if (*color_format == RK_IF_FORMAT_YCBCR420) -+ tmdsclock /= 2; -+ -+ /* XXX: max_tmds_clock of some sink is 0, we think it is 340MHz. */ -+ if (!max_tmds_clock) -+ max_tmds_clock = 340000; -+ -+ max_tmds_clock = min(max_tmds_clock, hdmi->max_tmdsclk); -+ -+ if ((tmdsclock > max_tmds_clock) && !hdmi->is_hdmi_qp) { -+ if (max_tmds_clock >= 594000) { -+ color_depth = 8; -+ } else if (max_tmds_clock > 340000) { -+ if (drm_mode_is_420(info, &mode) || tmdsclock >= 594000) -+ *color_format = RK_IF_FORMAT_YCBCR420; -+ } else { -+ color_depth = 8; -+ if (drm_mode_is_420(info, &mode) || tmdsclock >= 594000) -+ *color_format = RK_IF_FORMAT_YCBCR420; -+ } -+ } -+ -+ if (hdmi->is_hdmi_qp) { -+ if (mode.clock >= 340000) { -+ if (drm_mode_is_420(info, &mode)) -+ *color_format = RK_IF_FORMAT_YCBCR420; -+ else -+ *color_format = RK_IF_FORMAT_RGB; -+ } else if (tmdsclock > max_tmds_clock) { -+ color_depth = 8; -+ if (drm_mode_is_420(info, &mode)) -+ *color_format = RK_IF_FORMAT_YCBCR420; -+ } -+ } -+ -+ if (*color_format == RK_IF_FORMAT_YCBCR420) { -+ *output_mode = ROCKCHIP_OUT_MODE_YUV420; -+ if (color_depth > 8) -+ *bus_format = MEDIA_BUS_FMT_UYYVYY10_0_5X30; -+ else -+ *bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24; -+ *bus_width = color_depth / 2; -+ } else { -+ *output_mode = ROCKCHIP_OUT_MODE_AAAA; -+ if (color_depth > 8) { -+ if (*color_format != RK_IF_FORMAT_RGB && -+ !hdmi->unsupported_yuv_input) -+ *bus_format = MEDIA_BUS_FMT_YUV10_1X30; -+ else -+ *bus_format = MEDIA_BUS_FMT_RGB101010_1X30; -+ } else { -+ if (*color_format != RK_IF_FORMAT_RGB && -+ !hdmi->unsupported_yuv_input) -+ *bus_format = MEDIA_BUS_FMT_YUV8_1X24; -+ else -+ *bus_format = MEDIA_BUS_FMT_RGB888_1X24; -+ } -+ if (*color_format == RK_IF_FORMAT_YCBCR422) -+ *bus_width = 8; -+ else -+ *bus_width = color_depth; -+ } -+ -+ hdmi->bus_format = *bus_format; -+ -+ if (*color_format == RK_IF_FORMAT_YCBCR422) { -+ if (color_depth == 12) -+ hdmi->output_bus_format = MEDIA_BUS_FMT_UYVY12_1X24; -+ else if (color_depth == 10) -+ hdmi->output_bus_format = MEDIA_BUS_FMT_UYVY10_1X20; -+ else -+ hdmi->output_bus_format = MEDIA_BUS_FMT_UYVY8_1X16; -+ } else { -+ hdmi->output_bus_format = *bus_format; -+ } -+} -+ -+static bool -+dw_hdmi_rockchip_check_color(struct drm_connector_state *conn_state, -+ struct rockchip_hdmi *hdmi) -+{ -+ struct drm_crtc_state *crtc_state = conn_state->crtc->state; -+ unsigned int colorformat; -+ unsigned long bus_format; -+ unsigned long output_bus_format = hdmi->output_bus_format; -+ unsigned long enc_out_encoding = hdmi->enc_out_encoding; -+ unsigned int eotf, bus_width; -+ unsigned int output_mode; -+ -+ dw_hdmi_rockchip_select_output(conn_state, crtc_state, hdmi, -+ &colorformat, -+ &output_mode, &bus_format, &bus_width, -+ &hdmi->enc_out_encoding, &eotf); -+ -+ if (output_bus_format != hdmi->output_bus_format || -+ enc_out_encoding != hdmi->enc_out_encoding) -+ return true; -+ else -+ return false; -+} -+ -+static int -+dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state) -+{ -+ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); -+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); -+ unsigned int colorformat, bus_width, tmdsclk; -+ struct drm_display_mode mode; -+ unsigned int output_mode; -+ unsigned long bus_format; -+ int color_depth; -+ bool secondary = false; -+ -+ /* -+ * There are two hdmi but only one encoder in split mode, -+ * so we need to check twice. -+ */ -+secondary: -+ drm_mode_copy(&mode, &crtc_state->mode); -+ -+ hdmi->vp_id = s->vp_id; -+ if (hdmi->plat_data->split_mode) -+ drm_mode_convert_to_origin_mode(&mode); -+ -+ dw_hdmi_rockchip_select_output(conn_state, crtc_state, hdmi, -+ &colorformat, -+ &output_mode, &bus_format, &bus_width, -+ &hdmi->enc_out_encoding, &s->eotf); -+ -+ s->bus_format = bus_format; -+ if (hdmi->is_hdmi_qp) { -+ color_depth = hdmi_bus_fmt_color_depth(bus_format); -+ tmdsclk = hdmi_get_tmdsclock(hdmi, crtc_state->mode.clock); -+ if (hdmi_bus_fmt_is_yuv420(hdmi->output_bus_format)) -+ tmdsclk /= 2; -+ hdmi_select_link_config(hdmi, crtc_state, tmdsclk); -+ -+ if (hdmi->link_cfg.frl_mode) { -+ gpiod_set_value(hdmi->enable_gpio, 0); -+ /* in the current version, support max 40G frl */ -+ if (hdmi->link_cfg.rate_per_lane >= 10) { -+ hdmi->link_cfg.frl_lanes = 4; -+ hdmi->link_cfg.rate_per_lane = 10; -+ } -+ bus_width = hdmi->link_cfg.frl_lanes * -+ hdmi->link_cfg.rate_per_lane * 1000000; -+ /* 10 bit color depth and frl mode */ -+ if (color_depth == 10) -+ bus_width |= -+ COLOR_DEPTH_10BIT | HDMI_FRL_MODE; -+ else -+ bus_width |= HDMI_FRL_MODE; -+ } else { -+ gpiod_set_value(hdmi->enable_gpio, 1); -+ bus_width = hdmi_get_tmdsclock(hdmi, mode.clock * 10); -+ if (hdmi_bus_fmt_is_yuv420(hdmi->output_bus_format)) -+ bus_width /= 2; -+ -+ if (color_depth == 10) -+ bus_width |= COLOR_DEPTH_10BIT; -+ } -+ } -+ -+ hdmi->phy_bus_width = bus_width; -+ -+ if (hdmi->phy) -+ phy_set_bus_width(hdmi->phy, bus_width); -+ -+ s->output_type = DRM_MODE_CONNECTOR_HDMIA; -+ s->tv_state = &conn_state->tv; -+ -+ if (hdmi->plat_data->split_mode) { -+ s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE; -+ if (hdmi->plat_data->right && hdmi->id) -+ s->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP; -+ s->output_if |= VOP_OUTPUT_IF_HDMI0 | VOP_OUTPUT_IF_HDMI1; -+ } else { -+ if (!hdmi->id) -+ s->output_if |= VOP_OUTPUT_IF_HDMI0; -+ else -+ s->output_if |= VOP_OUTPUT_IF_HDMI1; -+ } -+ -+ s->output_mode = output_mode; -+ hdmi->bus_format = s->bus_format; -+ -+ if (hdmi->enc_out_encoding == V4L2_YCBCR_ENC_BT2020) -+ s->color_space = V4L2_COLORSPACE_BT2020; -+ else if (colorformat == RK_IF_FORMAT_RGB) -+ s->color_space = V4L2_COLORSPACE_DEFAULT; -+ else if (hdmi->enc_out_encoding == V4L2_YCBCR_ENC_709) -+ s->color_space = V4L2_COLORSPACE_REC709; -+ else -+ s->color_space = V4L2_COLORSPACE_SMPTE170M; -+ -+ if (hdmi->plat_data->split_mode && !secondary) { -+ hdmi = rockchip_hdmi_find_by_id(hdmi->dev->driver, !hdmi->id); -+ secondary = true; -+ goto secondary; -+ } -+ -+ return 0; -+} -+ -+static unsigned long -+dw_hdmi_rockchip_get_input_bus_format(void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ return hdmi->bus_format; -+} -+ -+static unsigned long -+dw_hdmi_rockchip_get_output_bus_format(void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ return hdmi->output_bus_format; -+} -+ -+static unsigned long -+dw_hdmi_rockchip_get_enc_in_encoding(void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ return hdmi->enc_out_encoding; -+} -+ -+static unsigned long -+dw_hdmi_rockchip_get_enc_out_encoding(void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ return hdmi->enc_out_encoding; -+} -+ -+static unsigned long -+dw_hdmi_rockchip_get_quant_range(void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ return hdmi->hdmi_quant_range; -+} -+ -+static struct drm_property * -+dw_hdmi_rockchip_get_hdr_property(void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ return hdmi->hdr_panel_metadata_property; -+} -+ -+static struct drm_property_blob * -+dw_hdmi_rockchip_get_hdr_blob(void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ return hdmi->hdr_panel_blob_ptr; -+} -+ -+static bool -+dw_hdmi_rockchip_get_color_changed(void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ bool ret = false; -+ -+ if (hdmi->color_changed) -+ ret = true; -+ hdmi->color_changed = 0; -+ -+ return ret; -+} -+ -+static int -+dw_hdmi_rockchip_get_yuv422_format(struct drm_connector *connector, -+ struct edid *edid) -+{ -+ if (!connector || !edid) -+ return -EINVAL; -+ -+ return rockchip_drm_get_yuv422_format(connector, edid); -+} -+ -+static int -+dw_hdmi_rockchip_get_edid_dsc_info(void *data, struct edid *edid) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ if (!edid) -+ return -EINVAL; -+ -+ return rockchip_drm_parse_cea_ext(&hdmi->dsc_cap, -+ &hdmi->max_frl_rate_per_lane, -+ &hdmi->max_lanes, edid); -+} -+ -+static int -+dw_hdmi_rockchip_get_next_hdr_data(void *data, struct edid *edid, -+ struct drm_connector *connector) -+{ -+ int ret; -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ struct next_hdr_sink_data *sink_data = &hdmi->next_hdr_data; -+ size_t size = sizeof(*sink_data); -+ struct drm_property *property = hdmi->next_hdr_sink_data_property; -+ struct drm_property_blob *blob = hdmi->hdr_panel_blob_ptr; -+ -+ if (!edid) -+ return -EINVAL; -+ -+ rockchip_drm_parse_next_hdr(sink_data, edid); -+ -+ ret = drm_property_replace_global_blob(connector->dev, &blob, size, sink_data, -+ &connector->base, property); -+ -+ return ret; -+}; -+ -+static -+struct dw_hdmi_link_config *dw_hdmi_rockchip_get_link_cfg(void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ return &hdmi->link_cfg; -+} -+ -+static int dw_hdmi_dclk_set(void *data, bool enable) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ char clk_name[16]; -+ struct clk *dclk; -+ int ret; -+ -+ snprintf(clk_name, sizeof(clk_name), "dclk_vp%d", hdmi->vp_id); -+ -+ dclk = devm_clk_get(hdmi->dev, clk_name); -+ if (IS_ERR(dclk)) { -+ DRM_DEV_ERROR(hdmi->dev, "failed to get %s\n", clk_name); -+ return PTR_ERR(dclk); -+ } -+ -+ if (enable) { -+ ret = clk_prepare_enable(dclk); -+ if (ret < 0) -+ DRM_DEV_ERROR(hdmi->dev, "failed to enable dclk for video port%d - %d\n", -+ hdmi->vp_id, ret); -+ } else { -+ clk_disable_unprepare(dclk); -+ } - - return 0; - } - -+static const struct drm_prop_enum_list color_depth_enum_list[] = { -+ { 0, "Automatic" }, /* Prefer highest color depth */ -+ { 8, "24bit" }, -+ { 10, "30bit" }, -+}; -+ -+static const struct drm_prop_enum_list drm_hdmi_output_enum_list[] = { -+ { RK_IF_FORMAT_RGB, "rgb" }, -+ { RK_IF_FORMAT_YCBCR444, "ycbcr444" }, -+ { RK_IF_FORMAT_YCBCR422, "ycbcr422" }, -+ { RK_IF_FORMAT_YCBCR420, "ycbcr420" }, -+ { RK_IF_FORMAT_YCBCR_HQ, "ycbcr_high_subsampling" }, -+ { RK_IF_FORMAT_YCBCR_LQ, "ycbcr_low_subsampling" }, -+ { RK_IF_FORMAT_MAX, "invalid_output" }, -+}; -+ -+static const struct drm_prop_enum_list quant_range_enum_list[] = { -+ { HDMI_QUANTIZATION_RANGE_DEFAULT, "default" }, -+ { HDMI_QUANTIZATION_RANGE_LIMITED, "limit" }, -+ { HDMI_QUANTIZATION_RANGE_FULL, "full" }, -+}; -+ -+static const struct drm_prop_enum_list output_hdmi_dvi_enum_list[] = { -+ { 0, "auto" }, -+ { 1, "force_hdmi" }, -+ { 2, "force_dvi" }, -+}; -+ -+static const struct drm_prop_enum_list output_type_cap_list[] = { -+ { 0, "DVI" }, -+ { 1, "HDMI" }, -+}; -+ -+static void -+dw_hdmi_rockchip_attach_properties(struct drm_connector *connector, -+ unsigned int color, int version, -+ void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ struct drm_property *prop; -+ struct rockchip_drm_private *private = connector->dev->dev_private; -+ -+ switch (color) { -+ case MEDIA_BUS_FMT_RGB101010_1X30: -+ hdmi->hdmi_output = RK_IF_FORMAT_RGB; -+ hdmi->colordepth = 10; -+ break; -+ case MEDIA_BUS_FMT_YUV8_1X24: -+ hdmi->hdmi_output = RK_IF_FORMAT_YCBCR444; -+ hdmi->colordepth = 8; -+ break; -+ case MEDIA_BUS_FMT_YUV10_1X30: -+ hdmi->hdmi_output = RK_IF_FORMAT_YCBCR444; -+ hdmi->colordepth = 10; -+ break; -+ case MEDIA_BUS_FMT_UYVY10_1X20: -+ hdmi->hdmi_output = RK_IF_FORMAT_YCBCR422; -+ hdmi->colordepth = 10; -+ break; -+ case MEDIA_BUS_FMT_UYVY8_1X16: -+ hdmi->hdmi_output = RK_IF_FORMAT_YCBCR422; -+ hdmi->colordepth = 8; -+ break; -+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: -+ hdmi->hdmi_output = RK_IF_FORMAT_YCBCR420; -+ hdmi->colordepth = 8; -+ break; -+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: -+ hdmi->hdmi_output = RK_IF_FORMAT_YCBCR420; -+ hdmi->colordepth = 10; -+ break; -+ default: -+ hdmi->hdmi_output = RK_IF_FORMAT_RGB; -+ hdmi->colordepth = 8; -+ } -+ -+ hdmi->bus_format = color; -+ -+ if (hdmi->hdmi_output == RK_IF_FORMAT_YCBCR422) { -+ if (hdmi->colordepth == 12) -+ hdmi->output_bus_format = MEDIA_BUS_FMT_UYVY12_1X24; -+ else if (hdmi->colordepth == 10) -+ hdmi->output_bus_format = MEDIA_BUS_FMT_UYVY10_1X20; -+ else -+ hdmi->output_bus_format = MEDIA_BUS_FMT_UYVY8_1X16; -+ } else { -+ hdmi->output_bus_format = hdmi->bus_format; -+ } -+ -+ /* RK3368 does not support deep color mode */ -+ if (!hdmi->color_depth_property && !hdmi->unsupported_deep_color) { -+ prop = drm_property_create_enum(connector->dev, 0, -+ RK_IF_PROP_COLOR_DEPTH, -+ color_depth_enum_list, -+ ARRAY_SIZE(color_depth_enum_list)); -+ if (prop) { -+ hdmi->color_depth_property = prop; -+ drm_object_attach_property(&connector->base, prop, 0); -+ } -+ } -+ -+ prop = drm_property_create_enum(connector->dev, 0, RK_IF_PROP_COLOR_FORMAT, -+ drm_hdmi_output_enum_list, -+ ARRAY_SIZE(drm_hdmi_output_enum_list)); -+ if (prop) { -+ hdmi->hdmi_output_property = prop; -+ drm_object_attach_property(&connector->base, prop, 0); -+ } -+ -+ prop = drm_property_create_range(connector->dev, 0, -+ RK_IF_PROP_COLOR_DEPTH_CAPS, -+ 0, 0xff); -+ if (prop) { -+ hdmi->colordepth_capacity = prop; -+ drm_object_attach_property(&connector->base, prop, 0); -+ } -+ -+ prop = drm_property_create_range(connector->dev, 0, -+ RK_IF_PROP_COLOR_FORMAT_CAPS, -+ 0, 0xf); -+ if (prop) { -+ hdmi->outputmode_capacity = prop; -+ drm_object_attach_property(&connector->base, prop, 0); -+ } -+ -+ prop = drm_property_create(connector->dev, -+ DRM_MODE_PROP_BLOB | -+ DRM_MODE_PROP_IMMUTABLE, -+ "HDR_PANEL_METADATA", 0); -+ if (prop) { -+ hdmi->hdr_panel_metadata_property = prop; -+ drm_object_attach_property(&connector->base, prop, 0); -+ } -+ -+ prop = drm_property_create(connector->dev, -+ DRM_MODE_PROP_BLOB | -+ DRM_MODE_PROP_IMMUTABLE, -+ "NEXT_HDR_SINK_DATA", 0); -+ if (prop) { -+ hdmi->next_hdr_sink_data_property = prop; -+ drm_object_attach_property(&connector->base, prop, 0); -+ } -+ -+ prop = drm_property_create_bool(connector->dev, DRM_MODE_PROP_IMMUTABLE, -+ "USER_SPLIT_MODE"); -+ if (prop) { -+ hdmi->user_split_mode_prop = prop; -+ drm_object_attach_property(&connector->base, prop, -+ hdmi->user_split_mode ? 1 : 0); -+ } -+ -+ if (!hdmi->is_hdmi_qp) { -+ prop = drm_property_create_enum(connector->dev, 0, -+ "output_hdmi_dvi", -+ output_hdmi_dvi_enum_list, -+ ARRAY_SIZE(output_hdmi_dvi_enum_list)); -+ if (prop) { -+ hdmi->output_hdmi_dvi = prop; -+ drm_object_attach_property(&connector->base, prop, 0); -+ } -+ -+ prop = drm_property_create_enum(connector->dev, 0, -+ "output_type_capacity", -+ output_type_cap_list, -+ ARRAY_SIZE(output_type_cap_list)); -+ if (prop) { -+ hdmi->output_type_capacity = prop; -+ drm_object_attach_property(&connector->base, prop, 0); -+ } -+ -+ prop = drm_property_create_enum(connector->dev, 0, -+ "hdmi_quant_range", -+ quant_range_enum_list, -+ ARRAY_SIZE(quant_range_enum_list)); -+ if (prop) { -+ hdmi->quant_range = prop; -+ drm_object_attach_property(&connector->base, prop, 0); -+ } -+ } -+ -+ prop = connector->dev->mode_config.hdr_output_metadata_property; -+ if (version >= 0x211a || hdmi->is_hdmi_qp) -+ drm_object_attach_property(&connector->base, prop, 0); -+ -+ if (!drm_mode_create_hdmi_colorspace_property(connector, 0)) -+ drm_object_attach_property(&connector->base, -+ connector->colorspace_property, 0); -+ -+ // [CC:] if this is not needed, also drop connector_id_prop -+ if (!private->connector_id_prop) -+ private->connector_id_prop = drm_property_create_range(connector->dev, -+ DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_IMMUTABLE, -+ "CONNECTOR_ID", 0, 0xf); -+ if (private->connector_id_prop) -+ drm_object_attach_property(&connector->base, private->connector_id_prop, hdmi->id); -+} -+ -+static void -+dw_hdmi_rockchip_destroy_properties(struct drm_connector *connector, -+ void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ if (hdmi->color_depth_property) { -+ drm_property_destroy(connector->dev, -+ hdmi->color_depth_property); -+ hdmi->color_depth_property = NULL; -+ } -+ -+ if (hdmi->hdmi_output_property) { -+ drm_property_destroy(connector->dev, -+ hdmi->hdmi_output_property); -+ hdmi->hdmi_output_property = NULL; -+ } -+ -+ if (hdmi->colordepth_capacity) { -+ drm_property_destroy(connector->dev, -+ hdmi->colordepth_capacity); -+ hdmi->colordepth_capacity = NULL; -+ } -+ -+ if (hdmi->outputmode_capacity) { -+ drm_property_destroy(connector->dev, -+ hdmi->outputmode_capacity); -+ hdmi->outputmode_capacity = NULL; -+ } -+ -+ if (hdmi->quant_range) { -+ drm_property_destroy(connector->dev, -+ hdmi->quant_range); -+ hdmi->quant_range = NULL; -+ } -+ -+ if (hdmi->hdr_panel_metadata_property) { -+ drm_property_destroy(connector->dev, -+ hdmi->hdr_panel_metadata_property); -+ hdmi->hdr_panel_metadata_property = NULL; -+ } -+ -+ if (hdmi->next_hdr_sink_data_property) { -+ drm_property_destroy(connector->dev, -+ hdmi->next_hdr_sink_data_property); -+ hdmi->next_hdr_sink_data_property = NULL; -+ } -+ -+ if (hdmi->output_hdmi_dvi) { -+ drm_property_destroy(connector->dev, -+ hdmi->output_hdmi_dvi); -+ hdmi->output_hdmi_dvi = NULL; -+ } -+ -+ if (hdmi->output_type_capacity) { -+ drm_property_destroy(connector->dev, -+ hdmi->output_type_capacity); -+ hdmi->output_type_capacity = NULL; -+ } -+ -+ if (hdmi->user_split_mode_prop) { -+ drm_property_destroy(connector->dev, -+ hdmi->user_split_mode_prop); -+ hdmi->user_split_mode_prop = NULL; -+ } -+} -+ -+static int -+dw_hdmi_rockchip_set_property(struct drm_connector *connector, -+ struct drm_connector_state *state, -+ struct drm_property *property, -+ u64 val, -+ void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ struct drm_mode_config *config = &connector->dev->mode_config; -+ -+ if (property == hdmi->color_depth_property) { -+ hdmi->colordepth = val; -+ /* If hdmi is disconnected, state->crtc is null */ -+ if (!state->crtc) -+ return 0; -+ if (dw_hdmi_rockchip_check_color(state, hdmi)) -+ hdmi->color_changed++; -+ return 0; -+ } else if (property == hdmi->hdmi_output_property) { -+ hdmi->hdmi_output = val; -+ if (!state->crtc) -+ return 0; -+ if (dw_hdmi_rockchip_check_color(state, hdmi)) -+ hdmi->color_changed++; -+ return 0; -+ } else if (property == hdmi->quant_range) { -+ u64 quant_range = hdmi->hdmi_quant_range; -+ -+ hdmi->hdmi_quant_range = val; -+ if (quant_range != hdmi->hdmi_quant_range) -+ dw_hdmi_set_quant_range(hdmi->hdmi); -+ return 0; -+ } else if (property == config->hdr_output_metadata_property) { -+ return 0; -+ } else if (property == hdmi->output_hdmi_dvi) { -+ if (hdmi->force_output != val) -+ hdmi->color_changed++; -+ hdmi->force_output = val; -+ dw_hdmi_set_output_type(hdmi->hdmi, val); -+ return 0; -+ } else if (property == hdmi->colordepth_capacity) { -+ return 0; -+ } else if (property == hdmi->outputmode_capacity) { -+ return 0; -+ } else if (property == hdmi->output_type_capacity) { -+ return 0; -+ } -+ -+ DRM_ERROR("Unknown property [PROP:%d:%s]\n", -+ property->base.id, property->name); -+ -+ return -EINVAL; -+} -+ -+static int -+dw_hdmi_rockchip_get_property(struct drm_connector *connector, -+ const struct drm_connector_state *state, -+ struct drm_property *property, -+ u64 *val, -+ void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ struct drm_display_info *info = &connector->display_info; -+ struct drm_mode_config *config = &connector->dev->mode_config; -+ -+ if (property == hdmi->color_depth_property) { -+ *val = hdmi->colordepth; -+ return 0; -+ } else if (property == hdmi->hdmi_output_property) { -+ *val = hdmi->hdmi_output; -+ return 0; -+ } else if (property == hdmi->colordepth_capacity) { -+ *val = BIT(RK_IF_DEPTH_8); -+ /* RK3368 only support 8bit */ -+ if (hdmi->unsupported_deep_color) -+ return 0; -+ if (info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) -+ *val |= BIT(RK_IF_DEPTH_10); -+ if (info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36) -+ *val |= BIT(RK_IF_DEPTH_12); -+ if (info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_48) -+ *val |= BIT(RK_IF_DEPTH_16); -+ if (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) -+ *val |= BIT(RK_IF_DEPTH_420_10); -+ if (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) -+ *val |= BIT(RK_IF_DEPTH_420_12); -+ if (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48) -+ *val |= BIT(RK_IF_DEPTH_420_16); -+ return 0; -+ } else if (property == hdmi->outputmode_capacity) { -+ *val = BIT(RK_IF_FORMAT_RGB); -+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) -+ *val |= BIT(RK_IF_FORMAT_YCBCR444); -+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) -+ *val |= BIT(RK_IF_FORMAT_YCBCR422); -+ if (connector->ycbcr_420_allowed && -+ info->color_formats & DRM_COLOR_FORMAT_YCBCR420) -+ *val |= BIT(RK_IF_FORMAT_YCBCR420); -+ return 0; -+ } else if (property == hdmi->quant_range) { -+ *val = hdmi->hdmi_quant_range; -+ return 0; -+ } else if (property == config->hdr_output_metadata_property) { -+ *val = state->hdr_output_metadata ? -+ state->hdr_output_metadata->base.id : 0; -+ return 0; -+ } else if (property == hdmi->output_hdmi_dvi) { -+ *val = hdmi->force_output; -+ return 0; -+ } else if (property == hdmi->output_type_capacity) { -+ *val = dw_hdmi_get_output_type_cap(hdmi->hdmi); -+ return 0; -+ } else if (property == hdmi->user_split_mode_prop) { -+ *val = hdmi->user_split_mode; -+ return 0; -+ } -+ -+ DRM_ERROR("Unknown property [PROP:%d:%s]\n", -+ property->base.id, property->name); -+ -+ return -EINVAL; -+} -+ -+static const struct dw_hdmi_property_ops dw_hdmi_rockchip_property_ops = { -+ .attach_properties = dw_hdmi_rockchip_attach_properties, -+ .destroy_properties = dw_hdmi_rockchip_destroy_properties, -+ .set_property = dw_hdmi_rockchip_set_property, -+ .get_property = dw_hdmi_rockchip_get_property, -+}; -+ - static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = { - .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup, - .mode_set = dw_hdmi_rockchip_encoder_mode_set, -@@ -357,20 +2526,24 @@ static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_fun - .atomic_check = dw_hdmi_rockchip_encoder_atomic_check, - }; - --static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, -- const struct drm_display_info *display, -- const struct drm_display_mode *mode) -+static void dw_hdmi_rockchip_genphy_disable(struct dw_hdmi *dw_hdmi, void *data) - { - struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; - -- return phy_power_on(hdmi->phy); -+ while (hdmi->phy->power_count > 0) -+ phy_power_off(hdmi->phy); - } - --static void dw_hdmi_rockchip_genphy_disable(struct dw_hdmi *dw_hdmi, void *data) -+static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, -+ const struct drm_display_info *display, -+ const struct drm_display_mode *mode) - { - struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; - -- phy_power_off(hdmi->phy); -+ dw_hdmi_rockchip_genphy_disable(dw_hdmi, data); -+ dw_hdmi_set_high_tmds_clock_ratio(dw_hdmi, display); -+ -+ return phy_power_on(hdmi->phy); - } - - static void dw_hdmi_rk3228_setup_hpd(struct dw_hdmi *dw_hdmi, void *data) -@@ -437,6 +2610,90 @@ static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data) - RK3328_HDMI_HPD_IOE)); - } - -+static void dw_hdmi_qp_rockchip_phy_disable(struct dw_hdmi_qp *dw_hdmi, -+ void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ while (hdmi->phy->power_count > 0) -+ phy_power_off(hdmi->phy); -+} -+ -+static int dw_hdmi_qp_rockchip_genphy_init(struct dw_hdmi_qp *dw_hdmi, void *data, -+ struct drm_display_mode *mode) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ dw_hdmi_qp_rockchip_phy_disable(dw_hdmi, data); -+ -+ return phy_power_on(hdmi->phy); -+} -+ -+static enum drm_connector_status -+dw_hdmi_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data) -+{ -+ u32 val; -+ int ret; -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &val); -+ -+ if (!hdmi->id) { -+ if (val & RK3588_HDMI0_LEVEL_INT) { -+ hdmi->hpd_stat = true; -+ ret = connector_status_connected; -+ } else { -+ hdmi->hpd_stat = false; -+ ret = connector_status_disconnected; -+ } -+ } else { -+ if (val & RK3588_HDMI1_LEVEL_INT) { -+ hdmi->hpd_stat = true; -+ ret = connector_status_connected; -+ } else { -+ hdmi->hpd_stat = false; -+ ret = connector_status_disconnected; -+ } -+ } -+ -+ return ret; -+} -+ -+static void dw_hdmi_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ u32 val; -+ -+ if (!hdmi->id) { -+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, -+ RK3588_HDMI0_HPD_INT_CLR) | -+ HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK); -+ } else { -+ val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_CLR, -+ RK3588_HDMI1_HPD_INT_CLR) | -+ HIWORD_UPDATE(0, RK3588_HDMI1_HPD_INT_MSK); -+ } -+ -+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); -+} -+ -+static void dw_hdmi_rk3588_phy_set_mode(struct dw_hdmi_qp *dw_hdmi, void *data, -+ u32 mode_mask, bool enable) -+{ -+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; -+ -+ if (!hdmi->phy) -+ return; -+ -+ /* set phy earc/frl mode */ -+ if (enable) -+ hdmi->phy_bus_width |= mode_mask; -+ else -+ hdmi->phy_bus_width &= ~mode_mask; -+ -+ phy_set_bus_width(hdmi->phy, hdmi->phy_bus_width); -+} -+ - static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = { - .init = dw_hdmi_rockchip_genphy_init, - .disable = dw_hdmi_rockchip_genphy_disable, -@@ -526,6 +2783,30 @@ static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = { - .use_drm_infoframe = true, - }; - -+static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = { -+ .init = dw_hdmi_qp_rockchip_genphy_init, -+ .disable = dw_hdmi_qp_rockchip_phy_disable, -+ .read_hpd = dw_hdmi_rk3588_read_hpd, -+ .setup_hpd = dw_hdmi_rk3588_setup_hpd, -+ .set_mode = dw_hdmi_rk3588_phy_set_mode, -+}; -+ -+struct rockchip_hdmi_chip_data rk3588_hdmi_chip_data = { -+ .lcdsel_grf_reg = -1, -+ .ddc_en_reg = RK3588_GRF_VO1_CON3, -+ .split_mode = true, -+}; -+ -+static const struct dw_hdmi_plat_data rk3588_hdmi_drv_data = { -+ .phy_data = &rk3588_hdmi_chip_data, -+ .qp_phy_ops = &rk3588_hdmi_phy_ops, -+ .phy_name = "samsung_hdptx_phy", -+ .phy_force_vendor = true, -+ .ycbcr_420_allowed = true, -+ .is_hdmi_qp = true, -+ .use_drm_infoframe = true, -+}; -+ - static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { - { .compatible = "rockchip,rk3228-dw-hdmi", - .data = &rk3228_hdmi_drv_data -@@ -542,6 +2823,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); -@@ -551,44 +2835,107 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - { - struct platform_device *pdev = to_platform_device(dev); - struct dw_hdmi_plat_data *plat_data; -- const struct of_device_id *match; - struct drm_device *drm = data; - struct drm_encoder *encoder; - struct rockchip_hdmi *hdmi; -+ struct rockchip_hdmi *secondary; - int ret; -+ u32 val; - - if (!pdev->dev.of_node) - return -ENODEV; - -- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); -+ hdmi = platform_get_drvdata(pdev); - if (!hdmi) - return -ENOMEM; - -- 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); -- if (!plat_data) -- return -ENOMEM; -+ plat_data = hdmi->plat_data; -+ hdmi->drm_dev = drm; - -- hdmi->dev = &pdev->dev; -- hdmi->plat_data = plat_data; -- hdmi->chip_data = plat_data->phy_data; - plat_data->phy_data = hdmi; -- plat_data->priv_data = hdmi; -- encoder = &hdmi->encoder.encoder; -+ plat_data->get_input_bus_format = -+ dw_hdmi_rockchip_get_input_bus_format; -+ plat_data->get_output_bus_format = -+ dw_hdmi_rockchip_get_output_bus_format; -+ plat_data->get_enc_in_encoding = -+ dw_hdmi_rockchip_get_enc_in_encoding; -+ plat_data->get_enc_out_encoding = -+ dw_hdmi_rockchip_get_enc_out_encoding; -+ plat_data->get_quant_range = -+ dw_hdmi_rockchip_get_quant_range; -+ plat_data->get_hdr_property = -+ dw_hdmi_rockchip_get_hdr_property; -+ plat_data->get_hdr_blob = -+ dw_hdmi_rockchip_get_hdr_blob; -+ plat_data->get_color_changed = -+ dw_hdmi_rockchip_get_color_changed; -+ plat_data->get_yuv422_format = -+ dw_hdmi_rockchip_get_yuv422_format; -+ plat_data->get_edid_dsc_info = -+ dw_hdmi_rockchip_get_edid_dsc_info; -+ plat_data->get_next_hdr_data = -+ dw_hdmi_rockchip_get_next_hdr_data; -+ plat_data->get_link_cfg = dw_hdmi_rockchip_get_link_cfg; -+ plat_data->set_grf_cfg = rk3588_set_grf_cfg; -+ plat_data->convert_to_split_mode = drm_mode_convert_to_split_mode; -+ plat_data->convert_to_origin_mode = drm_mode_convert_to_origin_mode; -+ plat_data->dclk_set = dw_hdmi_dclk_set; -+ -+ plat_data->property_ops = &dw_hdmi_rockchip_property_ops; -+ -+ secondary = rockchip_hdmi_find_by_id(dev->driver, !hdmi->id); -+ /* If don't enable hdmi0 and hdmi1, we don't enable split mode */ -+ if (hdmi->chip_data->split_mode && secondary) { - -- encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); -- rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder, -- dev->of_node, 0, 0); -+ /* -+ * hdmi can only attach bridge and init encoder/connector in the -+ * last bind hdmi in split mode, or hdmi->hdmi_qp will not be initialized -+ * and plat_data->left/right will be null pointer. we must check if split -+ * mode is on and determine the sequence of hdmi bind. -+ */ -+ if (device_property_read_bool(dev, "split-mode") || -+ device_property_read_bool(secondary->dev, "split-mode")) { -+ plat_data->split_mode = true; -+ secondary->plat_data->split_mode = true; -+ if (!secondary->plat_data->first_screen) -+ plat_data->first_screen = true; -+ } -+ -+ if (device_property_read_bool(dev, "user-split-mode") || -+ device_property_read_bool(secondary->dev, "user-split-mode")) { -+ hdmi->user_split_mode = true; -+ secondary->user_split_mode = true; -+ } -+ } - -- /* -- * If we failed to find the CRTC(s) which this encoder is -- * supposed to be connected to, it's because the CRTC has -- * not been registered yet. Defer probing, and hope that -- * the required CRTC is added later. -- */ -- if (encoder->possible_crtcs == 0) -- return -EPROBE_DEFER; -+ if (!plat_data->first_screen) { -+ encoder = &hdmi->encoder.encoder; -+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); -+ rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder, -+ dev->of_node, 0, 0); -+ /* -+ * If we failed to find the CRTC(s) which this encoder is -+ * supposed to be connected to, it's because the CRTC has -+ * not been registered yet. Defer probing, and hope that -+ * the required CRTC is added later. -+ */ -+ if (encoder->possible_crtcs == 0) -+ return -EPROBE_DEFER; -+ -+ drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); -+ // [CC:] consider using drmm_simple_encoder_alloc() -+ drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); -+ } -+ -+ if (!plat_data->max_tmdsclk) -+ hdmi->max_tmdsclk = 594000; -+ else -+ hdmi->max_tmdsclk = plat_data->max_tmdsclk; -+ -+ hdmi->is_hdmi_qp = plat_data->is_hdmi_qp; -+ -+ hdmi->unsupported_yuv_input = plat_data->unsupported_yuv_input; -+ hdmi->unsupported_deep_color = plat_data->unsupported_deep_color; - - ret = rockchip_hdmi_parse_dt(hdmi); - if (ret) { -@@ -597,34 +2944,44 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - return ret; - } - -- hdmi->phy = devm_phy_optional_get(dev, "hdmi"); -- if (IS_ERR(hdmi->phy)) { -- ret = PTR_ERR(hdmi->phy); -- if (ret != -EPROBE_DEFER) -- DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n"); -+ ret = clk_prepare_enable(hdmi->aud_clk); -+ if (ret) { -+ dev_err(hdmi->dev, "Failed to enable HDMI aud_clk: %d\n", ret); - return ret; - } - -- ret = regulator_enable(hdmi->avdd_0v9); -+ ret = clk_prepare_enable(hdmi->hpd_clk); - if (ret) { -- DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd0v9: %d\n", ret); -- goto err_avdd_0v9; -+ dev_err(hdmi->dev, "Failed to enable HDMI hpd_clk: %d\n", ret); -+ return ret; - } - -- ret = regulator_enable(hdmi->avdd_1v8); -+ ret = clk_prepare_enable(hdmi->hclk_vo1); - if (ret) { -- DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd1v8: %d\n", ret); -- goto err_avdd_1v8; -+ dev_err(hdmi->dev, "Failed to enable HDMI hclk_vo1: %d\n", ret); -+ return ret; - } - -- ret = clk_prepare_enable(hdmi->ref_clk); -+ ret = clk_prepare_enable(hdmi->earc_clk); - if (ret) { -- DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n", -- ret); -- goto err_clk; -+ dev_err(hdmi->dev, "Failed to enable HDMI earc_clk: %d\n", ret); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(hdmi->hdmitx_ref); -+ if (ret) { -+ dev_err(hdmi->dev, "Failed to enable HDMI hdmitx_ref: %d\n", -+ ret); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(hdmi->pclk); -+ if (ret) { -+ dev_err(hdmi->dev, "Failed to enable HDMI pclk: %d\n", ret); -+ return ret; - } - -- if (hdmi->chip_data == &rk3568_chip_data) { -+ if (hdmi->chip_data->ddc_en_reg == RK3568_GRF_VO_CON1) { - regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1, - HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK | - RK3568_HDMI_SCLIN_MSK, -@@ -632,12 +2989,132 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - RK3568_HDMI_SCLIN_MSK)); - } - -- drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); -- drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); -+ if (hdmi->is_hdmi_qp) { -+ if (!hdmi->id) { -+ 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); -+ } else { -+ 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_CON6, 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_HDMI1_GRANT_SEL, -+ RK3588_HDMI1_GRANT_SEL); -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON9, val); -+ } -+ init_hpd_work(hdmi); -+ } - -- platform_set_drvdata(pdev, hdmi); -+ ret = clk_prepare_enable(hdmi->hclk_vio); -+ if (ret) { -+ dev_err(hdmi->dev, "Failed to enable HDMI hclk_vio: %d\n", -+ ret); -+ return ret; -+ } - -- hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data); -+ ret = clk_prepare_enable(hdmi->hclk_vop); -+ if (ret) { -+ dev_err(hdmi->dev, "Failed to enable HDMI hclk_vop: %d\n", -+ ret); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(hdmi->ref_clk); -+ if (ret) { -+ DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n", -+ ret); -+ goto err_clk; -+ } -+ -+ ret = regulator_enable(hdmi->avdd_0v9); -+ if (ret) { -+ DRM_DEV_ERROR(hdmi->dev, "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); -+ goto err_avdd_1v8; -+ } -+ -+ if (!hdmi->id) -+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK); -+ else -+ val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_MSK, RK3588_HDMI1_HPD_INT_MSK); -+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); -+ -+ if (hdmi->is_hdmi_qp) { -+ hdmi->hpd_irq = platform_get_irq(pdev, 4); -+ if (hdmi->hpd_irq < 0) -+ return hdmi->hpd_irq; -+ -+ ret = devm_request_threaded_irq(hdmi->dev, hdmi->hpd_irq, -+ rockchip_hdmi_hardirq, -+ rockchip_hdmi_irq, -+ IRQF_SHARED, "dw-hdmi-qp-hpd", -+ hdmi); -+ if (ret) -+ return ret; -+ } -+ -+ hdmi->phy = devm_phy_optional_get(dev, "hdmi"); -+ if (IS_ERR(hdmi->phy)) { -+ hdmi->phy = devm_phy_optional_get(dev, "hdmi_phy"); -+ if (IS_ERR(hdmi->phy)) { -+ ret = PTR_ERR(hdmi->phy); -+ if (ret != -EPROBE_DEFER) -+ DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n"); -+ return ret; -+ } -+ } -+ -+ if (hdmi->is_hdmi_qp) { -+ // [CC:] do proper error handling, e.g. clk_disable_unprepare -+ hdmi->hdmi_qp = dw_hdmi_qp_bind(pdev, &hdmi->encoder.encoder, plat_data); -+ -+ if (IS_ERR(hdmi->hdmi_qp)) { -+ ret = PTR_ERR(hdmi->hdmi_qp); -+ drm_encoder_cleanup(&hdmi->encoder.encoder); -+ } -+ -+ if (plat_data->connector) { -+ hdmi->sub_dev.connector = plat_data->connector; -+ hdmi->sub_dev.of_node = dev->of_node; -+ rockchip_drm_register_sub_dev(&hdmi->sub_dev); -+ } -+ -+ if (plat_data->split_mode && secondary) { -+ if (device_property_read_bool(dev, "split-mode")) { -+ plat_data->right = secondary->hdmi_qp; -+ secondary->plat_data->left = hdmi->hdmi_qp; -+ } else { -+ plat_data->left = secondary->hdmi_qp; -+ secondary->plat_data->right = hdmi->hdmi_qp; -+ } -+ } -+ -+ return ret; -+ } -+ -+ hdmi->hdmi = dw_hdmi_bind(pdev, &hdmi->encoder.encoder, plat_data); - - /* - * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), -@@ -648,11 +3125,24 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - goto err_bind; - } - -+ if (plat_data->connector) { -+ hdmi->sub_dev.connector = plat_data->connector; -+ hdmi->sub_dev.of_node = dev->of_node; -+ rockchip_drm_register_sub_dev(&hdmi->sub_dev); -+ } -+ - return 0; - - err_bind: -- drm_encoder_cleanup(encoder); -+ drm_encoder_cleanup(&hdmi->encoder.encoder); -+ clk_disable_unprepare(hdmi->aud_clk); - clk_disable_unprepare(hdmi->ref_clk); -+ clk_disable_unprepare(hdmi->hclk_vop); -+ clk_disable_unprepare(hdmi->hpd_clk); -+ clk_disable_unprepare(hdmi->hclk_vo1); -+ clk_disable_unprepare(hdmi->earc_clk); -+ clk_disable_unprepare(hdmi->hdmitx_ref); -+ clk_disable_unprepare(hdmi->pclk); - err_clk: - regulator_disable(hdmi->avdd_1v8); - err_avdd_1v8: -@@ -666,9 +3156,30 @@ 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(&hdmi->work); -+ flush_workqueue(hdmi->workqueue); -+ destroy_workqueue(hdmi->workqueue); -+ } -+ -+ if (hdmi->sub_dev.connector) -+ rockchip_drm_unregister_sub_dev(&hdmi->sub_dev); -+ -+ if (hdmi->is_hdmi_qp) -+ dw_hdmi_qp_unbind(hdmi->hdmi_qp); -+ else -+ dw_hdmi_unbind(hdmi->hdmi); -+ - drm_encoder_cleanup(&hdmi->encoder.encoder); -+ -+ clk_disable_unprepare(hdmi->aud_clk); - clk_disable_unprepare(hdmi->ref_clk); -+ clk_disable_unprepare(hdmi->hclk_vop); -+ clk_disable_unprepare(hdmi->hpd_clk); -+ clk_disable_unprepare(hdmi->hclk_vo1); -+ clk_disable_unprepare(hdmi->earc_clk); -+ clk_disable_unprepare(hdmi->hdmitx_ref); -+ clk_disable_unprepare(hdmi->pclk); - - regulator_disable(hdmi->avdd_1v8); - regulator_disable(hdmi->avdd_0v9); -@@ -681,30 +3192,131 @@ static const struct component_ops dw_hdmi_rockchip_ops = { - - static int dw_hdmi_rockchip_probe(struct platform_device *pdev) - { -+ struct rockchip_hdmi *hdmi; -+ const struct of_device_id *match; -+ struct dw_hdmi_plat_data *plat_data; -+ int id; -+ -+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); -+ if (!hdmi) -+ return -ENOMEM; -+ -+ id = of_alias_get_id(pdev->dev.of_node, "hdmi"); -+ if (id < 0) -+ id = 0; -+ -+ hdmi->id = id; -+ hdmi->dev = &pdev->dev; -+ -+ 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); -+ if (!plat_data) -+ return -ENOMEM; -+ -+ plat_data->id = hdmi->id; -+ hdmi->plat_data = plat_data; -+ hdmi->chip_data = plat_data->phy_data; -+ -+ platform_set_drvdata(pdev, hdmi); -+ pm_runtime_enable(&pdev->dev); -+ pm_runtime_get_sync(&pdev->dev); -+ - return component_add(&pdev->dev, &dw_hdmi_rockchip_ops); - } - -+static void dw_hdmi_rockchip_shutdown(struct platform_device *pdev) -+{ -+ struct rockchip_hdmi *hdmi = dev_get_drvdata(&pdev->dev); -+ -+ if (!hdmi) -+ return; -+ -+ if (hdmi->is_hdmi_qp) { -+ cancel_delayed_work(&hdmi->work); -+ flush_workqueue(hdmi->workqueue); -+ dw_hdmi_qp_suspend(hdmi->dev, hdmi->hdmi_qp); -+ } else { -+ dw_hdmi_suspend(hdmi->hdmi); -+ } -+ pm_runtime_put_sync(&pdev->dev); -+} -+ - static void dw_hdmi_rockchip_remove(struct platform_device *pdev) - { - component_del(&pdev->dev, &dw_hdmi_rockchip_ops); -+ pm_runtime_disable(&pdev->dev); -+} -+ -+static int dw_hdmi_rockchip_suspend(struct device *dev) -+{ -+ struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); -+ -+ if (hdmi->is_hdmi_qp) -+ dw_hdmi_qp_suspend(dev, hdmi->hdmi_qp); -+ else -+ dw_hdmi_suspend(hdmi->hdmi); -+ -+ pm_runtime_put_sync(dev); -+ -+ return 0; - } - - static int __maybe_unused dw_hdmi_rockchip_resume(struct device *dev) - { - struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); -+ u32 val; - -- dw_hdmi_resume(hdmi->hdmi); -+ if (hdmi->is_hdmi_qp) { -+ if (!hdmi->id) { -+ 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); -+ } else { -+ 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_CON6, 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_HDMI1_GRANT_SEL, -+ RK3588_HDMI1_GRANT_SEL); -+ regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON9, val); -+ } -+ -+ dw_hdmi_qp_resume(dev, hdmi->hdmi_qp); -+ drm_helper_hpd_irq_event(hdmi->drm_dev); -+ } else { -+ dw_hdmi_resume(hdmi->hdmi); -+ } -+ pm_runtime_get_sync(dev); - - return 0; - } - - static const struct dev_pm_ops dw_hdmi_rockchip_pm = { -- SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_rockchip_resume) -+ SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_rockchip_suspend, -+ dw_hdmi_rockchip_resume) - }; - - struct platform_driver dw_hdmi_rockchip_pltfm_driver = { - .probe = dw_hdmi_rockchip_probe, - .remove_new = dw_hdmi_rockchip_remove, -+ .shutdown = dw_hdmi_rockchip_shutdown, - .driver = { - .name = "dwhdmi-rockchip", - .pm = &dw_hdmi_rockchip_pm, -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c -index ab55d7132..44d49c86b 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c -@@ -17,8 +17,12 @@ - #include - - #include -+#include -+#include -+#include - #include - #include -+//#include - #include - #include - #include -@@ -44,6 +48,629 @@ - - static const struct drm_driver rockchip_drm_driver; - -+void drm_mode_convert_to_split_mode(struct drm_display_mode *mode) -+{ -+ u16 hactive, hfp, hsync, hbp; -+ -+ hactive = mode->hdisplay; -+ hfp = mode->hsync_start - mode->hdisplay; -+ hsync = mode->hsync_end - mode->hsync_start; -+ hbp = mode->htotal - mode->hsync_end; -+ -+ mode->clock *= 2; -+ mode->hdisplay = hactive * 2; -+ mode->hsync_start = mode->hdisplay + hfp * 2; -+ mode->hsync_end = mode->hsync_start + hsync * 2; -+ mode->htotal = mode->hsync_end + hbp * 2; -+ drm_mode_set_name(mode); -+} -+EXPORT_SYMBOL(drm_mode_convert_to_split_mode); -+ -+void drm_mode_convert_to_origin_mode(struct drm_display_mode *mode) -+{ -+ u16 hactive, hfp, hsync, hbp; -+ -+ hactive = mode->hdisplay; -+ hfp = mode->hsync_start - mode->hdisplay; -+ hsync = mode->hsync_end - mode->hsync_start; -+ hbp = mode->htotal - mode->hsync_end; -+ -+ mode->clock /= 2; -+ mode->hdisplay = hactive / 2; -+ mode->hsync_start = mode->hdisplay + hfp / 2; -+ mode->hsync_end = mode->hsync_start + hsync / 2; -+ mode->htotal = mode->hsync_end + hbp / 2; -+} -+EXPORT_SYMBOL(drm_mode_convert_to_origin_mode); -+ -+static DEFINE_MUTEX(rockchip_drm_sub_dev_lock); -+static LIST_HEAD(rockchip_drm_sub_dev_list); -+ -+void rockchip_drm_register_sub_dev(struct rockchip_drm_sub_dev *sub_dev) -+{ -+ mutex_lock(&rockchip_drm_sub_dev_lock); -+ list_add_tail(&sub_dev->list, &rockchip_drm_sub_dev_list); -+ mutex_unlock(&rockchip_drm_sub_dev_lock); -+} -+EXPORT_SYMBOL(rockchip_drm_register_sub_dev); -+ -+void rockchip_drm_unregister_sub_dev(struct rockchip_drm_sub_dev *sub_dev) -+{ -+ mutex_lock(&rockchip_drm_sub_dev_lock); -+ list_del(&sub_dev->list); -+ mutex_unlock(&rockchip_drm_sub_dev_lock); -+} -+EXPORT_SYMBOL(rockchip_drm_unregister_sub_dev); -+ -+static int -+cea_db_tag(const u8 *db) -+{ -+ return db[0] >> 5; -+} -+ -+static int -+cea_db_payload_len(const u8 *db) -+{ -+ return db[0] & 0x1f; -+} -+ -+#define for_each_cea_db(cea, i, start, end) \ -+ for ((i) = (start); \ -+ (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); \ -+ (i) += cea_db_payload_len(&(cea)[(i)]) + 1) -+ -+#define HDMI_NEXT_HDR_VSDB_OUI 0xd04601 -+ -+static bool cea_db_is_hdmi_next_hdr_block(const u8 *db) -+{ -+ unsigned int oui; -+ -+ if (cea_db_tag(db) != 0x07) -+ return false; -+ -+ if (cea_db_payload_len(db) < 11) -+ return false; -+ -+ oui = db[3] << 16 | db[2] << 8 | db[1]; -+ -+ return oui == HDMI_NEXT_HDR_VSDB_OUI; -+} -+ -+static bool cea_db_is_hdmi_forum_vsdb(const u8 *db) -+{ -+ unsigned int oui; -+ -+ if (cea_db_tag(db) != 0x03) -+ return false; -+ -+ if (cea_db_payload_len(db) < 7) -+ return false; -+ -+ oui = db[3] << 16 | db[2] << 8 | db[1]; -+ -+ return oui == HDMI_FORUM_IEEE_OUI; -+} -+ -+static int -+cea_db_offsets(const u8 *cea, int *start, int *end) -+{ -+ /* DisplayID CTA extension blocks and top-level CEA EDID -+ * block header definitions differ in the following bytes: -+ * 1) Byte 2 of the header specifies length differently, -+ * 2) Byte 3 is only present in the CEA top level block. -+ * -+ * The different definitions for byte 2 follow. -+ * -+ * DisplayID CTA extension block defines byte 2 as: -+ * Number of payload bytes -+ * -+ * CEA EDID block defines byte 2 as: -+ * Byte number (decimal) within this block where the 18-byte -+ * DTDs begin. If no non-DTD data is present in this extension -+ * block, the value should be set to 04h (the byte after next). -+ * If set to 00h, there are no DTDs present in this block and -+ * no non-DTD data. -+ */ -+ if (cea[0] == 0x81) { -+ /* -+ * for_each_displayid_db() has already verified -+ * that these stay within expected bounds. -+ */ -+ *start = 3; -+ *end = *start + cea[2]; -+ } else if (cea[0] == 0x02) { -+ /* Data block offset in CEA extension block */ -+ *start = 4; -+ *end = cea[2]; -+ if (*end == 0) -+ *end = 127; -+ if (*end < 4 || *end > 127) -+ return -ERANGE; -+ } else { -+ return -EOPNOTSUPP; -+ } -+ -+ return 0; -+} -+ -+static u8 *find_edid_extension(const struct edid *edid, -+ int ext_id, int *ext_index) -+{ -+ u8 *edid_ext = NULL; -+ int i; -+ -+ /* No EDID or EDID extensions */ -+ if (edid == NULL || edid->extensions == 0) -+ return NULL; -+ -+ /* Find CEA extension */ -+ for (i = *ext_index; i < edid->extensions; i++) { -+ edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); -+ if (edid_ext[0] == ext_id) -+ break; -+ } -+ -+ if (i >= edid->extensions) -+ return NULL; -+ -+ *ext_index = i + 1; -+ -+ return edid_ext; -+} -+ -+static int validate_displayid(u8 *displayid, int length, int idx) -+{ -+ int i, dispid_length; -+ u8 csum = 0; -+ struct displayid_header *base; -+ -+ base = (struct displayid_header *)&displayid[idx]; -+ -+ DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n", -+ base->rev, base->bytes, base->prod_id, base->ext_count); -+ -+ /* +1 for DispID checksum */ -+ dispid_length = sizeof(*base) + base->bytes + 1; -+ if (dispid_length > length - idx) -+ return -EINVAL; -+ -+ for (i = 0; i < dispid_length; i++) -+ csum += displayid[idx + i]; -+ if (csum) { -+ DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static u8 *find_displayid_extension(const struct edid *edid, -+ int *length, int *idx, -+ int *ext_index) -+{ -+ u8 *displayid = find_edid_extension(edid, 0x70, ext_index); -+ struct displayid_header *base; -+ int ret; -+ -+ if (!displayid) -+ return NULL; -+ -+ /* EDID extensions block checksum isn't for us */ -+ *length = EDID_LENGTH - 1; -+ *idx = 1; -+ -+ ret = validate_displayid(displayid, *length, *idx); -+ if (ret) -+ return NULL; -+ -+ base = (struct displayid_header *)&displayid[*idx]; -+ *length = *idx + sizeof(*base) + base->bytes; -+ -+ return displayid; -+} -+ -+static u8 *find_cea_extension(const struct edid *edid) -+{ -+ int length, idx; -+ const struct displayid_block *block; -+ u8 *cea; -+ u8 *displayid; -+ int ext_index; -+ -+ /* Look for a top level CEA extension block */ -+ /* FIXME: make callers iterate through multiple CEA ext blocks? */ -+ ext_index = 0; -+ cea = find_edid_extension(edid, 0x02, &ext_index); -+ if (cea) -+ return cea; -+ -+ /* CEA blocks can also be found embedded in a DisplayID block */ -+ ext_index = 0; -+ for (;;) { -+ struct displayid_iter iter; -+ const struct drm_edid *drm_edid; -+ int edid_size = (edid->extensions + 1) * EDID_LENGTH; -+ -+ drm_edid = drm_edid_alloc(edid, edid_size); -+ if (!drm_edid) -+ return NULL; -+ displayid = find_displayid_extension(edid, &length, &idx, -+ &ext_index); -+ if (!displayid) { -+ drm_edid_free(drm_edid); -+ return NULL; -+ } -+ -+ displayid_iter_edid_begin(drm_edid, &iter); -+ idx += sizeof(struct displayid_header); -+ displayid_iter_for_each(block, &iter) { -+ if (block->tag == 0x81) { -+ displayid_iter_end(&iter); -+ drm_edid_free(drm_edid); -+ return (u8 *)block; -+ } -+ } -+ -+ displayid_iter_end(&iter); -+ drm_edid_free(drm_edid); -+ } -+ -+ return NULL; -+} -+ -+#define EDID_CEA_YCRCB422 (1 << 4) -+ -+int rockchip_drm_get_yuv422_format(struct drm_connector *connector, -+ struct edid *edid) -+{ -+ struct drm_display_info *info; -+ const u8 *edid_ext; -+ -+ if (!connector || !edid) -+ return -EINVAL; -+ -+ info = &connector->display_info; -+ -+ edid_ext = find_cea_extension(edid); -+ if (!edid_ext) -+ return -EINVAL; -+ -+ if (edid_ext[3] & EDID_CEA_YCRCB422) -+ info->color_formats |= DRM_COLOR_FORMAT_YCBCR422; -+ -+ return 0; -+} -+EXPORT_SYMBOL(rockchip_drm_get_yuv422_format); -+ -+static -+void get_max_frl_rate(int max_frl_rate, u8 *max_lanes, u8 *max_rate_per_lane) -+{ -+ switch (max_frl_rate) { -+ case 1: -+ *max_lanes = 3; -+ *max_rate_per_lane = 3; -+ break; -+ case 2: -+ *max_lanes = 3; -+ *max_rate_per_lane = 6; -+ break; -+ case 3: -+ *max_lanes = 4; -+ *max_rate_per_lane = 6; -+ break; -+ case 4: -+ *max_lanes = 4; -+ *max_rate_per_lane = 8; -+ break; -+ case 5: -+ *max_lanes = 4; -+ *max_rate_per_lane = 10; -+ break; -+ case 6: -+ *max_lanes = 4; -+ *max_rate_per_lane = 12; -+ break; -+ case 0: -+ default: -+ *max_lanes = 0; -+ *max_rate_per_lane = 0; -+ } -+} -+ -+#define EDID_DSC_10BPC (1 << 0) -+#define EDID_DSC_12BPC (1 << 1) -+#define EDID_DSC_16BPC (1 << 2) -+#define EDID_DSC_ALL_BPP (1 << 3) -+#define EDID_DSC_NATIVE_420 (1 << 6) -+#define EDID_DSC_1P2 (1 << 7) -+#define EDID_DSC_MAX_FRL_RATE_MASK 0xf0 -+#define EDID_DSC_MAX_SLICES 0xf -+#define EDID_DSC_TOTAL_CHUNK_KBYTES 0x3f -+#define EDID_MAX_FRL_RATE_MASK 0xf0 -+ -+static -+void parse_edid_forum_vsdb(struct rockchip_drm_dsc_cap *dsc_cap, -+ u8 *max_frl_rate_per_lane, u8 *max_lanes, -+ const u8 *hf_vsdb) -+{ -+ u8 max_frl_rate; -+ u8 dsc_max_frl_rate; -+ u8 dsc_max_slices; -+ -+ if (!hf_vsdb[7]) -+ return; -+ -+ DRM_DEBUG_KMS("hdmi_21 sink detected. parsing edid\n"); -+ max_frl_rate = (hf_vsdb[7] & EDID_MAX_FRL_RATE_MASK) >> 4; -+ get_max_frl_rate(max_frl_rate, max_lanes, -+ max_frl_rate_per_lane); -+ -+ if (cea_db_payload_len(hf_vsdb) < 13) -+ return; -+ -+ dsc_cap->v_1p2 = hf_vsdb[11] & EDID_DSC_1P2; -+ -+ if (!dsc_cap->v_1p2) -+ return; -+ -+ dsc_cap->native_420 = hf_vsdb[11] & EDID_DSC_NATIVE_420; -+ dsc_cap->all_bpp = hf_vsdb[11] & EDID_DSC_ALL_BPP; -+ -+ if (hf_vsdb[11] & EDID_DSC_16BPC) -+ dsc_cap->bpc_supported = 16; -+ else if (hf_vsdb[11] & EDID_DSC_12BPC) -+ dsc_cap->bpc_supported = 12; -+ else if (hf_vsdb[11] & EDID_DSC_10BPC) -+ dsc_cap->bpc_supported = 10; -+ else -+ dsc_cap->bpc_supported = 0; -+ -+ dsc_max_frl_rate = (hf_vsdb[12] & EDID_DSC_MAX_FRL_RATE_MASK) >> 4; -+ get_max_frl_rate(dsc_max_frl_rate, &dsc_cap->max_lanes, -+ &dsc_cap->max_frl_rate_per_lane); -+ dsc_cap->total_chunk_kbytes = hf_vsdb[13] & EDID_DSC_TOTAL_CHUNK_KBYTES; -+ -+ dsc_max_slices = hf_vsdb[12] & EDID_DSC_MAX_SLICES; -+ switch (dsc_max_slices) { -+ case 1: -+ dsc_cap->max_slices = 1; -+ dsc_cap->clk_per_slice = 340; -+ break; -+ case 2: -+ dsc_cap->max_slices = 2; -+ dsc_cap->clk_per_slice = 340; -+ break; -+ case 3: -+ dsc_cap->max_slices = 4; -+ dsc_cap->clk_per_slice = 340; -+ break; -+ case 4: -+ dsc_cap->max_slices = 8; -+ dsc_cap->clk_per_slice = 340; -+ break; -+ case 5: -+ dsc_cap->max_slices = 8; -+ dsc_cap->clk_per_slice = 400; -+ break; -+ case 6: -+ dsc_cap->max_slices = 12; -+ dsc_cap->clk_per_slice = 400; -+ break; -+ case 7: -+ dsc_cap->max_slices = 16; -+ dsc_cap->clk_per_slice = 400; -+ break; -+ case 0: -+ default: -+ dsc_cap->max_slices = 0; -+ dsc_cap->clk_per_slice = 0; -+ } -+} -+ -+enum { -+ VER_26_BYTE_V0, -+ VER_15_BYTE_V1, -+ VER_12_BYTE_V1, -+ VER_12_BYTE_V2, -+}; -+ -+static int check_next_hdr_version(const u8 *next_hdr_db) -+{ -+ u16 ver; -+ -+ ver = (next_hdr_db[5] & 0xf0) << 8 | next_hdr_db[0]; -+ -+ switch (ver) { -+ case 0x00f9: -+ return VER_26_BYTE_V0; -+ case 0x20ee: -+ return VER_15_BYTE_V1; -+ case 0x20eb: -+ return VER_12_BYTE_V1; -+ case 0x40eb: -+ return VER_12_BYTE_V2; -+ default: -+ return -ENOENT; -+ } -+} -+ -+static void parse_ver_26_v0_data(struct ver_26_v0 *hdr, const u8 *data) -+{ -+ hdr->yuv422_12bit = data[5] & BIT(0); -+ hdr->support_2160p_60 = (data[5] & BIT(1)) >> 1; -+ hdr->global_dimming = (data[5] & BIT(2)) >> 2; -+ -+ hdr->dm_major_ver = (data[21] & 0xf0) >> 4; -+ hdr->dm_minor_ver = data[21] & 0xf; -+ -+ hdr->t_min_pq = (data[19] << 4) | ((data[18] & 0xf0) >> 4); -+ hdr->t_max_pq = (data[20] << 4) | (data[18] & 0xf); -+ -+ hdr->rx = (data[7] << 4) | ((data[6] & 0xf0) >> 4); -+ hdr->ry = (data[8] << 4) | (data[6] & 0xf); -+ hdr->gx = (data[10] << 4) | ((data[9] & 0xf0) >> 4); -+ hdr->gy = (data[11] << 4) | (data[9] & 0xf); -+ hdr->bx = (data[13] << 4) | ((data[12] & 0xf0) >> 4); -+ hdr->by = (data[14] << 4) | (data[12] & 0xf); -+ hdr->wx = (data[16] << 4) | ((data[15] & 0xf0) >> 4); -+ hdr->wy = (data[17] << 4) | (data[15] & 0xf); -+} -+ -+static void parse_ver_15_v1_data(struct ver_15_v1 *hdr, const u8 *data) -+{ -+ hdr->yuv422_12bit = data[5] & BIT(0); -+ hdr->support_2160p_60 = (data[5] & BIT(1)) >> 1; -+ hdr->global_dimming = data[6] & BIT(0); -+ -+ hdr->dm_version = (data[5] & 0x1c) >> 2; -+ -+ hdr->colorimetry = data[7] & BIT(0); -+ -+ hdr->t_max_lum = (data[6] & 0xfe) >> 1; -+ hdr->t_min_lum = (data[7] & 0xfe) >> 1; -+ -+ hdr->rx = data[9]; -+ hdr->ry = data[10]; -+ hdr->gx = data[11]; -+ hdr->gy = data[12]; -+ hdr->bx = data[13]; -+ hdr->by = data[14]; -+} -+ -+static void parse_ver_12_v1_data(struct ver_12_v1 *hdr, const u8 *data) -+{ -+ hdr->yuv422_12bit = data[5] & BIT(0); -+ hdr->support_2160p_60 = (data[5] & BIT(1)) >> 1; -+ hdr->global_dimming = data[6] & BIT(0); -+ -+ hdr->dm_version = (data[5] & 0x1c) >> 2; -+ -+ hdr->colorimetry = data[7] & BIT(0); -+ -+ hdr->t_max_lum = (data[6] & 0xfe) >> 1; -+ hdr->t_min_lum = (data[7] & 0xfe) >> 1; -+ -+ hdr->low_latency = data[8] & 0x3; -+ -+ hdr->unique_rx = (data[11] & 0xf8) >> 3; -+ hdr->unique_ry = (data[11] & 0x7) << 2 | (data[10] & BIT(0)) << 1 | -+ (data[9] & BIT(0)); -+ hdr->unique_gx = (data[9] & 0xfe) >> 1; -+ hdr->unique_gy = (data[10] & 0xfe) >> 1; -+ hdr->unique_bx = (data[8] & 0xe0) >> 5; -+ hdr->unique_by = (data[8] & 0x1c) >> 2; -+} -+ -+static void parse_ver_12_v2_data(struct ver_12_v2 *hdr, const u8 *data) -+{ -+ hdr->yuv422_12bit = data[5] & BIT(0); -+ hdr->backlt_ctrl = (data[5] & BIT(1)) >> 1; -+ hdr->global_dimming = (data[6] & BIT(2)) >> 2; -+ -+ hdr->dm_version = (data[5] & 0x1c) >> 2; -+ hdr->backlt_min_luma = data[6] & 0x3; -+ hdr->interface = data[7] & 0x3; -+ hdr->yuv444_10b_12b = (data[8] & BIT(0)) << 1 | (data[9] & BIT(0)); -+ -+ hdr->t_min_pq_v2 = (data[6] & 0xf8) >> 3; -+ hdr->t_max_pq_v2 = (data[7] & 0xf8) >> 3; -+ -+ hdr->unique_rx = (data[10] & 0xf8) >> 3; -+ hdr->unique_ry = (data[11] & 0xf8) >> 3; -+ hdr->unique_gx = (data[8] & 0xfe) >> 1; -+ hdr->unique_gy = (data[9] & 0xfe) >> 1; -+ hdr->unique_bx = data[10] & 0x7; -+ hdr->unique_by = data[11] & 0x7; -+} -+ -+static -+void parse_next_hdr_block(struct next_hdr_sink_data *sink_data, -+ const u8 *next_hdr_db) -+{ -+ int version; -+ -+ version = check_next_hdr_version(next_hdr_db); -+ if (version < 0) -+ return; -+ -+ sink_data->version = version; -+ -+ switch (version) { -+ case VER_26_BYTE_V0: -+ parse_ver_26_v0_data(&sink_data->ver_26_v0, next_hdr_db); -+ break; -+ case VER_15_BYTE_V1: -+ parse_ver_15_v1_data(&sink_data->ver_15_v1, next_hdr_db); -+ break; -+ case VER_12_BYTE_V1: -+ parse_ver_12_v1_data(&sink_data->ver_12_v1, next_hdr_db); -+ break; -+ case VER_12_BYTE_V2: -+ parse_ver_12_v2_data(&sink_data->ver_12_v2, next_hdr_db); -+ break; -+ default: -+ break; -+ } -+} -+ -+int rockchip_drm_parse_cea_ext(struct rockchip_drm_dsc_cap *dsc_cap, -+ u8 *max_frl_rate_per_lane, u8 *max_lanes, -+ const struct edid *edid) -+{ -+ const u8 *edid_ext; -+ int i, start, end; -+ -+ if (!dsc_cap || !max_frl_rate_per_lane || !max_lanes || !edid) -+ return -EINVAL; -+ -+ edid_ext = find_cea_extension(edid); -+ if (!edid_ext) -+ return -EINVAL; -+ -+ if (cea_db_offsets(edid_ext, &start, &end)) -+ return -EINVAL; -+ -+ for_each_cea_db(edid_ext, i, start, end) { -+ const u8 *db = &edid_ext[i]; -+ -+ if (cea_db_is_hdmi_forum_vsdb(db)) -+ parse_edid_forum_vsdb(dsc_cap, max_frl_rate_per_lane, -+ max_lanes, db); -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(rockchip_drm_parse_cea_ext); -+ -+int rockchip_drm_parse_next_hdr(struct next_hdr_sink_data *sink_data, -+ const struct edid *edid) -+{ -+ const u8 *edid_ext; -+ int i, start, end; -+ -+ if (!sink_data || !edid) -+ return -EINVAL; -+ -+ memset(sink_data, 0, sizeof(struct next_hdr_sink_data)); -+ -+ edid_ext = find_cea_extension(edid); -+ if (!edid_ext) -+ return -EINVAL; -+ -+ if (cea_db_offsets(edid_ext, &start, &end)) -+ return -EINVAL; -+ -+ for_each_cea_db(edid_ext, i, start, end) { -+ const u8 *db = &edid_ext[i]; -+ -+ if (cea_db_is_hdmi_next_hdr_block(db)) -+ parse_next_hdr_block(sink_data, db); -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(rockchip_drm_parse_next_hdr); -+ - /* - * Attach a (component) device to the shared drm dma mapping from master drm - * device. This is used by the VOPs to map GEM buffers to a common DMA -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h -index aeb03a572..581496f04 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h -@@ -10,8 +10,11 @@ - #define _ROCKCHIP_DRM_DRV_H - - #include -+#include -+#include -+#include - #include -- -+#include - #include - #include - #include -@@ -19,25 +22,367 @@ - #define ROCKCHIP_MAX_FB_BUFFER 3 - #define ROCKCHIP_MAX_CONNECTOR 2 - #define ROCKCHIP_MAX_CRTC 4 -+#define ROCKCHIP_MAX_LAYER 16 - - struct drm_device; - struct drm_connector; - struct iommu_domain; - -+#define VOP_COLOR_KEY_NONE (0 << 31) -+#define VOP_COLOR_KEY_MASK (1 << 31) -+ -+#define VOP_OUTPUT_IF_RGB BIT(0) -+#define VOP_OUTPUT_IF_BT1120 BIT(1) -+#define VOP_OUTPUT_IF_BT656 BIT(2) -+#define VOP_OUTPUT_IF_LVDS0 BIT(3) -+#define VOP_OUTPUT_IF_LVDS1 BIT(4) -+#define VOP_OUTPUT_IF_MIPI0 BIT(5) -+#define VOP_OUTPUT_IF_MIPI1 BIT(6) -+#define VOP_OUTPUT_IF_eDP0 BIT(7) -+#define VOP_OUTPUT_IF_eDP1 BIT(8) -+#define VOP_OUTPUT_IF_DP0 BIT(9) -+#define VOP_OUTPUT_IF_DP1 BIT(10) -+#define VOP_OUTPUT_IF_HDMI0 BIT(11) -+#define VOP_OUTPUT_IF_HDMI1 BIT(12) -+ -+#ifndef DRM_FORMAT_NV20 -+#define DRM_FORMAT_NV20 fourcc_code('N', 'V', '2', '0') /* 2x1 subsampled Cr:Cb plane */ -+#endif -+ -+#ifndef DRM_FORMAT_NV30 -+#define DRM_FORMAT_NV30 fourcc_code('N', 'V', '3', '0') /* non-subsampled Cr:Cb plane */ -+#endif -+ -+#define RK_IF_PROP_COLOR_DEPTH "color_depth" -+#define RK_IF_PROP_COLOR_FORMAT "color_format" -+#define RK_IF_PROP_COLOR_DEPTH_CAPS "color_depth_caps" -+#define RK_IF_PROP_COLOR_FORMAT_CAPS "color_format_caps" -+ -+enum rk_if_color_depth { -+ RK_IF_DEPTH_8, -+ RK_IF_DEPTH_10, -+ RK_IF_DEPTH_12, -+ RK_IF_DEPTH_16, -+ RK_IF_DEPTH_420_10, -+ RK_IF_DEPTH_420_12, -+ RK_IF_DEPTH_420_16, -+ RK_IF_DEPTH_6, -+ RK_IF_DEPTH_MAX, -+}; -+ -+enum rk_if_color_format { -+ RK_IF_FORMAT_RGB, /* default RGB */ -+ RK_IF_FORMAT_YCBCR444, /* YCBCR 444 */ -+ RK_IF_FORMAT_YCBCR422, /* YCBCR 422 */ -+ RK_IF_FORMAT_YCBCR420, /* YCBCR 420 */ -+ RK_IF_FORMAT_YCBCR_HQ, /* Highest subsampled YUV */ -+ RK_IF_FORMAT_YCBCR_LQ, /* Lowest subsampled YUV */ -+ RK_IF_FORMAT_MAX, -+}; -+ -+struct rockchip_drm_sub_dev { -+ struct list_head list; -+ struct drm_connector *connector; -+ struct device_node *of_node; -+ void (*loader_protect)(struct drm_encoder *encoder, bool on); -+ void (*oob_hotplug_event)(struct drm_connector *connector); -+}; -+ -+struct rockchip_sdr2hdr_state { -+ int sdr2hdr_func; -+ -+ bool bt1886eotf_pre_conv_en; -+ bool rgb2rgb_pre_conv_en; -+ bool rgb2rgb_pre_conv_mode; -+ bool st2084oetf_pre_conv_en; -+ -+ bool bt1886eotf_post_conv_en; -+ bool rgb2rgb_post_conv_en; -+ bool rgb2rgb_post_conv_mode; -+ bool st2084oetf_post_conv_en; -+}; -+ -+struct rockchip_hdr_state { -+ bool pre_overlay; -+ bool hdr2sdr_en; -+ struct rockchip_sdr2hdr_state sdr2hdr_state; -+}; -+ -+struct rockchip_bcsh_state { -+ int brightness; -+ int contrast; -+ int saturation; -+ int sin_hue; -+ int cos_hue; -+}; -+ -+struct rockchip_crtc { -+ struct drm_crtc crtc; -+#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) -+ /** -+ * @vop_dump_status the status of vop dump control -+ * @vop_dump_list_head the list head of vop dump list -+ * @vop_dump_list_init_flag init once -+ * @vop_dump_times control the dump times -+ * @frme_count the frame of dump buf -+ */ -+ enum vop_dump_status vop_dump_status; -+ struct list_head vop_dump_list_head; -+ bool vop_dump_list_init_flag; -+ int vop_dump_times; -+ int frame_count; -+#endif -+}; -+ -+struct rockchip_dsc_sink_cap { -+ /** -+ * @slice_width: the number of pixel columns that comprise the slice width -+ * @slice_height: the number of pixel rows that comprise the slice height -+ * @block_pred: Does block prediction -+ * @native_420: Does sink support DSC with 4:2:0 compression -+ * @bpc_supported: compressed bpc supported by sink : 10, 12 or 16 bpc -+ * @version_major: DSC major version -+ * @version_minor: DSC minor version -+ * @target_bits_per_pixel_x16: bits num after compress and multiply 16 -+ */ -+ u16 slice_width; -+ u16 slice_height; -+ bool block_pred; -+ bool native_420; -+ u8 bpc_supported; -+ u8 version_major; -+ u8 version_minor; -+ u16 target_bits_per_pixel_x16; -+}; -+ - struct rockchip_crtc_state { - struct drm_crtc_state base; -+ int vp_id; - int output_type; - int output_mode; - int output_bpc; - int output_flags; - bool enable_afbc; -+ -+ //[CC:] vop2 related change -+ /** -+ * @splice_mode: enabled when display a hdisplay > 4096 on rk3588 -+ */ -+ bool splice_mode; -+ -+ /** -+ * @hold_mode: enabled when it's: -+ * (1) mcu hold mode -+ * (2) mipi dsi cmd mode -+ * (3) edp psr mode -+ */ -+ bool hold_mode; -+ -+ struct drm_tv_connector_state *tv_state; -+ int left_margin; -+ int right_margin; -+ int top_margin; -+ int bottom_margin; -+ int vdisplay; -+ int afbdc_win_format; -+ int afbdc_win_width; -+ int afbdc_win_height; -+ int afbdc_win_ptr; -+ int afbdc_win_id; -+ int afbdc_en; -+ int afbdc_win_vir_width; -+ int afbdc_win_xoffset; -+ int afbdc_win_yoffset; -+ int dsp_layer_sel; -+ u32 output_if; - u32 bus_format; - u32 bus_flags; -+ int yuv_overlay; -+ int post_r2y_en; -+ int post_y2r_en; -+ int post_csc_mode; -+ int bcsh_en; - int color_space; -+ int eotf; -+ u32 background; -+ u32 line_flag; -+ u8 mode_update; -+ u8 dsc_id; -+ -+ //[CC:] vop2 related changes -+ u8 dsc_enable; -+ unsigned long dsc_clk; -+ -+ u8 dsc_slice_num; -+ u8 dsc_pixel_num; -+ -+ u64 dsc_txp_clk_rate; -+ u64 dsc_pxl_clk_rate; -+ u64 dsc_cds_clk_rate; -+ -+ struct drm_dsc_picture_parameter_set pps; -+ struct rockchip_dsc_sink_cap dsc_sink_cap; -+ struct rockchip_hdr_state hdr; - }; -+ - #define to_rockchip_crtc_state(s) \ - container_of(s, struct rockchip_crtc_state, base) - -+struct rockchip_drm_vcnt { -+ struct drm_pending_vblank_event *event; -+ __u32 sequence; -+ int pipe; -+}; -+ -+struct rockchip_logo { -+ dma_addr_t dma_addr; -+ struct drm_mm_node logo_reserved_node; -+ void *kvaddr; -+ phys_addr_t start; -+ phys_addr_t size; -+ int count; -+}; -+ -+struct loader_cubic_lut { -+ bool enable; -+ u32 offset; -+}; -+ -+struct rockchip_drm_dsc_cap { -+ bool v_1p2; -+ bool native_420; -+ bool all_bpp; -+ u8 bpc_supported; -+ u8 max_slices; -+ u8 max_lanes; -+ u8 max_frl_rate_per_lane; -+ u8 total_chunk_kbytes; -+ int clk_per_slice; -+}; -+ -+struct ver_26_v0 { -+ u8 yuv422_12bit; -+ u8 support_2160p_60; -+ u8 global_dimming; -+ u8 dm_major_ver; -+ u8 dm_minor_ver; -+ u16 t_min_pq; -+ u16 t_max_pq; -+ u16 rx; -+ u16 ry; -+ u16 gx; -+ u16 gy; -+ u16 bx; -+ u16 by; -+ u16 wx; -+ u16 wy; -+} __packed; -+ -+struct ver_15_v1 { -+ u8 yuv422_12bit; -+ u8 support_2160p_60; -+ u8 global_dimming; -+ u8 dm_version; -+ u8 colorimetry; -+ u8 t_max_lum; -+ u8 t_min_lum; -+ u8 rx; -+ u8 ry; -+ u8 gx; -+ u8 gy; -+ u8 bx; -+ u8 by; -+} __packed; -+ -+struct ver_12_v1 { -+ u8 yuv422_12bit; -+ u8 support_2160p_60; -+ u8 global_dimming; -+ u8 dm_version; -+ u8 colorimetry; -+ u8 low_latency; -+ u8 t_max_lum; -+ u8 t_min_lum; -+ u8 unique_rx; -+ u8 unique_ry; -+ u8 unique_gx; -+ u8 unique_gy; -+ u8 unique_bx; -+ u8 unique_by; -+} __packed; -+ -+struct ver_12_v2 { -+ u8 yuv422_12bit; -+ u8 backlt_ctrl; -+ u8 global_dimming; -+ u8 dm_version; -+ u8 backlt_min_luma; -+ u8 interface; -+ u8 yuv444_10b_12b; -+ u8 t_min_pq_v2; -+ u8 t_max_pq_v2; -+ u8 unique_rx; -+ u8 unique_ry; -+ u8 unique_gx; -+ u8 unique_gy; -+ u8 unique_bx; -+ u8 unique_by; -+} __packed; -+ -+struct next_hdr_sink_data { -+ u8 version; -+ struct ver_26_v0 ver_26_v0; -+ struct ver_15_v1 ver_15_v1; -+ struct ver_12_v1 ver_12_v1; -+ struct ver_12_v2 ver_12_v2; -+} __packed; -+ -+//[CC:] drop struct dmcfreq_vop_info -+struct dmcfreq_vop_info; -+ -+/* -+ * Rockchip drm private crtc funcs. -+ * @loader_protect: protect loader logo crtc's power -+ * @enable_vblank: enable crtc vblank irq. -+ * @disable_vblank: disable crtc vblank irq. -+ * @bandwidth: report present crtc bandwidth consume. -+ * @cancel_pending_vblank: cancel pending vblank. -+ * @debugfs_init: init crtc debugfs. -+ * @debugfs_dump: debugfs to dump crtc and plane state. -+ * @regs_dump: dump vop current register config. -+ * @mode_valid: verify that the current mode is supported. -+ * @crtc_close: close vop. -+ * @crtc_send_mcu_cmd: send mcu panel init cmd. -+ * @te_handler: soft te hand for cmd mode panel. -+ * @wait_vact_end: wait the last active line. -+ */ -+struct rockchip_crtc_funcs { -+ int (*loader_protect)(struct drm_crtc *crtc, bool on); -+ int (*enable_vblank)(struct drm_crtc *crtc); -+ void (*disable_vblank)(struct drm_crtc *crtc); -+ size_t (*bandwidth)(struct drm_crtc *crtc, -+ struct drm_crtc_state *crtc_state, -+ struct dmcfreq_vop_info *vop_bw_info); -+ void (*cancel_pending_vblank)(struct drm_crtc *crtc, -+ struct drm_file *file_priv); -+ int (*debugfs_init)(struct drm_minor *minor, struct drm_crtc *crtc); -+ int (*debugfs_dump)(struct drm_crtc *crtc, struct seq_file *s); -+ void (*regs_dump)(struct drm_crtc *crtc, struct seq_file *s); -+ enum drm_mode_status (*mode_valid)(struct drm_crtc *crtc, -+ const struct drm_display_mode *mode, -+ int output_type); -+ void (*crtc_close)(struct drm_crtc *crtc); -+ void (*crtc_send_mcu_cmd)(struct drm_crtc *crtc, u32 type, u32 value); -+ void (*te_handler)(struct drm_crtc *crtc); -+ int (*wait_vact_end)(struct drm_crtc *crtc, unsigned int mstimeout); -+ void (*crtc_standby)(struct drm_crtc *crtc, bool standby); -+}; -+ -+struct rockchip_dclk_pll { -+ struct clk *pll; -+ unsigned int use_count; -+}; -+ - /* - * Rockchip drm private structure. - * -@@ -46,10 +391,56 @@ struct rockchip_crtc_state { - * @mm_lock: protect drm_mm on multi-threads. - */ - struct rockchip_drm_private { -+ struct rockchip_logo *logo; -+ struct drm_fb_helper *fbdev_helper; -+ struct drm_gem_object *fbdev_bo; - struct iommu_domain *domain; -+ struct gen_pool *secure_buffer_pool; - struct device *iommu_dev; - struct mutex mm_lock; - struct drm_mm mm; -+ struct list_head psr_list; -+ struct mutex psr_list_lock; -+ struct mutex commit_lock; -+ -+ /* private crtc prop */ -+ struct drm_property *soc_id_prop; -+ struct drm_property *port_id_prop; -+ struct drm_property *aclk_prop; -+ struct drm_property *bg_prop; -+ struct drm_property *line_flag_prop; -+ -+ /* private plane prop */ -+ struct drm_property *eotf_prop; -+ struct drm_property *color_space_prop; -+ struct drm_property *async_commit_prop; -+ struct drm_property *share_id_prop; -+ -+ /* private connector prop */ -+ struct drm_property *connector_id_prop; -+ -+ const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC]; -+ -+ struct rockchip_dclk_pll default_pll; -+ struct rockchip_dclk_pll hdmi_pll; -+ -+ /* -+ * protect some shared overlay resource -+ * OVL_LAYER_SEL/OVL_PORT_SEL -+ */ -+ struct mutex ovl_lock; -+ -+ struct rockchip_drm_vcnt vcnt[ROCKCHIP_MAX_CRTC]; -+ /** -+ * @loader_protect -+ * ignore restore_fbdev_mode_atomic when in logo on state -+ */ -+ bool loader_protect; -+ -+ dma_addr_t cubic_lut_dma_addr; -+ void *cubic_lut_kvaddr; -+ struct drm_mm_node *clut_reserved_node; -+ struct loader_cubic_lut cubic_lut[ROCKCHIP_MAX_CRTC]; - }; - - struct rockchip_encoder { -@@ -66,16 +457,52 @@ void rockchip_drm_dma_init_device(struct drm_device *drm_dev, - int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout); - int rockchip_drm_encoder_set_crtc_endpoint_id(struct rockchip_encoder *rencoder, - struct device_node *np, int port, int reg); -+ -+int rockchip_register_crtc_funcs(struct drm_crtc *crtc, -+ const struct rockchip_crtc_funcs *crtc_funcs); -+void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc); -+void rockchip_drm_crtc_standby(struct drm_crtc *crtc, bool standby); -+ -+void rockchip_drm_register_sub_dev(struct rockchip_drm_sub_dev *sub_dev); -+void rockchip_drm_unregister_sub_dev(struct rockchip_drm_sub_dev *sub_dev); -+struct rockchip_drm_sub_dev *rockchip_drm_get_sub_dev(struct device_node *node); -+int rockchip_drm_add_modes_noedid(struct drm_connector *connector); -+void rockchip_drm_te_handle(struct drm_crtc *crtc); -+void drm_mode_convert_to_split_mode(struct drm_display_mode *mode); -+void drm_mode_convert_to_origin_mode(struct drm_display_mode *mode); -+#if IS_REACHABLE(CONFIG_DRM_ROCKCHIP) -+int rockchip_drm_get_sub_dev_type(void); -+#else -+static inline int rockchip_drm_get_sub_dev_type(void) -+{ -+ return DRM_MODE_CONNECTOR_Unknown; -+} -+#endif -+ - int rockchip_drm_endpoint_is_subdriver(struct device_node *ep); -+uint32_t rockchip_drm_get_bpp(const struct drm_format_info *info); -+int rockchip_drm_get_yuv422_format(struct drm_connector *connector, -+ struct edid *edid); -+int rockchip_drm_parse_cea_ext(struct rockchip_drm_dsc_cap *dsc_cap, -+ u8 *max_frl_rate_per_lane, u8 *max_lanes, -+ const struct edid *edid); -+int rockchip_drm_parse_next_hdr(struct next_hdr_sink_data *sink_data, -+ const struct edid *edid); -+ - extern struct platform_driver cdn_dp_driver; - extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; - extern struct platform_driver dw_mipi_dsi_rockchip_driver; -+extern struct platform_driver dw_mipi_dsi2_rockchip_driver; - extern struct platform_driver inno_hdmi_driver; - extern struct platform_driver rockchip_dp_driver; - extern struct platform_driver rockchip_lvds_driver; - extern struct platform_driver vop_platform_driver; --extern struct platform_driver rk3066_hdmi_driver; - extern struct platform_driver vop2_platform_driver; -+extern struct platform_driver rk3066_hdmi_driver; -+extern struct platform_driver rockchip_rgb_driver; -+extern struct platform_driver dw_dp_driver; -+extern struct platform_driver vconn_platform_driver; -+extern struct platform_driver vvop_platform_driver; - - static inline struct rockchip_encoder *to_rockchip_encoder(struct drm_encoder *encoder) - { -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h -index 4b2daefeb..6ebea5c36 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h -@@ -15,6 +15,16 @@ - #define VOP_MAJOR(version) ((version) >> 8) - #define VOP_MINOR(version) ((version) & 0xff) - -+//[CC:] vop2 related changes -+#define VOP_VERSION_RK3568 VOP_VERSION(0x40, 0x15) -+#define VOP_VERSION_RK3588 VOP_VERSION(0x40, 0x17) -+ -+#define ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE BIT(0) -+#define ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE BIT(1) -+#define ROCKCHIP_OUTPUT_DATA_SWAP BIT(2) -+/* MIPI DSI DataStream(cmd) mode on rk3588 */ -+#define ROCKCHIP_OUTPUT_MIPI_DS_MODE BIT(3) -+ - #define NUM_YUV2YUV_COEFFICIENTS 12 - - /* AFBC supports a number of configurable modes. Relevant to us is block size -@@ -280,11 +290,16 @@ struct vop_data { - /* - * display output interface supported by rockchip lcdc - */ --#define ROCKCHIP_OUT_MODE_P888 0 --#define ROCKCHIP_OUT_MODE_P666 1 --#define ROCKCHIP_OUT_MODE_P565 2 -+#define ROCKCHIP_OUT_MODE_P888 0 -+#define ROCKCHIP_OUT_MODE_BT1120 0 -+#define ROCKCHIP_OUT_MODE_P666 1 -+#define ROCKCHIP_OUT_MODE_P565 2 -+#define ROCKCHIP_OUT_MODE_BT656 5 -+#define ROCKCHIP_OUT_MODE_S888 8 -+#define ROCKCHIP_OUT_MODE_S888_DUMMY 12 -+#define ROCKCHIP_OUT_MODE_YUV420 14 - /* for use special outface */ --#define ROCKCHIP_OUT_MODE_AAAA 15 -+#define ROCKCHIP_OUT_MODE_AAAA 15 - - /* output flags */ - #define ROCKCHIP_OUTPUT_DSI_DUAL BIT(0) -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -index 6862fb146..a073d1d5c 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 -@@ -17,6 +19,7 @@ - #include - #include - #include -+#include - #include - - #include -@@ -159,6 +162,8 @@ struct vop2_video_port { - struct drm_crtc crtc; - struct vop2 *vop2; - struct clk *dclk; -+ struct reset_control *dclk_rst; -+ struct clk *dclk_parent; - unsigned int id; - const struct vop2_video_port_data *data; - -@@ -191,6 +196,8 @@ struct vop2 { - struct regmap *map; - - struct regmap *grf; -+ struct regmap *vop_grf; -+ struct regmap *vo1_grf; - - /* physical map length of vop2 register */ - u32 len; -@@ -209,14 +216,43 @@ struct vop2 { - unsigned int enable_count; - struct clk *hclk; - struct clk *aclk; -+ struct clk *pclk; -+ // [CC:] handle all display modes -+ struct clk *hdmi0_phy_pll; -+ struct reset_control *ahb_rst; -+ struct reset_control *axi_rst; - - /* optional internal rgb encoder */ - struct rockchip_rgb *rgb; - -+ /* list_head of internal clk */ -+ struct list_head clk_list_head; -+ - /* must be put at the end of the struct */ - 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) -+#define vop2_output_if_is_dp(x) (x == ROCKCHIP_VOP2_EP_DP0 || x == ROCKCHIP_VOP2_EP_DP1) -+#define vop2_output_if_is_edp(x) (x == ROCKCHIP_VOP2_EP_EDP0 || x == ROCKCHIP_VOP2_EP_EDP1) -+#define vop2_output_if_is_mipi(x) (x == ROCKCHIP_VOP2_EP_MIPI0 || x == ROCKCHIP_VOP2_EP_MIPI1) -+#define vop2_output_if_is_lvds(x) (x == ROCKCHIP_VOP2_EP_LVDS0 || x == ROCKCHIP_VOP2_EP_LVDS1) -+#define vop2_output_if_is_dpi(x) (x == ROCKCHIP_VOP2_EP_RGB0) -+ - static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc) - { - return container_of(crtc, struct vop2_video_port, crtc); -@@ -269,9 +305,16 @@ static bool vop2_cluster_window(const struct vop2_win *win) - static void vop2_cfg_done(struct vop2_video_port *vp) - { - struct vop2 *vop2 = vp->vop2; -+ unsigned int bits = BIT(vp->id) | RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN; - -- regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, -- BIT(vp->id) | RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN); -+ if (vop2->data->soc_id == 3588) { -+ bits |= BIT(vp->id) << 16; -+ // [CC:] handle splice_mode -+ // if (vcstate->splice_mode) -+ // bits |= BIT(vp_data->splice_vp_id) | (BIT(vp_data->splice_vp_id) << 16); -+ } -+ -+ regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, bits); - } - - static void vop2_win_disable(struct vop2_win *win) -@@ -846,16 +889,36 @@ static int vop2_core_clks_prepare_enable(struct vop2 *vop2) - ret = clk_prepare_enable(vop2->aclk); - if (ret < 0) { - drm_err(vop2->drm, "failed to enable aclk - %d\n", ret); -- goto err; -+ goto err_aclk; -+ } -+ -+ ret = clk_prepare_enable(vop2->pclk); -+ if (ret < 0) { -+ drm_err(vop2->drm, "failed to enable pclk - %d\n", ret); -+ goto err_pclk; - } - - return 0; --err: -+ -+err_pclk: -+ clk_disable_unprepare(vop2->aclk); -+err_aclk: - clk_disable_unprepare(vop2->hclk); - - return ret; - } - -+static void vop2_power_domain_all_on(struct vop2 *vop2) -+{ -+ u32 pd; -+ -+ pd = vop2_readl(vop2, RK3588_SYS_PD_CTRL); -+ pd |= VOP2_PD_CLUSTER0 | VOP2_PD_CLUSTER1 | VOP2_PD_CLUSTER2 | -+ VOP2_PD_CLUSTER3 | VOP2_PD_ESMART; -+ -+ vop2_writel(vop2, RK3588_SYS_PD_CTRL, pd); -+} -+ - static void vop2_enable(struct vop2 *vop2) - { - int ret; -@@ -883,6 +946,9 @@ static void vop2_enable(struct vop2 *vop2) - if (vop2->data->soc_id == 3566) - vop2_writel(vop2, RK3568_OTP_WIN_EN, 1); - -+ if (vop2->data->soc_id == 3588) -+ vop2_power_domain_all_on(vop2); -+ - vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN); - - /* -@@ -910,63 +976,11 @@ static void vop2_disable(struct vop2 *vop2) - - regcache_mark_dirty(vop2->map); - -+ clk_disable_unprepare(vop2->pclk); - clk_disable_unprepare(vop2->aclk); - clk_disable_unprepare(vop2->hclk); - } - --static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, -- struct drm_atomic_state *state) --{ -- struct vop2_video_port *vp = to_vop2_video_port(crtc); -- struct vop2 *vop2 = vp->vop2; -- struct drm_crtc_state *old_crtc_state; -- int ret; -- -- vop2_lock(vop2); -- -- old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); -- drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false); -- -- drm_crtc_vblank_off(crtc); -- -- /* -- * Vop standby will take effect at end of current frame, -- * if dsp hold valid irq happen, it means standby complete. -- * -- * we must wait standby complete when we want to disable aclk, -- * if not, memory bus maybe dead. -- */ -- reinit_completion(&vp->dsp_hold_completion); -- -- vop2_crtc_enable_irq(vp, VP_INT_DSP_HOLD_VALID); -- -- vop2_vp_write(vp, RK3568_VP_DSP_CTRL, RK3568_VP_DSP_CTRL__STANDBY); -- -- ret = wait_for_completion_timeout(&vp->dsp_hold_completion, -- msecs_to_jiffies(50)); -- if (!ret) -- drm_info(vop2->drm, "wait for vp%d dsp_hold timeout\n", vp->id); -- -- vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID); -- -- clk_disable_unprepare(vp->dclk); -- -- vop2->enable_count--; -- -- if (!vop2->enable_count) -- vop2_disable(vop2); -- -- vop2_unlock(vop2); -- -- if (crtc->state->event && !crtc->state->active) { -- spin_lock_irq(&crtc->dev->event_lock); -- drm_crtc_send_vblank_event(crtc, crtc->state->event); -- spin_unlock_irq(&crtc->dev->event_lock); -- -- crtc->state->event = NULL; -- } --} -- - static int vop2_plane_atomic_check(struct drm_plane *plane, - struct drm_atomic_state *astate) - { -@@ -1004,6 +1018,7 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, - if (!pstate->visible) - return 0; - -+ // [CC:] Drop format var since it's not used anywhere, use ret var instead - format = vop2_convert_format(fb->format->format); - if (format < 0) - return format; -@@ -1027,6 +1042,35 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, - return -EINVAL; - } - -+ // [CC:] do we need the checks below? -+ bool afbc_en = rockchip_afbc(plane, fb->modifier); -+ struct vop2_win *win = to_vop2_win(plane); -+ -+ /* -+ * This is special feature at rk356x, the cluster layer only can support -+ * afbc format and can't support linear format; -+ */ -+ if (vp->vop2->data->soc_id == 3568) { -+ if (vop2_cluster_window(win) && !afbc_en) { -+ DRM_ERROR("Unsupported linear format at %s\n", win->data->name); -+ return -EINVAL; -+ } -+ } -+ -+ if (vp->vop2->data->soc_id > 3568) { -+ if (vop2_cluster_window(win) && !afbc_en && fb->format->is_yuv) { -+ DRM_ERROR("Unsupported linear yuv format at %s\n", win->data->name); -+ return -EINVAL; -+ } -+ -+ if (vop2_cluster_window(win) && !afbc_en && -+ (win->data->supported_rotations & pstate->rotation)) { -+ DRM_ERROR("Unsupported linear rotation(%d) format at %s\n", -+ pstate->rotation, win->data->name); -+ return -EINVAL; -+ } -+ } -+ - /* - * Src.x1 can be odd when do clip, but yuv plane start point - * need align with 2 pixel. -@@ -1107,6 +1151,7 @@ static void vop2_plane_setup_color_key(struct drm_plane *plane, u32 color_key) - vop2_win_write(win, VOP2_WIN_COLOR_KEY, (r << 20) | (g << 10) | b); - } - -+// [CC:] fix BUG: sleeping function called from invalid context - static void vop2_plane_atomic_update(struct drm_plane *plane, - struct drm_atomic_state *state) - { -@@ -1272,7 +1317,12 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, - vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 1); - vop2_win_write(win, VOP2_WIN_AFBC_FORMAT, afbc_format); - vop2_win_write(win, VOP2_WIN_AFBC_UV_SWAP, uv_swap); -- vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0); -+ -+ if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568) -+ vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0); -+ else -+ vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 1); -+ - vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0); - if (pstate->rotation & (DRM_MODE_ROTATE_270 | DRM_MODE_ROTATE_90)) { - vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, 0); -@@ -1376,9 +1426,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; - } - -@@ -1462,7 +1533,7 @@ static void vop2_post_config(struct drm_crtc *crtc) - } - - static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id, -- u32 polflags) -+ u32 polflags, u32 invpolflags) - { - struct vop2 *vop2 = vp->vop2; - u32 die, dip; -@@ -1477,6 +1548,7 @@ static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id, - FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_RGB_MUX, vp->id); - dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL; - dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags); -+ // [CC:] use .grf_dclk_inv = VOP_REG(RK3588_GRF_SOC_CON1, 0x1, 14) for 3588 variant - if (polflags & POLFLAG_DCLK_INV) - regmap_write(vop2->grf, RK3568_GRF_VO_CON1, BIT(3 + 16) | BIT(3)); - else -@@ -1487,8 +1559,18 @@ static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id, - die |= RK3568_SYS_DSP_INFACE_EN_HDMI | - FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_HDMI_MUX, vp->id); - dip &= ~RK3568_DSP_IF_POL__HDMI_PIN_POL; -- dip |= FIELD_PREP(RK3568_DSP_IF_POL__HDMI_PIN_POL, polflags); -+ dip |= FIELD_PREP(RK3568_DSP_IF_POL__HDMI_PIN_POL, invpolflags); -+ -+ /* grf_hdmi0_en */ -+ if (vop2->vop_grf) -+ regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, BIT(1 + 16) | BIT(1)); -+ /* hdmi0_pin_pol */ -+ if (vop2->vo1_grf) -+ regmap_write(vop2->vo1_grf, RK3588_GRF_VO1_CON0, -+ RK3588_GRF_VO1_CON0__HDMI0_PIN_POL << 16 | -+ FIELD_PREP(RK3588_GRF_VO1_CON0__HDMI0_PIN_POL, invpolflags)); - break; -+ // [CC:] TODO: ROCKCHIP_VOP2_EP_HDMI1 - case ROCKCHIP_VOP2_EP_EDP0: - die &= ~RK3568_SYS_DSP_INFACE_EN_EDP_MUX; - die |= RK3568_SYS_DSP_INFACE_EN_EDP | -@@ -1535,11 +1617,354 @@ static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id, - vop2_writel(vop2, RK3568_DSP_IF_POL, dip); - } - -+/* -+ * calc the dclk on rk3588 -+ * the available div of dclk is 1, 2, 4 -+ */ -+static unsigned long vop2_calc_dclk(unsigned long child_clk, unsigned long max_dclk) -+{ -+ if (child_clk * 4 <= max_dclk) -+ return child_clk * 4; -+ else if (child_clk * 2 <= max_dclk) -+ return child_clk * 2; -+ else if (child_clk <= max_dclk) -+ return child_clk; -+ else -+ 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 -+ * DP: dp_pixclk = dclk_out <= dclk_core -+ * DSI: mipi_pixclk <= dclk_out <= dclk_core -+ */ -+static unsigned long vop2_calc_cru_cfg(struct vop2_video_port *vp, int id, -+ int *dclk_core_div, int *dclk_out_div, -+ int *if_pixclk_div, int *if_dclk_div) -+{ -+ struct vop2 *vop2 = vp->vop2; -+ struct drm_crtc *crtc = &vp->crtc; -+ struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; -+ struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); -+ int output_mode = vcstate->output_mode; -+ unsigned long v_pixclk = adjusted_mode->crtc_clock * 1000LL; /* video timing pixclk */ -+ unsigned long dclk_core_rate = v_pixclk >> 2; -+ unsigned long dclk_rate = v_pixclk; -+ unsigned long dclk_out_rate; -+ unsigned long if_dclk_rate; -+ unsigned long if_pixclk_rate; -+ int K = 1; -+ -+ if (vop2_output_if_is_hdmi(id)) { -+ if (vop2->data->soc_id == 3588 && id == ROCKCHIP_VOP2_EP_HDMI0) { -+ 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 -+ */ -+ if (output_mode == ROCKCHIP_OUT_MODE_YUV420) { -+ dclk_rate = dclk_rate >> 1; -+ K = 2; -+ } -+ -+ if_pixclk_rate = (dclk_core_rate << 1) / K; -+ if_dclk_rate = dclk_core_rate / K; -+ -+ *if_pixclk_div = dclk_rate / if_pixclk_rate; -+ *if_dclk_div = dclk_rate / if_dclk_rate; -+ *dclk_core_div = dclk_rate / dclk_core_rate; -+ } else if (vop2_output_if_is_edp(id)) { -+ /* edp_pixclk = edp_dclk > dclk_core */ -+ if_pixclk_rate = v_pixclk / K; -+ if_dclk_rate = v_pixclk / K; -+ dclk_rate = if_pixclk_rate * K; -+ *dclk_core_div = dclk_rate / dclk_core_rate; -+ *if_pixclk_div = dclk_rate / if_pixclk_rate; -+ *if_dclk_div = *if_pixclk_div; -+ } else if (vop2_output_if_is_dp(id)) { -+ if (output_mode == ROCKCHIP_OUT_MODE_YUV420) -+ dclk_out_rate = v_pixclk >> 3; -+ else -+ dclk_out_rate = v_pixclk >> 2; -+ -+ dclk_rate = vop2_calc_dclk(dclk_out_rate, 600000); -+ if (!dclk_rate) { -+ drm_err(vop2->drm, "DP dclk_out_rate out of range(max_dclk: 600 KHZ, dclk_out_rate: %ld KHZ)\n", -+ dclk_out_rate); -+ return -EINVAL; -+ } -+ *dclk_out_div = dclk_rate / dclk_out_rate; -+ *dclk_core_div = dclk_rate / dclk_core_rate; -+ } else if (vop2_output_if_is_mipi(id)) { -+ if_pixclk_rate = dclk_core_rate / K; -+ /* dclk_core = dclk_out * K = if_pixclk * K = v_pixclk / 4 */ -+ dclk_out_rate = if_pixclk_rate; -+ /* dclk_rate = N * dclk_core_rate N = (1,2,4 ), we get a little factor here */ -+ dclk_rate = vop2_calc_dclk(dclk_out_rate, 600000); -+ if (!dclk_rate) { -+ drm_err(vop2->drm, "MIPI dclk out of range(max_dclk: 600 KHZ, dclk_out_rate: %ld KHZ)\n", -+ dclk_out_rate); -+ return -EINVAL; -+ } -+ *dclk_out_div = dclk_rate / dclk_out_rate; -+ *dclk_core_div = dclk_rate / dclk_core_rate; -+ *if_pixclk_div = 1; /*mipi pixclk == dclk_out*/ -+ } else if (vop2_output_if_is_dpi(id)) { -+ dclk_rate = v_pixclk; -+ *dclk_core_div = dclk_rate / dclk_core_rate; -+ } -+ -+ *if_pixclk_div = ilog2(*if_pixclk_div); -+ *if_dclk_div = ilog2(*if_dclk_div); -+ *dclk_core_div = ilog2(*dclk_core_div); -+ *dclk_out_div = ilog2(*dclk_out_div); -+ -+ drm_dbg(vop2->drm, "dclk:%ld,if_pixclk_div;%d,if_dclk_div:%d\n", dclk_rate, *if_pixclk_div, *if_dclk_div); -+ -+ return dclk_rate; -+} -+ -+/* -+ * MIPI port mux on rk3588: -+ * 0: Video Port2 -+ * 1: Video Port3 -+ * 3: Video Port 1(MIPI1 only) -+ */ -+static u32 rk3588_get_mipi_port_mux(int vp_id) -+{ -+ if (vp_id == 1) -+ return 3; -+ else if (vp_id == 3) -+ return 1; -+ else -+ return 0; -+} -+ -+static u32 rk3588_get_hdmi_pol(u32 flags) -+{ -+ u32 val; -+ -+ val = (flags & DRM_MODE_FLAG_NHSYNC) ? BIT(HSYNC_POSITIVE) : 0; -+ val |= (flags & DRM_MODE_FLAG_NVSYNC) ? BIT(VSYNC_POSITIVE) : 0; -+ -+ return val; -+} -+ -+static void rk3588_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags) -+{ -+ struct vop2 *vop2 = vp->vop2; -+ int dclk_core_div, dclk_out_div, if_pixclk_div, if_dclk_div; -+ u32 die, dip, div, vp_clk_div, val; -+ -+ vop2_calc_cru_cfg(vp, id, &dclk_core_div, &dclk_out_div, &if_pixclk_div, &if_dclk_div); -+ -+ vp_clk_div = FIELD_PREP(RK3588_VP_CLK_CTRL__DCLK_CORE_DIV, dclk_core_div); -+ vp_clk_div |= FIELD_PREP(RK3588_VP_CLK_CTRL__DCLK_OUT_DIV, dclk_out_div); -+ -+ die = vop2_readl(vop2, RK3568_DSP_IF_EN); -+ dip = vop2_readl(vop2, RK3568_DSP_IF_POL); -+ div = vop2_readl(vop2, RK3568_DSP_IF_CTRL); -+ -+ switch (id) { -+ case ROCKCHIP_VOP2_EP_HDMI0: -+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV, if_dclk_div); -+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV, if_pixclk_div); -+ die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX; -+ die |= RK3588_SYS_DSP_INFACE_EN_HDMI0 | -+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX, vp->id); -+ val = rk3588_get_hdmi_pol(polflags); -+ regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 1, 1)); -+ regmap_write(vop2->vo1_grf, RK3588_GRF_VO1_CON0, HIWORD_UPDATE(val, 6, 5)); -+ break; -+ case ROCKCHIP_VOP2_EP_HDMI1: -+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV, if_dclk_div); -+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV, if_pixclk_div); -+ die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX; -+ die |= RK3588_SYS_DSP_INFACE_EN_HDMI1 | -+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX, vp->id); -+ val = rk3588_get_hdmi_pol(polflags); -+ regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 4, 4)); -+ regmap_write(vop2->vo1_grf, RK3588_GRF_VO1_CON0, HIWORD_UPDATE(val, 8, 7)); -+ break; -+ case ROCKCHIP_VOP2_EP_EDP0: -+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV, if_dclk_div); -+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV, if_pixclk_div); -+ die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX; -+ die |= RK3588_SYS_DSP_INFACE_EN_EDP0 | -+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX, vp->id); -+ regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 0, 0)); -+ break; -+ case ROCKCHIP_VOP2_EP_EDP1: -+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV, if_dclk_div); -+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV, if_pixclk_div); -+ die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX; -+ die |= RK3588_SYS_DSP_INFACE_EN_EDP1 | -+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX, vp->id); -+ regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 3, 3)); -+ break; -+ case ROCKCHIP_VOP2_EP_MIPI0: -+ div |= FIELD_PREP(RK3588_DSP_IF_MIPI0_PCLK_DIV, if_pixclk_div); -+ die &= ~RK3588_SYS_DSP_INFACE_EN_MIPI0_MUX; -+ val = rk3588_get_mipi_port_mux(vp->id); -+ die |= RK3588_SYS_DSP_INFACE_EN_MIPI0 | -+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_MIPI0_MUX, !!val); -+ break; -+ case ROCKCHIP_VOP2_EP_MIPI1: -+ div |= FIELD_PREP(RK3588_DSP_IF_MIPI1_PCLK_DIV, if_pixclk_div); -+ die &= ~RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX; -+ val = rk3588_get_mipi_port_mux(vp->id); -+ die |= RK3588_SYS_DSP_INFACE_EN_MIPI1 | -+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX, val); -+ break; -+ case ROCKCHIP_VOP2_EP_DP0: -+ die &= ~RK3588_SYS_DSP_INFACE_EN_DP0_MUX; -+ die |= RK3588_SYS_DSP_INFACE_EN_DP0 | -+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_DP0_MUX, vp->id); -+ dip &= ~RK3588_DSP_IF_POL__DP0_PIN_POL; -+ dip |= FIELD_PREP(RK3588_DSP_IF_POL__DP0_PIN_POL, polflags); -+ break; -+ case ROCKCHIP_VOP2_EP_DP1: -+ die &= ~RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX; -+ die |= RK3588_SYS_DSP_INFACE_EN_MIPI1 | -+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX, vp->id); -+ dip &= ~RK3588_DSP_IF_POL__DP1_PIN_POL; -+ dip |= FIELD_PREP(RK3588_DSP_IF_POL__DP1_PIN_POL, polflags); -+ break; -+ default: -+ drm_err(vop2->drm, "Invalid interface id %d on vp%d\n", id, vp->id); -+ return; -+ } -+ -+ dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD; -+ -+ vop2_vp_write(vp, RK3588_VP_CLK_CTRL, vp_clk_div); -+ vop2_writel(vop2, RK3568_DSP_IF_EN, die); -+ vop2_writel(vop2, RK3568_DSP_IF_CTRL, div); -+ vop2_writel(vop2, RK3568_DSP_IF_POL, dip); -+} -+ -+static void vop2_set_intf_mux(struct vop2_video_port *vp, int ep_id, u32 polflags) -+{ -+ struct vop2 *vop2 = vp->vop2; -+ -+ if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568) { -+ // [CC:] drop 2nd polflags arg -+ rk3568_set_intf_mux(vp, ep_id, polflags, polflags); -+ } else if(vop2->data->soc_id == 3588) { -+ rk3588_set_intf_mux(vp, ep_id, polflags); -+ } -+} -+ - 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) - { -@@ -1564,9 +1989,11 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - u8 out_mode; - u32 dsp_ctrl = 0; - int act_end; -- u32 val, polflags; -+ u32 val, polflags, invpolflags; - 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", -@@ -1597,10 +2024,20 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - if (mode->flags & DRM_MODE_FLAG_PVSYNC) - polflags |= BIT(VSYNC_POSITIVE); - -+ /* RK3588 uses inverted HDMI V/HSYNC polarity */ -+ if (vop2->data->soc_id == 3588) { -+ invpolflags = 0; -+ if (mode->flags & DRM_MODE_FLAG_NHSYNC) -+ invpolflags |= BIT(HSYNC_POSITIVE); -+ if (mode->flags & DRM_MODE_FLAG_NVSYNC) -+ invpolflags |= BIT(VSYNC_POSITIVE); -+ } else { -+ invpolflags = polflags; -+ } -+ - drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { - struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); -- -- rk3568_set_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags); -+ vop2_set_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags); - } - - if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA && -@@ -1651,13 +2088,44 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - - vop2_vp_write(vp, RK3568_VP_DSP_VTOTAL_VS_END, vtotal << 16 | vsync_len); - -- if (mode->flags & DRM_MODE_FLAG_DBLCLK) { -- dsp_ctrl |= RK3568_VP_DSP_CTRL__CORE_DCLK_DIV; -- clock *= 2; -+ if (vop2->data->soc_id == 3568) { -+ if (mode->flags & DRM_MODE_FLAG_DBLCLK) { -+ dsp_ctrl |= RK3568_VP_DSP_CTRL__CORE_DCLK_DIV; -+ // [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, vp->dclk_parent); -+ else -+ 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); -@@ -1668,9 +2136,71 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - - drm_crtc_vblank_on(crtc); - -+ // [CC:] needed? -+ ret = reset_control_assert(vp->dclk_rst); -+ if (ret < 0) -+ drm_warn(vop2->drm, "failed to assert reset: %d\n", ret); -+ udelay(10); -+ ret = reset_control_deassert(vp->dclk_rst); -+ if (ret < 0) -+ drm_warn(vop2->drm, "failed to deassert reset: %d\n", ret); -+ - vop2_unlock(vop2); - } - -+static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, -+ struct drm_atomic_state *state) -+{ -+ struct vop2_video_port *vp = to_vop2_video_port(crtc); -+ struct vop2 *vop2 = vp->vop2; -+ struct drm_crtc_state *old_crtc_state; -+ int ret; -+ -+ vop2_lock(vop2); -+ -+ old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); -+ drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false); -+ -+ drm_crtc_vblank_off(crtc); -+ -+ /* -+ * Vop standby will take effect at end of current frame, -+ * if dsp hold valid irq happen, it means standby complete. -+ * -+ * we must wait standby complete when we want to disable aclk, -+ * if not, memory bus maybe dead. -+ */ -+ reinit_completion(&vp->dsp_hold_completion); -+ -+ vop2_crtc_enable_irq(vp, VP_INT_DSP_HOLD_VALID); -+ -+ vop2_vp_write(vp, RK3568_VP_DSP_CTRL, RK3568_VP_DSP_CTRL__STANDBY); -+ -+ ret = wait_for_completion_timeout(&vp->dsp_hold_completion, -+ msecs_to_jiffies(50)); -+ if (!ret) -+ drm_info(vop2->drm, "wait for vp%d dsp_hold timeout\n", vp->id); -+ -+ vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID); -+ -+ clk_disable_unprepare(vp->dclk); -+ -+ vop2->enable_count--; -+ -+ if (!vop2->enable_count) -+ vop2_disable(vop2); -+ -+ vop2_unlock(vop2); -+ -+ if (crtc->state->event && !crtc->state->active) { -+ spin_lock_irq(&crtc->dev->event_lock); -+ drm_crtc_send_vblank_event(crtc, crtc->state->event); -+ spin_unlock_irq(&crtc->dev->event_lock); -+ -+ crtc->state->event = NULL; -+ } -+} -+ - static int vop2_crtc_atomic_check(struct drm_crtc *crtc, - struct drm_atomic_state *state) - { -@@ -2104,7 +2634,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, -@@ -2299,7 +2865,7 @@ static int vop2_create_crtcs(struct vop2 *vop2) - for (i = 0; i < vop2_data->nr_vps; i++) { - const struct vop2_video_port_data *vp_data; - struct device_node *np; -- char dclk_name[9]; -+ char clk_name[16]; - - vp_data = &vop2_data->vp[i]; - vp = &vop2->vps[i]; -@@ -2307,13 +2873,26 @@ static int vop2_create_crtcs(struct vop2 *vop2) - vp->id = vp_data->id; - vp->data = vp_data; - -- snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id); -- vp->dclk = devm_clk_get(vop2->dev, dclk_name); -+ snprintf(clk_name, sizeof(clk_name), "dclk_vp%d", vp->id); -+ vp->dclk = devm_clk_get(vop2->dev, clk_name); - if (IS_ERR(vp->dclk)) { -- drm_err(vop2->drm, "failed to get %s\n", dclk_name); -+ drm_err(vop2->drm, "failed to get %s\n", clk_name); - return PTR_ERR(vp->dclk); - } - -+ vp->dclk_rst = devm_reset_control_get_optional(vop2->dev, clk_name); -+ if (IS_ERR(vp->dclk_rst)) { -+ drm_err(vop2->drm, "failed to get dclk reset\n"); -+ return PTR_ERR(vp->dclk_rst); -+ } -+ -+ snprintf(clk_name, sizeof(clk_name), "dclk_src_vp%d", vp->id); -+ vp->dclk_parent = devm_clk_get_optional(vop2->dev, clk_name); -+ if (IS_ERR(vp->dclk_parent)) { -+ drm_err(vop2->drm, "failed to get %s\n", clk_name); -+ return PTR_ERR(vp->dclk_parent); -+ } -+ - np = of_graph_get_remote_node(dev->of_node, i, -1); - if (!np) { - drm_dbg(vop2->drm, "%s: No remote for vp%d\n", __func__, i); -@@ -2674,6 +3253,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) -+ 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); -@@ -2726,7 +3635,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) - return PTR_ERR(vop2->lut_regs); - } - -+ // [CC:] grf -> sys_grf in downstream - vop2->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); -+ // [CC:] vop_grf -> grf in downstream -+ // [CC:] make use of new grf's -+ vop2->vop_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vop-grf"); -+ vop2->vo1_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vo1-grf"); - - vop2->hclk = devm_clk_get(vop2->dev, "hclk"); - if (IS_ERR(vop2->hclk)) { -@@ -2740,6 +3654,31 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) - return PTR_ERR(vop2->aclk); - } - -+ vop2->pclk = devm_clk_get_optional(vop2->dev, "pclk"); -+ if (IS_ERR(vop2->pclk)) { -+ DRM_DEV_ERROR(vop2->dev, "failed to get pclk source\n"); -+ 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); -+ } -+ -+ // [CC:] drop ahb_rst & axi_rst -+ vop2->ahb_rst = devm_reset_control_get_optional(vop2->dev, "ahb"); -+ if (IS_ERR(vop2->ahb_rst)) { -+ DRM_DEV_ERROR(vop2->dev, "failed to get ahb reset\n"); -+ return PTR_ERR(vop2->ahb_rst); -+ } -+ -+ vop2->axi_rst = devm_reset_control_get_optional(vop2->dev, "axi"); -+ if (IS_ERR(vop2->axi_rst)) { -+ DRM_DEV_ERROR(vop2->dev, "failed to get axi reset\n"); -+ return PTR_ERR(vop2->axi_rst); -+ } -+ - vop2->irq = platform_get_irq(pdev, 0); - if (vop2->irq < 0) { - drm_err(vop2->drm, "cannot find irq for vop2\n"); -@@ -2756,6 +3695,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, -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h -index 56fd31e05..cae71df81 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h -@@ -12,10 +12,18 @@ - #include - #include - --#define VOP_FEATURE_OUTPUT_10BIT BIT(0) -+/* a feature to splice two windows and two vps to support resolution > 4096 */ -+#define VOP_FEATURE_SPLICE BIT(5) -+//[CC:] dupplicate of #define VOP_FEATURE_OUTPUT_RGB10 BIT(0) in vop.h -+#define VOP_FEATURE_OUTPUT_10BIT BIT(0) - -+//[CC:] downstream uses #define WIN_FEATURE_AFBDC BIT(3) - #define WIN_FEATURE_AFBDC BIT(0) - #define WIN_FEATURE_CLUSTER BIT(1) -+/* Left win in splice mode */ -+#define WIN_FEATURE_SPLICE_LEFT BIT(6) -+ -+#define HIWORD_UPDATE(v, h, l) ((GENMASK(h, l) << 16) | ((v) << (l))) - - /* - * the delay number of a window in different mode. -@@ -39,6 +47,18 @@ enum vop2_scale_down_mode { - VOP2_SCALE_DOWN_AVG, - }; - -+/* -+ * vop2 internal power domain id, -+ * should be all none zero, 0 will be treat as invalid; -+ */ -+#define VOP2_PD_CLUSTER0 BIT(0) -+#define VOP2_PD_CLUSTER1 BIT(1) -+#define VOP2_PD_CLUSTER2 BIT(2) -+#define VOP2_PD_CLUSTER3 BIT(3) -+#define VOP2_PD_DSC_8K BIT(5) -+#define VOP2_PD_DSC_4K BIT(6) -+#define VOP2_PD_ESMART BIT(7) -+ - enum vop2_win_regs { - VOP2_WIN_ENABLE, - VOP2_WIN_FORMAT, -@@ -107,6 +127,7 @@ enum vop2_win_regs { - struct vop2_win_data { - const char *name; - unsigned int phys_id; -+ uint8_t splice_win_id; - - u32 base; - enum drm_plane_type type; -@@ -129,9 +150,11 @@ struct vop2_win_data { - - struct vop2_video_port_data { - unsigned int id; -+ uint8_t splice_vp_id; - u32 feature; - u16 gamma_lut_len; - u16 cubic_lut_len; -+ unsigned long dclk_max; - struct vop_rect max_output; - const u8 pre_scan_max_dly[4]; - unsigned int offset; -@@ -145,7 +168,13 @@ struct vop2_data { - struct vop_rect max_output; - - unsigned int win_size; -+ // [CC:] convert to an enum as it is used in conditional statements - unsigned int soc_id; -+ -+ uint8_t nr_dscs; -+ uint8_t nr_conns; -+ const struct vop2_dsc_data *dsc; -+ const struct vop2_connector_if_data *conn; - }; - - /* interrupt define */ -@@ -450,6 +479,45 @@ enum dst_factor_mode { - - #define POLFLAG_DCLK_INV BIT(3) - -+/* RK3588 registers */ -+#define RK3588_GRF_SOC_CON1 0x0304 -+#define RK3588_GRF_VOP_CON2 0x08 -+#define RK3588_GRF_VO1_CON0 0x00 -+ -+#define RK3588_GRF_VO1_CON0__HDMI0_PIN_POL GENMASK(6, 5) -+ -+#define RK3588_SYS_PD_CTRL 0x034 -+#define RK3588_VP_CLK_CTRL 0x0c -+ -+#define RK3588_VP_CLK_CTRL__DCLK_OUT_DIV GENMASK(3, 2) -+#define RK3588_VP_CLK_CTRL__DCLK_CORE_DIV GENMASK(1, 0) -+ -+#define RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX GENMASK(22, 21) -+#define RK3588_SYS_DSP_INFACE_EN_MIPI0_MUX GENMASK(20, 20) -+#define RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX GENMASK(19, 18) -+#define RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX GENMASK(17, 16) -+#define RK3588_SYS_DSP_INFACE_EN_DP1_MUX GENMASK(15, 14) -+#define RK3588_SYS_DSP_INFACE_EN_DP0_MUX GENMASK(13, 12) -+#define RK3588_SYS_DSP_INFACE_EN_DPI GENMASK(9, 8) -+#define RK3588_SYS_DSP_INFACE_EN_MIPI1 BIT(7) -+#define RK3588_SYS_DSP_INFACE_EN_MIPI0 BIT(6) -+#define RK3588_SYS_DSP_INFACE_EN_HDMI1 BIT(5) -+#define RK3588_SYS_DSP_INFACE_EN_EDP1 BIT(4) -+#define RK3588_SYS_DSP_INFACE_EN_HDMI0 BIT(3) -+#define RK3588_SYS_DSP_INFACE_EN_EDP0 BIT(2) -+#define RK3588_SYS_DSP_INFACE_EN_DP1 BIT(1) -+#define RK3588_SYS_DSP_INFACE_EN_DP0 BIT(0) -+ -+#define RK3588_DSP_IF_MIPI1_PCLK_DIV GENMASK(27, 26) -+#define RK3588_DSP_IF_MIPI0_PCLK_DIV GENMASK(25, 24) -+#define RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV GENMASK(22, 22) -+#define RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV GENMASK(21, 20) -+#define RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV GENMASK(18, 18) -+#define RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV GENMASK(17, 16) -+ -+#define RK3588_DSP_IF_POL__DP1_PIN_POL GENMASK(14, 12) -+#define RK3588_DSP_IF_POL__DP0_PIN_POL GENMASK(10, 8) -+ - enum vop2_layer_phy_id { - ROCKCHIP_VOP2_CLUSTER0 = 0, - ROCKCHIP_VOP2_CLUSTER1, -diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c -index 22288ad7f..2bc1baf5c 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c -+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c -@@ -131,6 +131,49 @@ static const struct vop2_video_port_data rk3568_vop_video_ports[] = { - }, - }; - -+static const struct vop2_video_port_data rk3588_vop_video_ports[] = { -+ { -+ .id = 0, -+ // .splice_vp_id = 1, -+ // .lut_dma_rid = 1, -+ .feature = VOP_FEATURE_OUTPUT_10BIT, -+ .gamma_lut_len = 1024, -+ .cubic_lut_len = 9 * 9 * 9, -+ // .dclk_max = 600000000, -+ .max_output = { 7680, 4320 }, -+ .pre_scan_max_dly = { 76, 65, 65, 54 }, -+ .offset = 0xc00, -+ }, { -+ .id = 1, -+ // .lut_dma_rid = 14, -+ .feature = VOP_FEATURE_OUTPUT_10BIT, -+ .gamma_lut_len = 1024, -+ .cubic_lut_len = 9 * 9 * 9, -+ // .dclk_max = 600000000, -+ .max_output = { 4096, 2304 }, -+ .pre_scan_max_dly = { 76, 65, 65, 54 }, -+ .offset = 0xd00, -+ }, { -+ .id = 2, -+ // .lut_dma_rid = 14, -+ .feature = VOP_FEATURE_OUTPUT_10BIT, -+ .gamma_lut_len = 1024, -+ .cubic_lut_len = 17 * 17 * 17, -+ // .dclk_max = 600000000, -+ .max_output = { 4096, 2304 }, -+ .pre_scan_max_dly = { 52, 52, 52, 52 }, -+ .offset = 0xe00, -+ }, { -+ .id = 3, -+ // .lut_dma_rid = 14, -+ .gamma_lut_len = 1024, -+ // .dclk_max = 200000000, -+ .max_output = { 2048, 1536 }, -+ .pre_scan_max_dly = { 52, 52, 52, 52 }, -+ .offset = 0xf00, -+ }, -+}; -+ - /* - * rk3568 vop with 2 cluster, 2 esmart win, 2 smart win. - * Every cluster can work as 4K win or split into two win. -@@ -234,6 +277,174 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { - }, - }; - -+/* -+ * rk3588 vop with 4 cluster, 4 esmart win. -+ * Every cluster can work as 4K win or split into two win. -+ * All win in cluster support AFBCD. -+ * -+ * Every esmart win and smart win support 4 Multi-region. -+ * -+ * Scale filter mode: -+ * -+ * * Cluster: bicubic for horizontal scale up, others use bilinear -+ * * ESmart: -+ * * nearest-neighbor/bilinear/bicubic for scale up -+ * * nearest-neighbor/bilinear/average for scale down -+ * -+ * AXI Read ID assignment: -+ * Two AXI bus: -+ * AXI0 is a read/write bus with a higher performance. -+ * AXI1 is a read only bus. -+ * -+ * Every window on a AXI bus must assigned two unique -+ * read id(yrgb_id/uv_id, valid id are 0x1~0xe). -+ * -+ * AXI0: -+ * Cluster0/1, Esmart0/1, WriteBack -+ * -+ * AXI 1: -+ * Cluster2/3, Esmart2/3 -+ */ -+static const struct vop2_win_data rk3588_vop_win_data[] = { -+ { -+ .name = "Cluster0-win0", -+ .phys_id = ROCKCHIP_VOP2_CLUSTER0, -+ //[CC:] .splice_win_id = ROCKCHIP_VOP2_CLUSTER1, -+ .base = 0x1000, -+ .formats = formats_cluster, -+ .nformats = ARRAY_SIZE(formats_cluster), -+ .format_modifiers = format_modifiers_afbc, -+ .layer_sel_id = 0, -+ .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | -+ DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, -+ .type = DRM_PLANE_TYPE_OVERLAY, -+ // .pd_id = VOP2_PD_CLUSTER0, -+ // .axi_id = 0, -+ // .axi_yrgb_id = 2, -+ // .axi_uv_id = 3, -+ .max_upscale_factor = 4, -+ .max_downscale_factor = 4, -+ .dly = { 4, 26, 29 }, -+ //[CC:] WIN_FEATURE_SPLICE_LEFT -+ .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER, -+ }, { -+ .name = "Cluster1-win0", -+ .phys_id = ROCKCHIP_VOP2_CLUSTER1, -+ .base = 0x1200, -+ .formats = formats_cluster, -+ .nformats = ARRAY_SIZE(formats_cluster), -+ .format_modifiers = format_modifiers_afbc, -+ .layer_sel_id = 1, -+ .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | -+ DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, -+ .type = DRM_PLANE_TYPE_OVERLAY, -+ // .pd_id = VOP2_PD_CLUSTER1, -+ // .axi_id = 0, -+ // .axi_yrgb_id = 6, -+ // .axi_uv_id = 7, -+ .max_upscale_factor = 4, -+ .max_downscale_factor = 4, -+ .dly = { 4, 26, 29 }, -+ .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER, -+ }, { -+ .name = "Cluster2-win0", -+ .phys_id = ROCKCHIP_VOP2_CLUSTER2, -+ // [CC:] .splice_win_id = ROCKCHIP_VOP2_CLUSTER3, -+ .base = 0x1400, -+ .formats = formats_cluster, -+ .nformats = ARRAY_SIZE(formats_cluster), -+ .format_modifiers = format_modifiers_afbc, -+ .layer_sel_id = 4, -+ .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | -+ DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, -+ .type = DRM_PLANE_TYPE_OVERLAY, -+ // .pd_id = VOP2_PD_CLUSTER2, -+ // .axi_id = 1, -+ // .axi_yrgb_id = 2, -+ // .axi_uv_id = 3, -+ .max_upscale_factor = 4, -+ .max_downscale_factor = 4, -+ .dly = { 4, 26, 29 }, -+ //[CC:] WIN_FEATURE_SPLICE_LEFT -+ .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER, -+ }, { -+ .name = "Cluster3-win0", -+ .phys_id = ROCKCHIP_VOP2_CLUSTER3, -+ .base = 0x1600, -+ .formats = formats_cluster, -+ .nformats = ARRAY_SIZE(formats_cluster), -+ .format_modifiers = format_modifiers_afbc, -+ .layer_sel_id = 5, -+ .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | -+ DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, -+ .type = DRM_PLANE_TYPE_OVERLAY, -+ // .pd_id = VOP2_PD_CLUSTER3, -+ // .axi_id = 1, -+ // .axi_yrgb_id = 6, -+ // .axi_uv_id = 7, -+ .max_upscale_factor = 4, -+ .max_downscale_factor = 4, -+ .dly = { 4, 26, 29 }, -+ .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER, -+ }, { -+ .name = "Esmart0-win0", -+ .phys_id = ROCKCHIP_VOP2_ESMART0, -+ // [CC:] .splice_win_id = ROCKCHIP_VOP2_ESMART1, -+ .formats = formats_rk356x_esmart, -+ .nformats = ARRAY_SIZE(formats_rk356x_esmart), -+ .format_modifiers = format_modifiers, -+ .base = 0x1800, -+ .layer_sel_id = 2, -+ .supported_rotations = DRM_MODE_REFLECT_Y, -+ .type = DRM_PLANE_TYPE_PRIMARY, -+ // [CC:] .pd_id missing in downstream code -+ // .axi_id = 0, -+ // .axi_yrgb_id = 0x0a, -+ // .axi_uv_id = 0x0b, -+ .max_upscale_factor = 8, -+ .max_downscale_factor = 8, -+ .dly = { 23, 45, 48 }, -+ // .feature = WIN_FEATURE_SPLICE_LEFT | WIN_FEATURE_MULTI_AREA, -+ }, { -+ .name = "Esmart2-win0", -+ .phys_id = ROCKCHIP_VOP2_ESMART2, -+ // [CC:] .splice_win_id = ROCKCHIP_VOP2_ESMART3, -+ .formats = formats_rk356x_esmart, -+ .nformats = ARRAY_SIZE(formats_rk356x_esmart), -+ .format_modifiers = format_modifiers, -+ .base = 0x1c00, -+ .layer_sel_id = 6, -+ .supported_rotations = DRM_MODE_REFLECT_Y, -+ .type = DRM_PLANE_TYPE_PRIMARY, -+ // .pd_id = VOP2_PD_ESMART, -+ // .axi_id = 1, -+ // .axi_yrgb_id = 0x0a, -+ // .axi_uv_id = 0x0b, -+ .max_upscale_factor = 8, -+ .max_downscale_factor = 8, -+ .dly = { 23, 45, 48 }, -+ // .feature = WIN_FEATURE_SPLICE_LEFT | WIN_FEATURE_MULTI_AREA, -+ }, { -+ .name = "Esmart1-win0", -+ .phys_id = ROCKCHIP_VOP2_ESMART1, -+ .formats = formats_rk356x_esmart, -+ .nformats = ARRAY_SIZE(formats_rk356x_esmart), -+ .format_modifiers = format_modifiers, -+ .base = 0x1a00, -+ .layer_sel_id = 3, -+ .supported_rotations = DRM_MODE_REFLECT_Y, -+ .type = DRM_PLANE_TYPE_PRIMARY, -+ // .pd_id = VOP2_PD_ESMART, -+ // .axi_id = 0, -+ // .axi_yrgb_id = 0x0c, -+ // .axi_uv_id = 0x0d, -+ .max_upscale_factor = 8, -+ .max_downscale_factor = 8, -+ .dly = { 23, 45, 48 }, -+ // .feature = WIN_FEATURE_MULTI_AREA, -+ }, -+}; -+ - static const struct vop2_data rk3566_vop = { - .nr_vps = 3, - .max_input = { 4096, 2304 }, -@@ -246,14 +457,27 @@ static const struct vop2_data rk3566_vop = { - - static const struct vop2_data rk3568_vop = { - .nr_vps = 3, -- .max_input = { 4096, 2304 }, -- .max_output = { 4096, 2304 }, -+ .max_input = { 4096, 4320 }, -+ .max_output = { 4096, 4320 }, - .vp = rk3568_vop_video_ports, - .win = rk3568_vop_win_data, - .win_size = ARRAY_SIZE(rk3568_vop_win_data), - .soc_id = 3568, - }; - -+static const struct vop2_data rk3588_vop = { -+ // .feature = VOP_FEATURE_SPLICE, -+ .nr_vps = 4, -+ .max_input = { 4096, 2304 }, -+ .max_output = { 4096, 2304 }, -+ .vp = rk3588_vop_video_ports, -+ .win = rk3588_vop_win_data, -+ .win_size = ARRAY_SIZE(rk3588_vop_win_data), -+ // .conn = rk3588_conn_if_data, -+ // .nr_conns = ARRAY_SIZE(rk3588_conn_if_data), -+ .soc_id = 3588, -+}; -+ - static const struct of_device_id vop2_dt_match[] = { - { - .compatible = "rockchip,rk3566-vop", -@@ -261,6 +485,9 @@ static const struct of_device_id vop2_dt_match[] = { - }, { - .compatible = "rockchip,rk3568-vop", - .data = &rk3568_vop, -+ }, { -+ .compatible = "rockchip,rk3588-vop", -+ .data = &rk3588_vop, - }, { - }, - }; -diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig -index 94360fc96..62c18e25b 100644 ---- a/drivers/phy/rockchip/Kconfig -+++ b/drivers/phy/rockchip/Kconfig -@@ -83,6 +83,13 @@ config PHY_ROCKCHIP_PCIE - help - Enable this to support the Rockchip PCIe PHY. - -+config PHY_ROCKCHIP_SAMSUNG_HDPTX_HDMI -+ tristate "Rockchip Samsung HDMI/DP Combo PHY HDMI driver" -+ depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST) -+ select GENERIC_PHY -+ help -+ Support for Rockchip HDMI/DP Combo PHY with Samsung IP block. -+ - config PHY_ROCKCHIP_SNPS_PCIE3 - tristate "Rockchip Snps PCIe3 PHY Driver" - depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST -@@ -107,3 +114,15 @@ config PHY_ROCKCHIP_USB - select GENERIC_PHY - help - Enable this to support the Rockchip USB 2.0 PHY. -+ -+config PHY_ROCKCHIP_USBDP -+ tristate "Rockchip USBDP COMBO PHY Driver" -+ depends on ARCH_ROCKCHIP && OF -+ select GENERIC_PHY -+ select TYPEC -+ help -+ Enable this to support the Rockchip USB3.0/DP combo PHY with -+ Samsung IP block. This is required for USB3 support on RK3588. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called phy-rockchip-usbdp -diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile -index 7eab12923..d266414a1 100644 ---- a/drivers/phy/rockchip/Makefile -+++ b/drivers/phy/rockchip/Makefile -@@ -8,6 +8,8 @@ obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI) += phy-rockchip-inno-hdmi.o - obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o - obj-$(CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY) += phy-rockchip-naneng-combphy.o - obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o -+obj-$(CONFIG_PHY_ROCKCHIP_SAMSUNG_HDPTX_HDMI) += phy-rockchip-samsung-hdptx-hdmi.o - obj-$(CONFIG_PHY_ROCKCHIP_SNPS_PCIE3) += phy-rockchip-snps-pcie3.o - obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o - obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o -+obj-$(CONFIG_PHY_ROCKCHIP_USBDP) += phy-rockchip-usbdp.o -diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx-hdmi.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx-hdmi.c -new file mode 100644 -index 000000000..036db0877 ---- /dev/null -+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx-hdmi.c -@@ -0,0 +1,2347 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) Rockchip Electronics Co.Ltd -+ * Author: -+ * Algea Cao -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) -+ -+#define GRF_HDPTX_CON0 0x00 -+#define HDPTX_I_PLL_EN BIT(7) -+#define HDPTX_I_BIAS_EN BIT(6) -+#define HDPTX_I_BGR_EN BIT(5) -+#define GRF_HDPTX_STATUS 0x80 -+#define HDPTX_O_PLL_LOCK_DONE BIT(3) -+#define HDPTX_O_PHY_CLK_RDY BIT(2) -+#define HDPTX_O_PHY_RDY BIT(1) -+#define HDPTX_O_SB_RDY BIT(0) -+ -+#define CMN_REG0000 0x0000 -+#define CMN_REG0001 0x0004 -+#define CMN_REG0002 0x0008 -+#define CMN_REG0003 0x000C -+#define CMN_REG0004 0x0010 -+#define CMN_REG0005 0x0014 -+#define CMN_REG0006 0x0018 -+#define CMN_REG0007 0x001C -+#define CMN_REG0008 0x0020 -+#define LCPLL_EN_MASK BIT(6) -+#define LCPLL_EN(x) UPDATE(x, 4, 4) -+#define LCPLL_LCVCO_MODE_EN_MASK BIT(4) -+#define LCPLL_LCVCO_MODE_EN(x) UPDATE(x, 4, 4) -+#define CMN_REG0009 0x0024 -+#define CMN_REG000A 0x0028 -+#define CMN_REG000B 0x002C -+#define CMN_REG000C 0x0030 -+#define CMN_REG000D 0x0034 -+#define CMN_REG000E 0x0038 -+#define CMN_REG000F 0x003C -+#define CMN_REG0010 0x0040 -+#define CMN_REG0011 0x0044 -+#define CMN_REG0012 0x0048 -+#define CMN_REG0013 0x004C -+#define CMN_REG0014 0x0050 -+#define CMN_REG0015 0x0054 -+#define CMN_REG0016 0x0058 -+#define CMN_REG0017 0x005C -+#define CMN_REG0018 0x0060 -+#define CMN_REG0019 0x0064 -+#define CMN_REG001A 0x0068 -+#define CMN_REG001B 0x006C -+#define CMN_REG001C 0x0070 -+#define CMN_REG001D 0x0074 -+#define CMN_REG001E 0x0078 -+#define LCPLL_PI_EN_MASK BIT(5) -+#define LCPLL_PI_EN(x) UPDATE(x, 5, 5) -+#define LCPLL_100M_CLK_EN_MASK BIT(0) -+#define LCPLL_100M_CLK_EN(x) UPDATE(x, 0, 0) -+#define CMN_REG001F 0x007C -+#define CMN_REG0020 0x0080 -+#define CMN_REG0021 0x0084 -+#define CMN_REG0022 0x0088 -+#define CMN_REG0023 0x008C -+#define CMN_REG0024 0x0090 -+#define CMN_REG0025 0x0094 -+#define LCPLL_PMS_IQDIV_RSTN BIT(4) -+#define CMN_REG0026 0x0098 -+#define CMN_REG0027 0x009C -+#define CMN_REG0028 0x00A0 -+#define LCPLL_SDC_FRAC_EN BIT(2) -+#define LCPLL_SDC_FRAC_RSTN BIT(0) -+#define CMN_REG0029 0x00A4 -+#define CMN_REG002A 0x00A8 -+#define CMN_REG002B 0x00AC -+#define CMN_REG002C 0x00B0 -+#define CMN_REG002D 0x00B4 -+#define LCPLL_SDC_N_MASK GENMASK(3, 1) -+#define LCPLL_SDC_N(x) UPDATE(x, 3, 1) -+#define CMN_REG002E 0x00B8 -+#define LCPLL_SDC_NUMBERATOR_MASK GENMASK(5, 0) -+#define LCPLL_SDC_NUMBERATOR(x) UPDATE(x, 5, 0) -+#define CMN_REG002F 0x00BC -+#define LCPLL_SDC_DENOMINATOR_MASK GENMASK(7, 2) -+#define LCPLL_SDC_DENOMINATOR(x) UPDATE(x, 7, 2) -+#define LCPLL_SDC_NDIV_RSTN BIT(0) -+#define CMN_REG0030 0x00C0 -+#define CMN_REG0031 0x00C4 -+#define CMN_REG0032 0x00C8 -+#define CMN_REG0033 0x00CC -+#define CMN_REG0034 0x00D0 -+#define CMN_REG0035 0x00D4 -+#define CMN_REG0036 0x00D8 -+#define CMN_REG0037 0x00DC -+#define CMN_REG0038 0x00E0 -+#define CMN_REG0039 0x00E4 -+#define CMN_REG003A 0x00E8 -+#define CMN_REG003B 0x00EC -+#define CMN_REG003C 0x00F0 -+#define CMN_REG003D 0x00F4 -+#define ROPLL_LCVCO_EN BIT(4) -+#define CMN_REG003E 0x00F8 -+#define CMN_REG003F 0x00FC -+#define CMN_REG0040 0x0100 -+#define CMN_REG0041 0x0104 -+#define CMN_REG0042 0x0108 -+#define CMN_REG0043 0x010C -+#define CMN_REG0044 0x0110 -+#define CMN_REG0045 0x0114 -+#define CMN_REG0046 0x0118 -+#define CMN_REG0047 0x011C -+#define CMN_REG0048 0x0120 -+#define CMN_REG0049 0x0124 -+#define CMN_REG004A 0x0128 -+#define CMN_REG004B 0x012C -+#define CMN_REG004C 0x0130 -+#define CMN_REG004D 0x0134 -+#define CMN_REG004E 0x0138 -+#define ROPLL_PI_EN BIT(5) -+#define CMN_REG004F 0x013C -+#define CMN_REG0050 0x0140 -+#define CMN_REG0051 0x0144 -+#define CMN_REG0052 0x0148 -+#define CMN_REG0053 0x014C -+#define CMN_REG0054 0x0150 -+#define CMN_REG0055 0x0154 -+#define CMN_REG0056 0x0158 -+#define CMN_REG0057 0x015C -+#define CMN_REG0058 0x0160 -+#define CMN_REG0059 0x0164 -+#define CMN_REG005A 0x0168 -+#define CMN_REG005B 0x016C -+#define CMN_REG005C 0x0170 -+#define ROPLL_PMS_IQDIV_RSTN BIT(5) -+#define CMN_REG005D 0x0174 -+#define CMN_REG005E 0x0178 -+#define ROPLL_SDM_EN_MASK BIT(6) -+#define ROPLL_SDM_EN(x) UPDATE(x, 6, 6) -+#define ROPLL_SDM_FRAC_EN_RBR BIT(3) -+#define ROPLL_SDM_FRAC_EN_HBR BIT(2) -+#define ROPLL_SDM_FRAC_EN_HBR2 BIT(1) -+#define ROPLL_SDM_FRAC_EN_HBR3 BIT(0) -+#define CMN_REG005F 0x017C -+#define CMN_REG0060 0x0180 -+#define CMN_REG0061 0x0184 -+#define CMN_REG0062 0x0188 -+#define CMN_REG0063 0x018C -+#define CMN_REG0064 0x0190 -+#define ROPLL_SDM_NUM_SIGN_RBR_MASK BIT(3) -+#define ROPLL_SDM_NUM_SIGN_RBR(x) UPDATE(x, 3, 3) -+#define CMN_REG0065 0x0194 -+#define CMN_REG0066 0x0198 -+#define CMN_REG0067 0x019C -+#define CMN_REG0068 0x01A0 -+#define CMN_REG0069 0x01A4 -+#define ROPLL_SDC_N_RBR_MASK GENMASK(2, 0) -+#define ROPLL_SDC_N_RBR(x) UPDATE(x, 2, 0) -+#define CMN_REG006A 0x01A8 -+#define CMN_REG006B 0x01AC -+#define CMN_REG006C 0x01B0 -+#define CMN_REG006D 0x01B4 -+#define CMN_REG006E 0x01B8 -+#define CMN_REG006F 0x01BC -+#define CMN_REG0070 0x01C0 -+#define CMN_REG0071 0x01C4 -+#define CMN_REG0072 0x01C8 -+#define CMN_REG0073 0x01CC -+#define CMN_REG0074 0x01D0 -+#define ROPLL_SDC_NDIV_RSTN BIT(2) -+#define ROPLL_SSC_EN BIT(0) -+#define CMN_REG0075 0x01D4 -+#define CMN_REG0076 0x01D8 -+#define CMN_REG0077 0x01DC -+#define CMN_REG0078 0x01E0 -+#define CMN_REG0079 0x01E4 -+#define CMN_REG007A 0x01E8 -+#define CMN_REG007B 0x01EC -+#define CMN_REG007C 0x01F0 -+#define CMN_REG007D 0x01F4 -+#define CMN_REG007E 0x01F8 -+#define CMN_REG007F 0x01FC -+#define CMN_REG0080 0x0200 -+#define CMN_REG0081 0x0204 -+#define OVRD_PLL_CD_CLK_EN BIT(8) -+#define PLL_CD_HSCLK_EAST_EN BIT(0) -+#define CMN_REG0082 0x0208 -+#define CMN_REG0083 0x020C -+#define CMN_REG0084 0x0210 -+#define CMN_REG0085 0x0214 -+#define CMN_REG0086 0x0218 -+#define PLL_PCG_POSTDIV_SEL_MASK GENMASK(7, 4) -+#define PLL_PCG_POSTDIV_SEL(x) UPDATE(x, 7, 4) -+#define PLL_PCG_CLK_SEL_MASK GENMASK(3, 1) -+#define PLL_PCG_CLK_SEL(x) UPDATE(x, 3, 1) -+#define PLL_PCG_CLK_EN BIT(0) -+#define CMN_REG0087 0x021C -+#define PLL_FRL_MODE_EN BIT(3) -+#define PLL_TX_HS_CLK_EN BIT(2) -+#define CMN_REG0088 0x0220 -+#define CMN_REG0089 0x0224 -+#define LCPLL_ALONE_MODE BIT(1) -+#define CMN_REG008A 0x0228 -+#define CMN_REG008B 0x022C -+#define CMN_REG008C 0x0230 -+#define CMN_REG008D 0x0234 -+#define CMN_REG008E 0x0238 -+#define CMN_REG008F 0x023C -+#define CMN_REG0090 0x0240 -+#define CMN_REG0091 0x0244 -+#define CMN_REG0092 0x0248 -+#define CMN_REG0093 0x024C -+#define CMN_REG0094 0x0250 -+#define CMN_REG0095 0x0254 -+#define CMN_REG0096 0x0258 -+#define CMN_REG0097 0x025C -+#define DIG_CLK_SEL BIT(1) -+#define ROPLL_REF BIT(1) -+#define LCPLL_REF 0 -+#define CMN_REG0098 0x0260 -+#define CMN_REG0099 0x0264 -+#define CMN_ROPLL_ALONE_MODE BIT(2) -+#define ROPLL_ALONE_MODE BIT(2) -+#define CMN_REG009A 0x0268 -+#define HS_SPEED_SEL BIT(0) -+#define DIV_10_CLOCK BIT(0) -+#define CMN_REG009B 0x026C -+#define IS_SPEED_SEL BIT(4) -+#define LINK_SYMBOL_CLOCK BIT(4) -+#define LINK_SYMBOL_CLOCK1_2 0 -+#define CMN_REG009C 0x0270 -+#define CMN_REG009D 0x0274 -+#define CMN_REG009E 0x0278 -+#define CMN_REG009F 0x027C -+#define CMN_REG00A0 0x0280 -+#define CMN_REG00A1 0x0284 -+#define CMN_REG00A2 0x0288 -+#define CMN_REG00A3 0x028C -+#define CMN_REG00AD 0x0290 -+#define CMN_REG00A5 0x0294 -+#define CMN_REG00A6 0x0298 -+#define CMN_REG00A7 0x029C -+#define SB_REG0100 0x0400 -+#define SB_REG0101 0x0404 -+#define SB_REG0102 0x0408 -+#define OVRD_SB_RXTERM_EN_MASK BIT(5) -+#define OVRD_SB_RXTERM_EN(x) UPDATE(x, 5, 5) -+#define SB_RXTERM_EN_MASK BIT(4) -+#define SB_RXTERM_EN(x) UPDATE(x, 4, 4) -+#define ANA_SB_RXTERM_OFFSP_MASK GENMASK(3, 0) -+#define ANA_SB_RXTERM_OFFSP(x) UPDATE(x, 3, 0) -+#define SB_REG0103 0x040C -+#define ANA_SB_RXTERM_OFFSN_MASK GENMASK(6, 3) -+#define ANA_SB_RXTERM_OFFSN(x) UPDATE(x, 6, 3) -+#define OVRD_SB_RX_RESCAL_DONE_MASK BIT(1) -+#define OVRD_SB_RX_RESCAL_DONE(x) UPDATE(x, 1, 1) -+#define SB_RX_RESCAL_DONE_MASK BIT(0) -+#define SB_RX_RESCAL_DONE(x) UPDATE(x, 0, 0) -+#define SB_REG0104 0x0410 -+#define OVRD_SB_EN_MASK BIT(5) -+#define OVRD_SB_EN(x) UPDATE(x, 5, 5) -+#define SB_EN_MASK BIT(4) -+#define SB_EN(x) UPDATE(x, 4, 4) -+#define SB_REG0105 0x0414 -+#define OVRD_SB_EARC_CMDC_EN_MASK BIT(6) -+#define OVRD_SB_EARC_CMDC_EN(x) UPDATE(x, 6, 6) -+#define SB_EARC_CMDC_EN_MASK BIT(5) -+#define SB_EARC_CMDC_EN(x) UPDATE(x, 5, 5) -+#define ANA_SB_TX_HLVL_PROG_MASK GENMASK(2, 0) -+#define ANA_SB_TX_HLVL_PROG(x) UPDATE(x, 2, 0) -+#define SB_REG0106 0x0418 -+#define ANA_SB_TX_LLVL_PROG_MASK GENMASK(6, 4) -+#define ANA_SB_TX_LLVL_PROG(x) UPDATE(x, 6, 4) -+#define SB_REG0107 0x041C -+#define SB_REG0108 0x0420 -+#define SB_REG0109 0x0424 -+#define ANA_SB_DMRX_AFC_DIV_RATIO_MASK GENMASK(2, 0) -+#define ANA_SB_DMRX_AFC_DIV_RATIO(x) UPDATE(x, 2, 0) -+#define SB_REG010A 0x0428 -+#define SB_REG010B 0x042C -+#define SB_REG010C 0x0430 -+#define SB_REG010D 0x0434 -+#define SB_REG010E 0x0438 -+#define SB_REG010F 0x043C -+#define OVRD_SB_VREG_EN_MASK BIT(7) -+#define OVRD_SB_VREG_EN(x) UPDATE(x, 7, 7) -+#define SB_VREG_EN_MASK BIT(6) -+#define SB_VREG_EN(x) UPDATE(x, 6, 6) -+#define OVRD_SB_VREG_LPF_BYPASS_MASK BIT(5) -+#define OVRD_SB_VREG_LPF_BYPASS(x) UPDATE(x, 5, 5) -+#define SB_VREG_LPF_BYPASS_MASK BIT(4) -+#define SB_VREG_LPF_BYPASS(x) UPDATE(x, 4, 4) -+#define ANA_SB_VREG_GAIN_CTRL_MASK GENMASK(3, 0) -+#define ANA_SB_VREG_GAIN_CTRL(x) UPDATE(x, 3, 0) -+#define SB_REG0110 0x0440 -+#define ANA_SB_VREG_REF_SEL_MASK BIT(0) -+#define ANA_SB_VREG_REF_SEL(x) UPDATE(x, 0, 0) -+#define SB_REG0111 0x0444 -+#define SB_REG0112 0x0448 -+#define SB_REG0113 0x044C -+#define SB_RX_RCAL_OPT_CODE_MASK GENMASK(5, 4) -+#define SB_RX_RCAL_OPT_CODE(x) UPDATE(x, 5, 4) -+#define SB_RX_RTERM_CTRL_MASK GENMASK(3, 0) -+#define SB_RX_RTERM_CTRL(x) UPDATE(x, 3, 0) -+#define SB_REG0114 0x0450 -+#define SB_TG_SB_EN_DELAY_TIME_MASK GENMASK(5, 3) -+#define SB_TG_SB_EN_DELAY_TIME(x) UPDATE(x, 5, 3) -+#define SB_TG_RXTERM_EN_DELAY_TIME_MASK GENMASK(2, 0) -+#define SB_TG_RXTERM_EN_DELAY_TIME(x) UPDATE(x, 2, 0) -+#define SB_REG0115 0x0454 -+#define SB_READY_DELAY_TIME_MASK GENMASK(5, 3) -+#define SB_READY_DELAY_TIME(x) UPDATE(x, 5, 3) -+#define SB_TG_OSC_EN_DELAY_TIME_MASK GENMASK(2, 0) -+#define SB_TG_OSC_EN_DELAY_TIME(x) UPDATE(x, 2, 0) -+#define SB_REG0116 0x0458 -+#define AFC_RSTN_DELAY_TIME_MASK GENMASK(6, 4) -+#define AFC_RSTN_DELAY_TIME(x) UPDATE(x, 6, 4) -+#define SB_REG0117 0x045C -+#define FAST_PULSE_TIME_MASK GENMASK(3, 0) -+#define FAST_PULSE_TIME(x) UPDATE(x, 3, 0) -+#define SB_REG0118 0x0460 -+#define SB_REG0119 0x0464 -+#define SB_REG011A 0x0468 -+#define SB_REG011B 0x046C -+#define SB_EARC_SIG_DET_BYPASS_MASK BIT(4) -+#define SB_EARC_SIG_DET_BYPASS(x) UPDATE(x, 4, 4) -+#define SB_AFC_TOL_MASK GENMASK(3, 0) -+#define SB_AFC_TOL(x) UPDATE(x, 3, 0) -+#define SB_REG011C 0x0470 -+#define SB_REG011D 0x0474 -+#define SB_REG011E 0x0478 -+#define SB_REG011F 0x047C -+#define SB_PWM_AFC_CTRL_MASK GENMASK(7, 2) -+#define SB_PWM_AFC_CTRL(x) UPDATE(x, 7, 2) -+#define SB_RCAL_RSTN_MASK BIT(1) -+#define SB_RCAL_RSTN(x) UPDATE(x, 1, 1) -+#define SB_REG0120 0x0480 -+#define SB_EARC_EN_MASK BIT(1) -+#define SB_EARC_EN(x) UPDATE(x, 1, 1) -+#define SB_EARC_AFC_EN_MASK BIT(2) -+#define SB_EARC_AFC_EN(x) UPDATE(x, 2, 2) -+#define SB_REG0121 0x0484 -+#define SB_REG0122 0x0488 -+#define SB_REG0123 0x048C -+#define OVRD_SB_READY_MASK BIT(5) -+#define OVRD_SB_READY(x) UPDATE(x, 5, 5) -+#define SB_READY_MASK BIT(4) -+#define SB_READY(x) UPDATE(x, 4, 4) -+#define SB_REG0124 0x0490 -+#define SB_REG0125 0x0494 -+#define SB_REG0126 0x0498 -+#define SB_REG0127 0x049C -+#define SB_REG0128 0x04A0 -+#define SB_REG0129 0x04AD -+#define LNTOP_REG0200 0x0800 -+#define PROTOCOL_SEL BIT(2) -+#define HDMI_MODE BIT(2) -+#define HDMI_TMDS_FRL_SEL BIT(1) -+#define LNTOP_REG0201 0x0804 -+#define LNTOP_REG0202 0x0808 -+#define LNTOP_REG0203 0x080C -+#define LNTOP_REG0204 0x0810 -+#define LNTOP_REG0205 0x0814 -+#define LNTOP_REG0206 0x0818 -+#define DATA_BUS_WIDTH (0x3 << 1) -+#define WIDTH_40BIT (0x3 << 1) -+#define WIDTH_36BIT (0x2 << 1) -+#define DATA_BUS_SEL BIT(0) -+#define DATA_BUS_36_40 BIT(0) -+#define LNTOP_REG0207 0x081C -+#define LANE_EN 0xf -+#define ALL_LANE_EN 0xf -+#define LNTOP_REG0208 0x0820 -+#define LNTOP_REG0209 0x0824 -+#define LNTOP_REG020A 0x0828 -+#define LNTOP_REG020B 0x082C -+#define LNTOP_REG020C 0x0830 -+#define LNTOP_REG020D 0x0834 -+#define LNTOP_REG020E 0x0838 -+#define LNTOP_REG020F 0x083C -+#define LNTOP_REG0210 0x0840 -+#define LNTOP_REG0211 0x0844 -+#define LNTOP_REG0212 0x0848 -+#define LNTOP_REG0213 0x084C -+#define LNTOP_REG0214 0x0850 -+#define LNTOP_REG0215 0x0854 -+#define LNTOP_REG0216 0x0858 -+#define LNTOP_REG0217 0x085C -+#define LNTOP_REG0218 0x0860 -+#define LNTOP_REG0219 0x0864 -+#define LNTOP_REG021A 0x0868 -+#define LNTOP_REG021B 0x086C -+#define LNTOP_REG021C 0x0870 -+#define LNTOP_REG021D 0x0874 -+#define LNTOP_REG021E 0x0878 -+#define LNTOP_REG021F 0x087C -+#define LNTOP_REG0220 0x0880 -+#define LNTOP_REG0221 0x0884 -+#define LNTOP_REG0222 0x0888 -+#define LNTOP_REG0223 0x088C -+#define LNTOP_REG0224 0x0890 -+#define LNTOP_REG0225 0x0894 -+#define LNTOP_REG0226 0x0898 -+#define LNTOP_REG0227 0x089C -+#define LNTOP_REG0228 0x08A0 -+#define LNTOP_REG0229 0x08A4 -+#define LANE_REG0300 0x0C00 -+#define LANE_REG0301 0x0C04 -+#define LANE_REG0302 0x0C08 -+#define LANE_REG0303 0x0C0C -+#define LANE_REG0304 0x0C10 -+#define LANE_REG0305 0x0C14 -+#define LANE_REG0306 0x0C18 -+#define LANE_REG0307 0x0C1C -+#define LANE_REG0308 0x0C20 -+#define LANE_REG0309 0x0C24 -+#define LANE_REG030A 0x0C28 -+#define LANE_REG030B 0x0C2C -+#define LANE_REG030C 0x0C30 -+#define LANE_REG030D 0x0C34 -+#define LANE_REG030E 0x0C38 -+#define LANE_REG030F 0x0C3C -+#define LANE_REG0310 0x0C40 -+#define LANE_REG0311 0x0C44 -+#define LANE_REG0312 0x0C48 -+#define LN0_TX_SER_RATE_SEL_RBR BIT(5) -+#define LN0_TX_SER_RATE_SEL_HBR BIT(4) -+#define LN0_TX_SER_RATE_SEL_HBR2 BIT(3) -+#define LN0_TX_SER_RATE_SEL_HBR3 BIT(2) -+#define LANE_REG0313 0x0C4C -+#define LANE_REG0314 0x0C50 -+#define LANE_REG0315 0x0C54 -+#define LANE_REG0316 0x0C58 -+#define LANE_REG0317 0x0C5C -+#define LANE_REG0318 0x0C60 -+#define LANE_REG0319 0x0C64 -+#define LANE_REG031A 0x0C68 -+#define LANE_REG031B 0x0C6C -+#define LANE_REG031C 0x0C70 -+#define LANE_REG031D 0x0C74 -+#define LANE_REG031E 0x0C78 -+#define LANE_REG031F 0x0C7C -+#define LANE_REG0320 0x0C80 -+#define LANE_REG0321 0x0C84 -+#define LANE_REG0322 0x0C88 -+#define LANE_REG0323 0x0C8C -+#define LANE_REG0324 0x0C90 -+#define LANE_REG0325 0x0C94 -+#define LANE_REG0326 0x0C98 -+#define LANE_REG0327 0x0C9C -+#define LANE_REG0328 0x0CA0 -+#define LANE_REG0329 0x0CA4 -+#define LANE_REG032A 0x0CA8 -+#define LANE_REG032B 0x0CAC -+#define LANE_REG032C 0x0CB0 -+#define LANE_REG032D 0x0CB4 -+#define LANE_REG0400 0x1000 -+#define LANE_REG0401 0x1004 -+#define LANE_REG0402 0x1008 -+#define LANE_REG0403 0x100C -+#define LANE_REG0404 0x1010 -+#define LANE_REG0405 0x1014 -+#define LANE_REG0406 0x1018 -+#define LANE_REG0407 0x101C -+#define LANE_REG0408 0x1020 -+#define LANE_REG0409 0x1024 -+#define LANE_REG040A 0x1028 -+#define LANE_REG040B 0x102C -+#define LANE_REG040C 0x1030 -+#define LANE_REG040D 0x1034 -+#define LANE_REG040E 0x1038 -+#define LANE_REG040F 0x103C -+#define LANE_REG0410 0x1040 -+#define LANE_REG0411 0x1044 -+#define LANE_REG0412 0x1048 -+#define LN1_TX_SER_RATE_SEL_RBR BIT(5) -+#define LN1_TX_SER_RATE_SEL_HBR BIT(4) -+#define LN1_TX_SER_RATE_SEL_HBR2 BIT(3) -+#define LN1_TX_SER_RATE_SEL_HBR3 BIT(2) -+#define LANE_REG0413 0x104C -+#define LANE_REG0414 0x1050 -+#define LANE_REG0415 0x1054 -+#define LANE_REG0416 0x1058 -+#define LANE_REG0417 0x105C -+#define LANE_REG0418 0x1060 -+#define LANE_REG0419 0x1064 -+#define LANE_REG041A 0x1068 -+#define LANE_REG041B 0x106C -+#define LANE_REG041C 0x1070 -+#define LANE_REG041D 0x1074 -+#define LANE_REG041E 0x1078 -+#define LANE_REG041F 0x107C -+#define LANE_REG0420 0x1080 -+#define LANE_REG0421 0x1084 -+#define LANE_REG0422 0x1088 -+#define LANE_REG0423 0x108C -+#define LANE_REG0424 0x1090 -+#define LANE_REG0425 0x1094 -+#define LANE_REG0426 0x1098 -+#define LANE_REG0427 0x109C -+#define LANE_REG0428 0x10A0 -+#define LANE_REG0429 0x10A4 -+#define LANE_REG042A 0x10A8 -+#define LANE_REG042B 0x10AC -+#define LANE_REG042C 0x10B0 -+#define LANE_REG042D 0x10B4 -+#define LANE_REG0500 0x1400 -+#define LANE_REG0501 0x1404 -+#define LANE_REG0502 0x1408 -+#define LANE_REG0503 0x140C -+#define LANE_REG0504 0x1410 -+#define LANE_REG0505 0x1414 -+#define LANE_REG0506 0x1418 -+#define LANE_REG0507 0x141C -+#define LANE_REG0508 0x1420 -+#define LANE_REG0509 0x1424 -+#define LANE_REG050A 0x1428 -+#define LANE_REG050B 0x142C -+#define LANE_REG050C 0x1430 -+#define LANE_REG050D 0x1434 -+#define LANE_REG050E 0x1438 -+#define LANE_REG050F 0x143C -+#define LANE_REG0510 0x1440 -+#define LANE_REG0511 0x1444 -+#define LANE_REG0512 0x1448 -+#define LN2_TX_SER_RATE_SEL_RBR BIT(5) -+#define LN2_TX_SER_RATE_SEL_HBR BIT(4) -+#define LN2_TX_SER_RATE_SEL_HBR2 BIT(3) -+#define LN2_TX_SER_RATE_SEL_HBR3 BIT(2) -+#define LANE_REG0513 0x144C -+#define LANE_REG0514 0x1450 -+#define LANE_REG0515 0x1454 -+#define LANE_REG0516 0x1458 -+#define LANE_REG0517 0x145C -+#define LANE_REG0518 0x1460 -+#define LANE_REG0519 0x1464 -+#define LANE_REG051A 0x1468 -+#define LANE_REG051B 0x146C -+#define LANE_REG051C 0x1470 -+#define LANE_REG051D 0x1474 -+#define LANE_REG051E 0x1478 -+#define LANE_REG051F 0x147C -+#define LANE_REG0520 0x1480 -+#define LANE_REG0521 0x1484 -+#define LANE_REG0522 0x1488 -+#define LANE_REG0523 0x148C -+#define LANE_REG0524 0x1490 -+#define LANE_REG0525 0x1494 -+#define LANE_REG0526 0x1498 -+#define LANE_REG0527 0x149C -+#define LANE_REG0528 0x14A0 -+#define LANE_REG0529 0x14AD -+#define LANE_REG052A 0x14A8 -+#define LANE_REG052B 0x14AC -+#define LANE_REG052C 0x14B0 -+#define LANE_REG052D 0x14B4 -+#define LANE_REG0600 0x1800 -+#define LANE_REG0601 0x1804 -+#define LANE_REG0602 0x1808 -+#define LANE_REG0603 0x180C -+#define LANE_REG0604 0x1810 -+#define LANE_REG0605 0x1814 -+#define LANE_REG0606 0x1818 -+#define LANE_REG0607 0x181C -+#define LANE_REG0608 0x1820 -+#define LANE_REG0609 0x1824 -+#define LANE_REG060A 0x1828 -+#define LANE_REG060B 0x182C -+#define LANE_REG060C 0x1830 -+#define LANE_REG060D 0x1834 -+#define LANE_REG060E 0x1838 -+#define LANE_REG060F 0x183C -+#define LANE_REG0610 0x1840 -+#define LANE_REG0611 0x1844 -+#define LANE_REG0612 0x1848 -+#define LN3_TX_SER_RATE_SEL_RBR BIT(5) -+#define LN3_TX_SER_RATE_SEL_HBR BIT(4) -+#define LN3_TX_SER_RATE_SEL_HBR2 BIT(3) -+#define LN3_TX_SER_RATE_SEL_HBR3 BIT(2) -+#define LANE_REG0613 0x184C -+#define LANE_REG0614 0x1850 -+#define LANE_REG0615 0x1854 -+#define LANE_REG0616 0x1858 -+#define LANE_REG0617 0x185C -+#define LANE_REG0618 0x1860 -+#define LANE_REG0619 0x1864 -+#define LANE_REG061A 0x1868 -+#define LANE_REG061B 0x186C -+#define LANE_REG061C 0x1870 -+#define LANE_REG061D 0x1874 -+#define LANE_REG061E 0x1878 -+#define LANE_REG061F 0x187C -+#define LANE_REG0620 0x1880 -+#define LANE_REG0621 0x1884 -+#define LANE_REG0622 0x1888 -+#define LANE_REG0623 0x188C -+#define LANE_REG0624 0x1890 -+#define LANE_REG0625 0x1894 -+#define LANE_REG0626 0x1898 -+#define LANE_REG0627 0x189C -+#define LANE_REG0628 0x18A0 -+#define LANE_REG0629 0x18A4 -+#define LANE_REG062A 0x18A8 -+#define LANE_REG062B 0x18AC -+#define LANE_REG062C 0x18B0 -+#define LANE_REG062D 0x18B4 -+ -+#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) -+ -+enum hdptx_combphy_type { -+ SS_HDMI, -+ SS_DP -+}; -+ -+ -+struct lcpll_config { -+ u32 bit_rate; -+ u8 lcvco_mode_en; -+ u8 pi_en; -+ u8 clk_en_100m; -+ u8 pms_mdiv; -+ u8 pms_mdiv_afc; -+ u8 pms_pdiv; -+ u8 pms_refdiv; -+ u8 pms_sdiv; -+ u8 pi_cdiv_rstn; -+ u8 pi_cdiv_sel; -+ u8 sdm_en; -+ u8 sdm_rstn; -+ u8 sdc_frac_en; -+ u8 sdc_rstn; -+ u8 sdm_deno; -+ u8 sdm_num_sign; -+ u8 sdm_num; -+ u8 sdc_n; -+ u8 sdc_n2; -+ u8 sdc_num; -+ u8 sdc_deno; -+ u8 sdc_ndiv_rstn; -+ u8 ssc_en; -+ u8 ssc_fm_dev; -+ u8 ssc_fm_freq; -+ u8 ssc_clk_div_sel; -+ u8 cd_tx_ser_rate_sel; -+}; -+ -+struct ropll_config { -+ u32 bit_rate; -+ u8 pms_mdiv; -+ u8 pms_mdiv_afc; -+ u8 pms_pdiv; -+ u8 pms_refdiv; -+ u8 pms_sdiv; -+ u8 pms_iqdiv_rstn; -+ u8 ref_clk_sel; -+ u8 sdm_en; -+ u8 sdm_rstn; -+ u8 sdc_frac_en; -+ u8 sdc_rstn; -+ u8 sdm_clk_div; -+ u8 sdm_deno; -+ u8 sdm_num_sign; -+ u8 sdm_num; -+ u8 sdc_n; -+ u8 sdc_num; -+ u8 sdc_deno; -+ u8 sdc_ndiv_rstn; -+ u8 ssc_en; -+ u8 ssc_fm_dev; -+ u8 ssc_fm_freq; -+ u8 ssc_clk_div_sel; -+ u8 ana_cpp_ctrl; -+ u8 ana_lpf_c_sel; -+ u8 cd_tx_ser_rate_sel; -+}; -+ -+struct rockchip_hdptx_phy { -+ struct device *dev; -+ struct regmap *regmap; -+ struct regmap *grf; -+ -+ int irq; -+ int id; -+ -+ struct phy *phy; -+ struct clk_bulk_data *clks; -+ int nr_clks; -+ struct phy_config *phy_cfg; -+ -+ /* clk provider */ -+ struct clk_hw hw; -+ struct clk *dclk; -+ unsigned long rate; -+ -+ struct reset_control *phy_reset; -+ struct reset_control *apb_reset; -+ struct reset_control *cmn_reset; -+ struct reset_control *init_reset; -+ struct reset_control *lane_reset; -+ struct reset_control *ropll_reset; -+ struct reset_control *lcpll_reset; -+ -+ bool earc_en; -+ int count; -+}; -+ -+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, -+ }, -+ { ~0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, -+ }, -+}; -+ -+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, -+ }, -+ { ~0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ }, -+}; -+ -+struct ropll_config ropll_tmds_cfg[] = { -+ { 5940000, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, -+ 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 3712500, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, -+ 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 2970000, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, -+ 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 1620000, 135, 135, 1, 1, 3, 1, 1, 0, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10, -+ 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 1856250, 155, 155, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, -+ 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 1540000, 193, 193, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 193, 1, 32, 2, 1, -+ 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 1485000, 0x7b, 0x7b, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10, -+ 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 1462500, 122, 122, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 244, 1, 16, 2, 1, 1, -+ 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 1190000, 149, 149, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 149, 1, 16, 2, 1, 1, -+ 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 1065000, 89, 89, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 89, 1, 16, 1, 0, 1, -+ 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 1080000, 135, 135, 1, 1, 5, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, 0x14, -+ 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 855000, 214, 214, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 214, 1, 16, 2, 1, -+ 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 835000, 105, 105, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 42, 1, 16, 1, 0, -+ 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 928125, 155, 155, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, -+ 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 742500, 124, 124, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, -+ 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 650000, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1, -+ 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 337500, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5, 1, -+ 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 400000, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, 0x14, -+ 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 270000, 0x5a, 0x5a, 1, 1, 0xf, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, 0x14, -+ 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { 251750, 84, 84, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 168, 1, 16, 4, 1, -+ 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, -+ }, -+ { ~0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ }, -+}; -+ -+static bool rockchip_hdptx_phy_is_accissible_reg(struct device *dev, -+ unsigned int reg) -+{ -+ switch (reg) { -+ case 0x0000 ... 0x029c: -+ case 0x0400 ... 0x04a4: -+ case 0x0800 ... 0x08a4: -+ case 0x0c00 ... 0x0cb4: -+ case 0x1000 ... 0x10b4: -+ case 0x1400 ... 0x14b4: -+ case 0x1800 ... 0x18b4: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static const struct regmap_config rockchip_hdptx_phy_regmap_config = { -+ .reg_bits = 32, -+ .reg_stride = 4, -+ .val_bits = 32, -+ .fast_io = true, -+ .max_register = 0x18b4, -+ .name = "hdptx-combphy", -+ -+ .readable_reg = rockchip_hdptx_phy_is_accissible_reg, -+ .writeable_reg = rockchip_hdptx_phy_is_accissible_reg, -+}; -+ -+static inline struct rockchip_hdptx_phy *to_rockchip_hdptx_phy(struct clk_hw *hw) -+{ -+ return container_of(hw, struct rockchip_hdptx_phy, hw); -+} -+ -+static inline void hdptx_write(struct rockchip_hdptx_phy *hdptx, u32 reg, u8 val) -+{ -+ regmap_write(hdptx->regmap, reg, val); -+} -+ -+static inline u8 hdptx_read(struct rockchip_hdptx_phy *hdptx, u32 reg) -+{ -+ u32 val; -+ -+ regmap_read(hdptx->regmap, reg, &val); -+ -+ return val; -+} -+ -+static inline void hdptx_update_bits(struct rockchip_hdptx_phy *hdptx, u32 reg, -+ u8 mask, u8 val) -+{ -+ regmap_update_bits(hdptx->regmap, reg, mask, val); -+} -+ -+static inline void hdptx_grf_write(struct rockchip_hdptx_phy *hdptx, u32 reg, u32 val) -+{ -+ regmap_write(hdptx->grf, reg, val); -+} -+ -+static inline u8 hdptx_grf_read(struct rockchip_hdptx_phy *hdptx, u32 reg) -+{ -+ u32 val; -+ -+ regmap_read(hdptx->grf, reg, &val); -+ -+ return val; -+} -+ -+static void hdptx_pre_power_up(struct rockchip_hdptx_phy *hdptx) -+{ -+ u32 val = 0; -+ -+ reset_control_assert(hdptx->apb_reset); -+ udelay(20); -+ reset_control_deassert(hdptx->apb_reset); -+ -+ reset_control_assert(hdptx->lane_reset); -+ reset_control_assert(hdptx->cmn_reset); -+ reset_control_assert(hdptx->init_reset); -+ -+ val = (HDPTX_I_PLL_EN | HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16; -+ hdptx_grf_write(hdptx, GRF_HDPTX_CON0, val); -+} -+ -+static int hdptx_post_enable_lane(struct rockchip_hdptx_phy *hdptx) -+{ -+ u32 val = 0; -+ int i; -+ -+ reset_control_deassert(hdptx->lane_reset); -+ -+ val = (HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16 | HDPTX_I_BIAS_EN | -+ HDPTX_I_BGR_EN; -+ hdptx_grf_write(hdptx, GRF_HDPTX_CON0, val); -+ -+ for (i = 0; i < 50; i++) { -+ val = hdptx_grf_read(hdptx, GRF_HDPTX_STATUS); -+ -+ if (val & HDPTX_O_PHY_RDY && val & HDPTX_O_PLL_LOCK_DONE) -+ break; -+ udelay(100); -+ } -+ -+ if (i == 50) { -+ dev_err(hdptx->dev, "hdptx phy lane can't ready!\n"); -+ return -EINVAL; -+ } -+ -+ dev_err(hdptx->dev, "hdptx phy lane locked!\n"); -+ -+ return 0; -+} -+ -+static int hdptx_post_enable_pll(struct rockchip_hdptx_phy *hdptx) -+{ -+ u32 val = 0; -+ int i; -+ -+ val = (HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16 | HDPTX_I_BIAS_EN | -+ HDPTX_I_BGR_EN; -+ hdptx_grf_write(hdptx, GRF_HDPTX_CON0, val); -+ udelay(10); -+ reset_control_deassert(hdptx->init_reset); -+ udelay(10); -+ val = HDPTX_I_PLL_EN << 16 | HDPTX_I_PLL_EN; -+ hdptx_grf_write(hdptx, GRF_HDPTX_CON0, val); -+ udelay(10); -+ reset_control_deassert(hdptx->cmn_reset); -+ -+ for (i = 0; i < 20; i++) { -+ val = hdptx_grf_read(hdptx, GRF_HDPTX_STATUS); -+ -+ if (val & HDPTX_O_PHY_CLK_RDY) -+ break; -+ udelay(20); -+ } -+ -+ if (i == 20) { -+ dev_err(hdptx->dev, "hdptx phy pll can't lock!\n"); -+ return -EINVAL; -+ } -+ -+ dev_err(hdptx->dev, "hdptx phy pll locked!\n"); -+ -+ return 0; -+} -+ -+static int hdptx_post_power_up(struct rockchip_hdptx_phy *hdptx) -+{ -+ u32 val = 0; -+ int i; -+ -+ val = (HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16 | HDPTX_I_BIAS_EN | -+ HDPTX_I_BGR_EN; -+ hdptx_grf_write(hdptx, GRF_HDPTX_CON0, val); -+ udelay(10); -+ reset_control_deassert(hdptx->init_reset); -+ udelay(10); -+ val = HDPTX_I_PLL_EN << 16 | HDPTX_I_PLL_EN; -+ hdptx_grf_write(hdptx, GRF_HDPTX_CON0, val); -+ udelay(10); -+ reset_control_deassert(hdptx->cmn_reset); -+ -+ for (i = 0; i < 20; i++) { -+ val = hdptx_grf_read(hdptx, GRF_HDPTX_STATUS); -+ -+ if (val & HDPTX_O_PLL_LOCK_DONE) -+ break; -+ udelay(20); -+ } -+ -+ if (i == 20) { -+ dev_err(hdptx->dev, "hdptx phy can't lock!\n"); -+ return -EINVAL; -+ } -+ -+ udelay(20); -+ -+ reset_control_deassert(hdptx->lane_reset); -+ -+ for (i = 0; i < 50; i++) { -+ val = hdptx_grf_read(hdptx, GRF_HDPTX_STATUS); -+ -+ if (val & HDPTX_O_PHY_RDY) -+ break; -+ udelay(100); -+ } -+ -+ if (i == 50) { -+ dev_err(hdptx->dev, "hdptx phy can't ready!\n"); -+ return -EINVAL; -+ } -+ -+ dev_err(hdptx->dev, "hdptx phy locked!\n"); -+ -+ return 0; -+} -+ -+static void hdptx_phy_disable(struct rockchip_hdptx_phy *hdptx) -+{ -+ u32 val; -+ -+ /* reset phy and apb, or phy locked flag may keep 1 */ -+ reset_control_assert(hdptx->phy_reset); -+ udelay(20); -+ reset_control_deassert(hdptx->phy_reset); -+ -+ reset_control_assert(hdptx->apb_reset); -+ udelay(20); -+ reset_control_deassert(hdptx->apb_reset); -+ -+ hdptx_write(hdptx, LANE_REG0300, 0x82); -+ hdptx_write(hdptx, SB_REG010F, 0xc1); -+ hdptx_write(hdptx, SB_REG0110, 0x1); -+ hdptx_write(hdptx, LANE_REG0301, 0x80); -+ hdptx_write(hdptx, LANE_REG0401, 0x80); -+ hdptx_write(hdptx, LANE_REG0501, 0x80); -+ hdptx_write(hdptx, LANE_REG0601, 0x80); -+ -+ reset_control_assert(hdptx->lane_reset); -+ reset_control_assert(hdptx->cmn_reset); -+ reset_control_assert(hdptx->init_reset); -+ -+ val = (HDPTX_I_PLL_EN | HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16; -+ hdptx_grf_write(hdptx, GRF_HDPTX_CON0, val); -+} -+ -+static void hdptx_earc_config(struct rockchip_hdptx_phy *hdptx) -+{ -+ hdptx_update_bits(hdptx, SB_REG0113, SB_RX_RCAL_OPT_CODE_MASK, -+ SB_RX_RCAL_OPT_CODE(1)); -+ hdptx_write(hdptx, SB_REG011C, 0x04); -+ hdptx_update_bits(hdptx, SB_REG011B, SB_AFC_TOL_MASK, -+ SB_AFC_TOL(3)); -+ hdptx_write(hdptx, SB_REG0109, 0x05); -+ hdptx_update_bits(hdptx, SB_REG0120, SB_EARC_EN_MASK | SB_EARC_AFC_EN_MASK, -+ SB_EARC_EN(1) | SB_EARC_AFC_EN(1)); -+ hdptx_update_bits(hdptx, SB_REG011B, SB_EARC_SIG_DET_BYPASS_MASK, -+ SB_EARC_SIG_DET_BYPASS(1)); -+ hdptx_update_bits(hdptx, SB_REG011F, SB_PWM_AFC_CTRL_MASK | SB_RCAL_RSTN_MASK, -+ SB_PWM_AFC_CTRL(0xc) | SB_RCAL_RSTN(1)); -+ hdptx_update_bits(hdptx, SB_REG0115, SB_READY_DELAY_TIME_MASK, -+ SB_READY_DELAY_TIME(2)); -+ hdptx_update_bits(hdptx, SB_REG0113, SB_RX_RTERM_CTRL_MASK, -+ SB_RX_RTERM_CTRL(3)); -+ hdptx_update_bits(hdptx, SB_REG0102, ANA_SB_RXTERM_OFFSP_MASK, -+ ANA_SB_RXTERM_OFFSP(3)); -+ hdptx_update_bits(hdptx, SB_REG0103, ANA_SB_RXTERM_OFFSN_MASK, -+ ANA_SB_RXTERM_OFFSN(3)); -+ hdptx_write(hdptx, SB_REG011A, 0x03); -+ hdptx_write(hdptx, SB_REG0118, 0x0a); -+ hdptx_write(hdptx, SB_REG011E, 0x6a); -+ hdptx_write(hdptx, SB_REG011D, 0x67); -+ hdptx_update_bits(hdptx, SB_REG0117, FAST_PULSE_TIME_MASK, -+ FAST_PULSE_TIME(4)); -+ hdptx_update_bits(hdptx, SB_REG0114, SB_TG_SB_EN_DELAY_TIME_MASK | -+ SB_TG_RXTERM_EN_DELAY_TIME_MASK, -+ SB_TG_SB_EN_DELAY_TIME(2) | -+ SB_TG_RXTERM_EN_DELAY_TIME(2)); -+ hdptx_update_bits(hdptx, SB_REG0105, ANA_SB_TX_HLVL_PROG_MASK, -+ ANA_SB_TX_HLVL_PROG(7)); -+ hdptx_update_bits(hdptx, SB_REG0106, ANA_SB_TX_LLVL_PROG_MASK, -+ ANA_SB_TX_LLVL_PROG(7)); -+ hdptx_update_bits(hdptx, SB_REG010F, ANA_SB_VREG_GAIN_CTRL_MASK, -+ ANA_SB_VREG_GAIN_CTRL(0)); -+ hdptx_update_bits(hdptx, SB_REG0110, ANA_SB_VREG_REF_SEL_MASK, -+ ANA_SB_VREG_REF_SEL(1)); -+ hdptx_update_bits(hdptx, SB_REG0115, SB_TG_OSC_EN_DELAY_TIME_MASK, -+ SB_TG_OSC_EN_DELAY_TIME(2)); -+ hdptx_update_bits(hdptx, SB_REG0116, AFC_RSTN_DELAY_TIME_MASK, -+ AFC_RSTN_DELAY_TIME(2)); -+ hdptx_update_bits(hdptx, SB_REG0109, ANA_SB_DMRX_AFC_DIV_RATIO_MASK, -+ ANA_SB_DMRX_AFC_DIV_RATIO(5)); -+ hdptx_update_bits(hdptx, SB_REG0103, OVRD_SB_RX_RESCAL_DONE_MASK, -+ OVRD_SB_RX_RESCAL_DONE(1)); -+ hdptx_update_bits(hdptx, SB_REG0104, OVRD_SB_EN_MASK, -+ OVRD_SB_EN(1)); -+ hdptx_update_bits(hdptx, SB_REG0102, OVRD_SB_RXTERM_EN_MASK, -+ OVRD_SB_RXTERM_EN(1)); -+ hdptx_update_bits(hdptx, SB_REG0105, OVRD_SB_EARC_CMDC_EN_MASK, -+ OVRD_SB_EARC_CMDC_EN(1)); -+ hdptx_update_bits(hdptx, SB_REG010F, OVRD_SB_VREG_EN_MASK | -+ OVRD_SB_VREG_LPF_BYPASS_MASK, -+ OVRD_SB_VREG_EN(1) | OVRD_SB_VREG_LPF_BYPASS(1)); -+ hdptx_update_bits(hdptx, SB_REG0123, OVRD_SB_READY_MASK, -+ OVRD_SB_READY(1)); -+ udelay(1000); -+ hdptx_update_bits(hdptx, SB_REG0103, SB_RX_RESCAL_DONE_MASK, -+ SB_RX_RESCAL_DONE(1)); -+ udelay(50); -+ hdptx_update_bits(hdptx, SB_REG0104, SB_EN_MASK, SB_EN(1)); -+ udelay(50); -+ hdptx_update_bits(hdptx, SB_REG0102, SB_RXTERM_EN_MASK, -+ SB_RXTERM_EN(1)); -+ udelay(50); -+ hdptx_update_bits(hdptx, SB_REG0105, SB_EARC_CMDC_EN_MASK, -+ SB_EARC_CMDC_EN(1)); -+ hdptx_update_bits(hdptx, SB_REG010F, SB_VREG_EN_MASK, -+ SB_VREG_EN(1)); -+ udelay(50); -+ hdptx_update_bits(hdptx, SB_REG010F, OVRD_SB_VREG_LPF_BYPASS_MASK, -+ OVRD_SB_VREG_LPF_BYPASS(1)); -+ udelay(250); -+ hdptx_update_bits(hdptx, SB_REG010F, OVRD_SB_VREG_LPF_BYPASS_MASK, -+ OVRD_SB_VREG_LPF_BYPASS(0)); -+ udelay(100); -+ hdptx_update_bits(hdptx, SB_REG0123, SB_READY_MASK, SB_READY(1)); -+} -+ -+static bool hdptx_phy_clk_pll_calc(unsigned int data_rate, -+ struct ropll_config *cfg) -+{ -+ unsigned int fref = 24000; -+ unsigned int sdc; -+ unsigned int fout = data_rate / 2; -+ unsigned int fvco; -+ u32 mdiv, sdiv, n = 8; -+ unsigned long k = 0, lc, k_sub, lc_sub; -+ -+ for (sdiv = 16; sdiv >= 1; sdiv--) { -+ if (sdiv % 2 && sdiv != 1) -+ continue; -+ -+ fvco = fout * sdiv; -+ -+ if (fvco < 2000000 || fvco > 4000000) -+ continue; -+ -+ mdiv = DIV_ROUND_UP(fvco, fref); -+ if (mdiv < 20 || mdiv > 255) -+ continue; -+ -+ if (fref * mdiv - fvco) { -+ for (sdc = 264000; sdc <= 750000; sdc += fref) -+ if (sdc * n > fref * mdiv) -+ break; -+ -+ if (sdc > 750000) -+ continue; -+ -+ rational_best_approximation(fref * mdiv - fvco, -+ sdc / 16, -+ GENMASK(6, 0), -+ GENMASK(7, 0), -+ &k, &lc); -+ -+ rational_best_approximation(sdc * n - fref * mdiv, -+ sdc, -+ GENMASK(6, 0), -+ GENMASK(7, 0), -+ &k_sub, &lc_sub); -+ } -+ -+ break; -+ } -+ -+ if (sdiv < 1) -+ return false; -+ -+ if (cfg) { -+ cfg->pms_mdiv = mdiv; -+ cfg->pms_mdiv_afc = mdiv; -+ cfg->pms_pdiv = 1; -+ cfg->pms_refdiv = 1; -+ cfg->pms_sdiv = sdiv - 1; -+ -+ cfg->sdm_en = k > 0 ? 1 : 0; -+ if (cfg->sdm_en) { -+ cfg->sdm_deno = lc; -+ cfg->sdm_num_sign = 1; -+ cfg->sdm_num = k; -+ cfg->sdc_n = n - 3; -+ cfg->sdc_num = k_sub; -+ cfg->sdc_deno = lc_sub; -+ } -+ } -+ -+ return true; -+} -+ -+static int hdptx_ropll_cmn_config(struct rockchip_hdptx_phy *hdptx, unsigned long bit_rate) -+{ -+ int bus_width = phy_get_bus_width(hdptx->phy); -+ u8 color_depth = (bus_width & COLOR_DEPTH_MASK) ? 1 : 0; -+ struct ropll_config *cfg = ropll_tmds_cfg; -+ struct ropll_config rc = {0}; -+ -+ dev_info(hdptx->dev, "%s bus_width:%x rate:%lu\n", __func__, bus_width, bit_rate); -+ hdptx->rate = bit_rate * 100; -+ -+ if (color_depth) -+ bit_rate = bit_rate * 10 / 8; -+ -+ for (; cfg->bit_rate != ~0; cfg++) -+ if (bit_rate == cfg->bit_rate) -+ break; -+ -+ if (cfg->bit_rate == ~0) { -+ if (hdptx_phy_clk_pll_calc(bit_rate, &rc)) { -+ cfg = &rc; -+ } else { -+ dev_err(hdptx->dev, "%s can't find pll cfg\n", __func__); -+ return -EINVAL; -+ } -+ } -+ -+ dev_dbg(hdptx->dev, "mdiv=%u, sdiv=%u\n", -+ cfg->pms_mdiv, cfg->pms_sdiv + 1); -+ dev_dbg(hdptx->dev, "sdm_en=%u, k_sign=%u, k=%u, lc=%u", -+ cfg->sdm_en, cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno); -+ dev_dbg(hdptx->dev, "n=%u, k_sub=%u, lc_sub=%u\n", -+ cfg->sdc_n + 3, cfg->sdc_num, cfg->sdc_deno); -+ -+ hdptx_pre_power_up(hdptx); -+ -+ reset_control_assert(hdptx->ropll_reset); -+ udelay(20); -+ reset_control_deassert(hdptx->ropll_reset); -+ -+ hdptx_write(hdptx, CMN_REG0008, 0x00); -+ hdptx_write(hdptx, CMN_REG0009, 0x0c); -+ hdptx_write(hdptx, CMN_REG000A, 0x83); -+ hdptx_write(hdptx, CMN_REG000B, 0x06); -+ hdptx_write(hdptx, CMN_REG000C, 0x20); -+ hdptx_write(hdptx, CMN_REG000D, 0xb8); -+ hdptx_write(hdptx, CMN_REG000E, 0x0f); -+ hdptx_write(hdptx, CMN_REG000F, 0x0f); -+ hdptx_write(hdptx, CMN_REG0010, 0x04); -+ hdptx_write(hdptx, CMN_REG0011, 0x01); -+ hdptx_write(hdptx, CMN_REG0012, 0x26); -+ hdptx_write(hdptx, CMN_REG0013, 0x22); -+ hdptx_write(hdptx, CMN_REG0014, 0x24); -+ hdptx_write(hdptx, CMN_REG0015, 0x77); -+ hdptx_write(hdptx, CMN_REG0016, 0x08); -+ hdptx_write(hdptx, CMN_REG0017, 0x20); -+ hdptx_write(hdptx, CMN_REG0018, 0x04); -+ hdptx_write(hdptx, CMN_REG0019, 0x48); -+ hdptx_write(hdptx, CMN_REG001A, 0x01); -+ hdptx_write(hdptx, CMN_REG001B, 0x00); -+ hdptx_write(hdptx, CMN_REG001C, 0x01); -+ hdptx_write(hdptx, CMN_REG001D, 0x64); -+ hdptx_write(hdptx, CMN_REG001E, 0x14); -+ hdptx_write(hdptx, CMN_REG001F, 0x00); -+ hdptx_write(hdptx, CMN_REG0020, 0x00); -+ hdptx_write(hdptx, CMN_REG0021, 0x00); -+ hdptx_write(hdptx, CMN_REG0022, 0x11); -+ hdptx_write(hdptx, CMN_REG0023, 0x00); -+ hdptx_write(hdptx, CMN_REG0024, 0x00); -+ hdptx_write(hdptx, CMN_REG0025, 0x53); -+ hdptx_write(hdptx, CMN_REG0026, 0x00); -+ hdptx_write(hdptx, CMN_REG0027, 0x00); -+ hdptx_write(hdptx, CMN_REG0028, 0x01); -+ hdptx_write(hdptx, CMN_REG0029, 0x01); -+ hdptx_write(hdptx, CMN_REG002A, 0x00); -+ hdptx_write(hdptx, CMN_REG002B, 0x00); -+ hdptx_write(hdptx, CMN_REG002C, 0x00); -+ hdptx_write(hdptx, CMN_REG002D, 0x00); -+ hdptx_write(hdptx, CMN_REG002E, 0x04); -+ hdptx_write(hdptx, CMN_REG002F, 0x00); -+ hdptx_write(hdptx, CMN_REG0030, 0x20); -+ hdptx_write(hdptx, CMN_REG0031, 0x30); -+ hdptx_write(hdptx, CMN_REG0032, 0x0b); -+ hdptx_write(hdptx, CMN_REG0033, 0x23); -+ hdptx_write(hdptx, CMN_REG0034, 0x00); -+ hdptx_write(hdptx, CMN_REG0035, 0x00); -+ hdptx_write(hdptx, CMN_REG0038, 0x00); -+ hdptx_write(hdptx, CMN_REG0039, 0x00); -+ hdptx_write(hdptx, CMN_REG003A, 0x00); -+ hdptx_write(hdptx, CMN_REG003B, 0x00); -+ hdptx_write(hdptx, CMN_REG003C, 0x80); -+ hdptx_write(hdptx, CMN_REG003D, 0x40); -+ hdptx_write(hdptx, CMN_REG003E, 0x0c); -+ hdptx_write(hdptx, CMN_REG003F, 0x83); -+ hdptx_write(hdptx, CMN_REG0040, 0x06); -+ hdptx_write(hdptx, CMN_REG0041, 0x20); -+ hdptx_write(hdptx, CMN_REG0042, 0x78); -+ hdptx_write(hdptx, CMN_REG0043, 0x00); -+ hdptx_write(hdptx, CMN_REG0044, 0x46); -+ hdptx_write(hdptx, CMN_REG0045, 0x24); -+ hdptx_write(hdptx, CMN_REG0046, 0xff); -+ hdptx_write(hdptx, CMN_REG0047, 0x00); -+ hdptx_write(hdptx, CMN_REG0048, 0x44); -+ hdptx_write(hdptx, CMN_REG0049, 0xfa); -+ hdptx_write(hdptx, CMN_REG004A, 0x08); -+ hdptx_write(hdptx, CMN_REG004B, 0x00); -+ hdptx_write(hdptx, CMN_REG004C, 0x01); -+ hdptx_write(hdptx, CMN_REG004D, 0x64); -+ hdptx_write(hdptx, CMN_REG004E, 0x34); -+ hdptx_write(hdptx, CMN_REG004F, 0x00); -+ hdptx_write(hdptx, CMN_REG0050, 0x00); -+ -+ hdptx_write(hdptx, CMN_REG0051, cfg->pms_mdiv); -+ hdptx_write(hdptx, CMN_REG0055, cfg->pms_mdiv_afc); -+ -+ hdptx_write(hdptx, CMN_REG0059, (cfg->pms_pdiv << 4) | cfg->pms_refdiv); -+ -+ hdptx_write(hdptx, CMN_REG005A, (cfg->pms_sdiv << 4)); -+ -+ hdptx_write(hdptx, CMN_REG005C, 0x25); -+ hdptx_write(hdptx, CMN_REG005D, 0x0c); -+ hdptx_write(hdptx, CMN_REG005E, 0x4f); -+ hdptx_update_bits(hdptx, CMN_REG005E, ROPLL_SDM_EN_MASK, -+ ROPLL_SDM_EN(cfg->sdm_en)); -+ if (!cfg->sdm_en) -+ hdptx_update_bits(hdptx, CMN_REG005E, 0xf, 0); -+ -+ hdptx_write(hdptx, CMN_REG005F, 0x01); -+ -+ hdptx_update_bits(hdptx, CMN_REG0064, ROPLL_SDM_NUM_SIGN_RBR_MASK, -+ ROPLL_SDM_NUM_SIGN_RBR(cfg->sdm_num_sign)); -+ hdptx_write(hdptx, CMN_REG0065, cfg->sdm_num); -+ hdptx_write(hdptx, CMN_REG0060, cfg->sdm_deno); -+ -+ hdptx_update_bits(hdptx, CMN_REG0069, ROPLL_SDC_N_RBR_MASK, -+ ROPLL_SDC_N_RBR(cfg->sdc_n)); -+ -+ hdptx_write(hdptx, CMN_REG006C, cfg->sdc_num); -+ hdptx_write(hdptx, CMN_REG0070, cfg->sdc_deno); -+ -+ hdptx_write(hdptx, CMN_REG006B, 0x04); -+ -+ hdptx_write(hdptx, CMN_REG0073, 0x30); -+ hdptx_write(hdptx, CMN_REG0074, 0x04); -+ hdptx_write(hdptx, CMN_REG0075, 0x20); -+ hdptx_write(hdptx, CMN_REG0076, 0x30); -+ hdptx_write(hdptx, CMN_REG0077, 0x08); -+ hdptx_write(hdptx, CMN_REG0078, 0x0c); -+ hdptx_write(hdptx, CMN_REG0079, 0x00); -+ hdptx_write(hdptx, CMN_REG007B, 0x00); -+ hdptx_write(hdptx, CMN_REG007C, 0x00); -+ hdptx_write(hdptx, CMN_REG007D, 0x00); -+ hdptx_write(hdptx, CMN_REG007E, 0x00); -+ hdptx_write(hdptx, CMN_REG007F, 0x00); -+ hdptx_write(hdptx, CMN_REG0080, 0x00); -+ hdptx_write(hdptx, CMN_REG0081, 0x01); -+ hdptx_write(hdptx, CMN_REG0082, 0x04); -+ hdptx_write(hdptx, CMN_REG0083, 0x24); -+ hdptx_write(hdptx, CMN_REG0084, 0x20); -+ hdptx_write(hdptx, CMN_REG0085, 0x03); -+ -+ hdptx_update_bits(hdptx, CMN_REG0086, PLL_PCG_POSTDIV_SEL_MASK, -+ PLL_PCG_POSTDIV_SEL(cfg->pms_sdiv)); -+ -+ hdptx_update_bits(hdptx, CMN_REG0086, PLL_PCG_CLK_SEL_MASK, -+ PLL_PCG_CLK_SEL(color_depth)); -+ -+ hdptx_update_bits(hdptx, CMN_REG0086, PLL_PCG_CLK_EN, PLL_PCG_CLK_EN); -+ -+ hdptx_write(hdptx, CMN_REG0087, 0x04); -+ hdptx_write(hdptx, CMN_REG0089, 0x00); -+ hdptx_write(hdptx, CMN_REG008A, 0x55); -+ hdptx_write(hdptx, CMN_REG008B, 0x25); -+ hdptx_write(hdptx, CMN_REG008C, 0x2c); -+ hdptx_write(hdptx, CMN_REG008D, 0x22); -+ hdptx_write(hdptx, CMN_REG008E, 0x14); -+ hdptx_write(hdptx, CMN_REG008F, 0x20); -+ hdptx_write(hdptx, CMN_REG0090, 0x00); -+ hdptx_write(hdptx, CMN_REG0091, 0x00); -+ hdptx_write(hdptx, CMN_REG0092, 0x00); -+ hdptx_write(hdptx, CMN_REG0093, 0x00); -+ hdptx_write(hdptx, CMN_REG0095, 0x00); -+ hdptx_write(hdptx, CMN_REG0097, 0x02); -+ hdptx_write(hdptx, CMN_REG0099, 0x04); -+ hdptx_write(hdptx, CMN_REG009A, 0x11); -+ hdptx_write(hdptx, CMN_REG009B, 0x00); -+ -+ return hdptx_post_enable_pll(hdptx); -+} -+ -+static int hdptx_ropll_tmds_mode_config(struct rockchip_hdptx_phy *hdptx, u32 rate) -+{ -+ u32 bit_rate = rate & DATA_RATE_MASK; -+ -+ if (!(hdptx_grf_read(hdptx, GRF_HDPTX_STATUS) & HDPTX_O_PLL_LOCK_DONE)) { -+ int ret; -+ -+ ret = hdptx_ropll_cmn_config(hdptx, bit_rate); -+ if (ret) -+ return ret; -+ } -+ -+ hdptx_write(hdptx, SB_REG0114, 0x00); -+ hdptx_write(hdptx, SB_REG0115, 0x00); -+ hdptx_write(hdptx, SB_REG0116, 0x00); -+ hdptx_write(hdptx, SB_REG0117, 0x00); -+ hdptx_write(hdptx, LNTOP_REG0200, 0x06); -+ -+ if (bit_rate >= 3400000) { -+ /* For 1/40 bitrate clk */ -+ hdptx_write(hdptx, LNTOP_REG0201, 0x00); -+ hdptx_write(hdptx, LNTOP_REG0202, 0x00); -+ hdptx_write(hdptx, LNTOP_REG0203, 0x0f); -+ hdptx_write(hdptx, LNTOP_REG0204, 0xff); -+ hdptx_write(hdptx, LNTOP_REG0205, 0xff); -+ } else { -+ /* For 1/10 bitrate clk */ -+ hdptx_write(hdptx, LNTOP_REG0201, 0x07); -+ hdptx_write(hdptx, LNTOP_REG0202, 0xc1); -+ hdptx_write(hdptx, LNTOP_REG0203, 0xf0); -+ hdptx_write(hdptx, LNTOP_REG0204, 0x7c); -+ hdptx_write(hdptx, LNTOP_REG0205, 0x1f); -+ } -+ -+ hdptx_write(hdptx, LNTOP_REG0206, 0x07); -+ hdptx_write(hdptx, LNTOP_REG0207, 0x0f); -+ hdptx_write(hdptx, LANE_REG0303, 0x0c); -+ hdptx_write(hdptx, LANE_REG0307, 0x20); -+ hdptx_write(hdptx, LANE_REG030A, 0x17); -+ hdptx_write(hdptx, LANE_REG030B, 0x77); -+ hdptx_write(hdptx, LANE_REG030C, 0x77); -+ hdptx_write(hdptx, LANE_REG030D, 0x77); -+ hdptx_write(hdptx, LANE_REG030E, 0x38); -+ hdptx_write(hdptx, LANE_REG0310, 0x03); -+ hdptx_write(hdptx, LANE_REG0311, 0x0f); -+ hdptx_write(hdptx, LANE_REG0312, 0x00); -+ hdptx_write(hdptx, LANE_REG0316, 0x02); -+ hdptx_write(hdptx, LANE_REG031B, 0x01); -+ hdptx_write(hdptx, LANE_REG031E, 0x00); -+ hdptx_write(hdptx, LANE_REG031F, 0x15); -+ hdptx_write(hdptx, LANE_REG0320, 0xa0); -+ hdptx_write(hdptx, LANE_REG0403, 0x0c); -+ hdptx_write(hdptx, LANE_REG0407, 0x20); -+ hdptx_write(hdptx, LANE_REG040A, 0x17); -+ hdptx_write(hdptx, LANE_REG040B, 0x77); -+ hdptx_write(hdptx, LANE_REG040C, 0x77); -+ hdptx_write(hdptx, LANE_REG040D, 0x77); -+ hdptx_write(hdptx, LANE_REG040E, 0x38); -+ hdptx_write(hdptx, LANE_REG0410, 0x03); -+ hdptx_write(hdptx, LANE_REG0411, 0x0f); -+ hdptx_write(hdptx, LANE_REG0412, 0x00); -+ hdptx_write(hdptx, LANE_REG0416, 0x02); -+ hdptx_write(hdptx, LANE_REG041B, 0x01); -+ hdptx_write(hdptx, LANE_REG041E, 0x00); -+ hdptx_write(hdptx, LANE_REG041F, 0x15); -+ hdptx_write(hdptx, LANE_REG0420, 0xa0); -+ hdptx_write(hdptx, LANE_REG0503, 0x0c); -+ hdptx_write(hdptx, LANE_REG0507, 0x20); -+ hdptx_write(hdptx, LANE_REG050A, 0x17); -+ hdptx_write(hdptx, LANE_REG050B, 0x77); -+ hdptx_write(hdptx, LANE_REG050C, 0x77); -+ hdptx_write(hdptx, LANE_REG050D, 0x77); -+ hdptx_write(hdptx, LANE_REG050E, 0x38); -+ hdptx_write(hdptx, LANE_REG0510, 0x03); -+ hdptx_write(hdptx, LANE_REG0511, 0x0f); -+ hdptx_write(hdptx, LANE_REG0512, 0x00); -+ hdptx_write(hdptx, LANE_REG0516, 0x02); -+ hdptx_write(hdptx, LANE_REG051B, 0x01); -+ hdptx_write(hdptx, LANE_REG051E, 0x00); -+ hdptx_write(hdptx, LANE_REG051F, 0x15); -+ hdptx_write(hdptx, LANE_REG0520, 0xa0); -+ hdptx_write(hdptx, LANE_REG0603, 0x0c); -+ hdptx_write(hdptx, LANE_REG0607, 0x20); -+ hdptx_write(hdptx, LANE_REG060A, 0x17); -+ hdptx_write(hdptx, LANE_REG060B, 0x77); -+ hdptx_write(hdptx, LANE_REG060C, 0x77); -+ hdptx_write(hdptx, LANE_REG060D, 0x77); -+ hdptx_write(hdptx, LANE_REG060E, 0x38); -+ hdptx_write(hdptx, LANE_REG0610, 0x03); -+ hdptx_write(hdptx, LANE_REG0611, 0x0f); -+ hdptx_write(hdptx, LANE_REG0612, 0x00); -+ hdptx_write(hdptx, LANE_REG0616, 0x02); -+ hdptx_write(hdptx, LANE_REG061B, 0x01); -+ hdptx_write(hdptx, LANE_REG061E, 0x08); -+ hdptx_write(hdptx, LANE_REG061F, 0x15); -+ hdptx_write(hdptx, LANE_REG0620, 0xa0); -+ -+ hdptx_write(hdptx, LANE_REG0303, 0x2f); -+ hdptx_write(hdptx, LANE_REG0403, 0x2f); -+ hdptx_write(hdptx, LANE_REG0503, 0x2f); -+ hdptx_write(hdptx, LANE_REG0603, 0x2f); -+ hdptx_write(hdptx, LANE_REG0305, 0x03); -+ hdptx_write(hdptx, LANE_REG0405, 0x03); -+ hdptx_write(hdptx, LANE_REG0505, 0x03); -+ hdptx_write(hdptx, LANE_REG0605, 0x03); -+ hdptx_write(hdptx, LANE_REG0306, 0x1c); -+ hdptx_write(hdptx, LANE_REG0406, 0x1c); -+ hdptx_write(hdptx, LANE_REG0506, 0x1c); -+ hdptx_write(hdptx, LANE_REG0606, 0x1c); -+ -+ if (hdptx->earc_en) -+ hdptx_earc_config(hdptx); -+ -+ return hdptx_post_enable_lane(hdptx); -+} -+ -+static int hdptx_ropll_frl_mode_config(struct rockchip_hdptx_phy *hdptx, u32 rate) -+{ -+ u32 bit_rate = rate & DATA_RATE_MASK; -+ u8 color_depth = (rate & COLOR_DEPTH_MASK) ? 1 : 0; -+ struct ropll_config *cfg = ropll_frl_cfg; -+ -+ for (; cfg->bit_rate != ~0; cfg++) -+ if (bit_rate == cfg->bit_rate) -+ break; -+ -+ if (cfg->bit_rate == ~0) { -+ dev_err(hdptx->dev, "%s can't find pll cfg\n", __func__); -+ return -EINVAL; -+ } -+ -+ hdptx_pre_power_up(hdptx); -+ -+ reset_control_assert(hdptx->ropll_reset); -+ usleep_range(10, 20); -+ reset_control_deassert(hdptx->ropll_reset); -+ -+ hdptx_write(hdptx, CMN_REG0008, 0x00); -+ hdptx_write(hdptx, CMN_REG0009, 0x0c); -+ hdptx_write(hdptx, CMN_REG000A, 0x83); -+ hdptx_write(hdptx, CMN_REG000B, 0x06); -+ hdptx_write(hdptx, CMN_REG000C, 0x20); -+ hdptx_write(hdptx, CMN_REG000D, 0xb8); -+ hdptx_write(hdptx, CMN_REG000E, 0x0f); -+ hdptx_write(hdptx, CMN_REG000F, 0x0f); -+ hdptx_write(hdptx, CMN_REG0010, 0x04); -+ hdptx_write(hdptx, CMN_REG0011, 0x00); -+ hdptx_write(hdptx, CMN_REG0012, 0x26); -+ hdptx_write(hdptx, CMN_REG0013, 0x22); -+ hdptx_write(hdptx, CMN_REG0014, 0x24); -+ hdptx_write(hdptx, CMN_REG0015, 0x77); -+ hdptx_write(hdptx, CMN_REG0016, 0x08); -+ hdptx_write(hdptx, CMN_REG0017, 0x00); -+ hdptx_write(hdptx, CMN_REG0018, 0x04); -+ hdptx_write(hdptx, CMN_REG0019, 0x48); -+ hdptx_write(hdptx, CMN_REG001A, 0x01); -+ hdptx_write(hdptx, CMN_REG001B, 0x00); -+ hdptx_write(hdptx, CMN_REG001C, 0x01); -+ hdptx_write(hdptx, CMN_REG001D, 0x64); -+ hdptx_write(hdptx, CMN_REG001E, 0x14); -+ hdptx_write(hdptx, CMN_REG001F, 0x00); -+ hdptx_write(hdptx, CMN_REG0020, 0x00); -+ hdptx_write(hdptx, CMN_REG0021, 0x00); -+ hdptx_write(hdptx, CMN_REG0022, 0x11); -+ hdptx_write(hdptx, CMN_REG0023, 0x00); -+ hdptx_write(hdptx, CMN_REG0025, 0x00); -+ hdptx_write(hdptx, CMN_REG0026, 0x53); -+ hdptx_write(hdptx, CMN_REG0027, 0x00); -+ hdptx_write(hdptx, CMN_REG0028, 0x00); -+ hdptx_write(hdptx, CMN_REG0029, 0x01); -+ hdptx_write(hdptx, CMN_REG002A, 0x01); -+ hdptx_write(hdptx, CMN_REG002B, 0x00); -+ hdptx_write(hdptx, CMN_REG002C, 0x00); -+ hdptx_write(hdptx, CMN_REG002D, 0x00); -+ hdptx_write(hdptx, CMN_REG002E, 0x00); -+ hdptx_write(hdptx, CMN_REG002F, 0x04); -+ hdptx_write(hdptx, CMN_REG0030, 0x00); -+ hdptx_write(hdptx, CMN_REG0031, 0x20); -+ hdptx_write(hdptx, CMN_REG0032, 0x30); -+ hdptx_write(hdptx, CMN_REG0033, 0x0b); -+ hdptx_write(hdptx, CMN_REG0034, 0x23); -+ hdptx_write(hdptx, CMN_REG0035, 0x00); -+ hdptx_write(hdptx, CMN_REG0038, 0x00); -+ hdptx_write(hdptx, CMN_REG0039, 0x00); -+ hdptx_write(hdptx, CMN_REG003A, 0x00); -+ hdptx_write(hdptx, CMN_REG003B, 0x00); -+ hdptx_write(hdptx, CMN_REG003C, 0x80); -+ hdptx_write(hdptx, CMN_REG003D, 0x40); -+ hdptx_write(hdptx, CMN_REG003E, 0x0c); -+ hdptx_write(hdptx, CMN_REG003F, 0x83); -+ hdptx_write(hdptx, CMN_REG0040, 0x06); -+ hdptx_write(hdptx, CMN_REG0041, 0x20); -+ hdptx_write(hdptx, CMN_REG0042, 0xb8); -+ hdptx_write(hdptx, CMN_REG0043, 0x00); -+ hdptx_write(hdptx, CMN_REG0044, 0x46); -+ hdptx_write(hdptx, CMN_REG0045, 0x24); -+ hdptx_write(hdptx, CMN_REG0046, 0xff); -+ hdptx_write(hdptx, CMN_REG0047, 0x00); -+ hdptx_write(hdptx, CMN_REG0048, 0x44); -+ hdptx_write(hdptx, CMN_REG0049, 0xfa); -+ hdptx_write(hdptx, CMN_REG004A, 0x08); -+ hdptx_write(hdptx, CMN_REG004B, 0x00); -+ hdptx_write(hdptx, CMN_REG004C, 0x01); -+ hdptx_write(hdptx, CMN_REG004D, 0x64); -+ hdptx_write(hdptx, CMN_REG004E, 0x14); -+ hdptx_write(hdptx, CMN_REG004F, 0x00); -+ hdptx_write(hdptx, CMN_REG0050, 0x00); -+ hdptx_write(hdptx, CMN_REG0051, cfg->pms_mdiv); -+ hdptx_write(hdptx, CMN_REG0055, cfg->pms_mdiv_afc); -+ hdptx_write(hdptx, CMN_REG0059, (cfg->pms_pdiv << 4) | cfg->pms_refdiv); -+ hdptx_write(hdptx, CMN_REG005A, (cfg->pms_sdiv << 4)); -+ hdptx_write(hdptx, CMN_REG005C, 0x25); -+ hdptx_write(hdptx, CMN_REG005D, 0x0c); -+ hdptx_update_bits(hdptx, CMN_REG005E, ROPLL_SDM_EN_MASK, -+ ROPLL_SDM_EN(cfg->sdm_en)); -+ if (!cfg->sdm_en) -+ hdptx_update_bits(hdptx, CMN_REG005E, 0xf, 0); -+ hdptx_write(hdptx, CMN_REG005F, 0x01); -+ hdptx_update_bits(hdptx, CMN_REG0064, ROPLL_SDM_NUM_SIGN_RBR_MASK, -+ ROPLL_SDM_NUM_SIGN_RBR(cfg->sdm_num_sign)); -+ hdptx_write(hdptx, CMN_REG0065, cfg->sdm_num); -+ hdptx_write(hdptx, CMN_REG0060, cfg->sdm_deno); -+ hdptx_update_bits(hdptx, CMN_REG0069, ROPLL_SDC_N_RBR_MASK, -+ ROPLL_SDC_N_RBR(cfg->sdc_n)); -+ hdptx_write(hdptx, CMN_REG006C, cfg->sdc_num); -+ hdptx_write(hdptx, CMN_REG0070, cfg->sdc_deno); -+ hdptx_write(hdptx, CMN_REG006B, 0x04); -+ hdptx_write(hdptx, CMN_REG0073, 0x30); -+ hdptx_write(hdptx, CMN_REG0074, 0x00); -+ hdptx_write(hdptx, CMN_REG0075, 0x20); -+ hdptx_write(hdptx, CMN_REG0076, 0x30); -+ hdptx_write(hdptx, CMN_REG0077, 0x08); -+ hdptx_write(hdptx, CMN_REG0078, 0x0c); -+ hdptx_write(hdptx, CMN_REG0079, 0x00); -+ hdptx_write(hdptx, CMN_REG007B, 0x00); -+ hdptx_write(hdptx, CMN_REG007C, 0x00); -+ hdptx_write(hdptx, CMN_REG007D, 0x00); -+ hdptx_write(hdptx, CMN_REG007E, 0x00); -+ hdptx_write(hdptx, CMN_REG007F, 0x00); -+ hdptx_write(hdptx, CMN_REG0080, 0x00); -+ hdptx_write(hdptx, CMN_REG0081, 0x09); -+ hdptx_write(hdptx, CMN_REG0082, 0x04); -+ hdptx_write(hdptx, CMN_REG0083, 0x24); -+ hdptx_write(hdptx, CMN_REG0084, 0x20); -+ hdptx_write(hdptx, CMN_REG0085, 0x03); -+ hdptx_write(hdptx, CMN_REG0086, 0x01); -+ hdptx_update_bits(hdptx, CMN_REG0086, PLL_PCG_POSTDIV_SEL_MASK, -+ PLL_PCG_POSTDIV_SEL(cfg->pms_sdiv)); -+ hdptx_update_bits(hdptx, CMN_REG0086, PLL_PCG_CLK_SEL_MASK, -+ PLL_PCG_CLK_SEL(color_depth)); -+ hdptx_write(hdptx, CMN_REG0087, 0x0c); -+ hdptx_write(hdptx, CMN_REG0089, 0x00); -+ hdptx_write(hdptx, CMN_REG008A, 0x55); -+ hdptx_write(hdptx, CMN_REG008B, 0x25); -+ hdptx_write(hdptx, CMN_REG008C, 0x2c); -+ hdptx_write(hdptx, CMN_REG008D, 0x22); -+ hdptx_write(hdptx, CMN_REG008E, 0x14); -+ hdptx_write(hdptx, CMN_REG008F, 0x20); -+ hdptx_write(hdptx, CMN_REG0090, 0x00); -+ hdptx_write(hdptx, CMN_REG0091, 0x00); -+ hdptx_write(hdptx, CMN_REG0092, 0x00); -+ hdptx_write(hdptx, CMN_REG0093, 0x00); -+ hdptx_write(hdptx, CMN_REG0094, 0x00); -+ hdptx_write(hdptx, CMN_REG0097, 0x02); -+ hdptx_write(hdptx, CMN_REG0099, 0x04); -+ hdptx_write(hdptx, CMN_REG009A, 0x11); -+ hdptx_write(hdptx, CMN_REG009B, 0x10); -+ hdptx_write(hdptx, SB_REG0114, 0x00); -+ hdptx_write(hdptx, SB_REG0115, 0x00); -+ hdptx_write(hdptx, SB_REG0116, 0x00); -+ hdptx_write(hdptx, SB_REG0117, 0x00); -+ hdptx_write(hdptx, LNTOP_REG0200, 0x04); -+ hdptx_write(hdptx, LNTOP_REG0201, 0x00); -+ hdptx_write(hdptx, LNTOP_REG0202, 0x00); -+ hdptx_write(hdptx, LNTOP_REG0203, 0xf0); -+ hdptx_write(hdptx, LNTOP_REG0204, 0xff); -+ hdptx_write(hdptx, LNTOP_REG0205, 0xff); -+ hdptx_write(hdptx, LNTOP_REG0206, 0x05); -+ hdptx_write(hdptx, LNTOP_REG0207, 0x0f); -+ hdptx_write(hdptx, LANE_REG0303, 0x0c); -+ hdptx_write(hdptx, LANE_REG0307, 0x20); -+ hdptx_write(hdptx, LANE_REG030A, 0x17); -+ hdptx_write(hdptx, LANE_REG030B, 0x77); -+ hdptx_write(hdptx, LANE_REG030C, 0x77); -+ hdptx_write(hdptx, LANE_REG030D, 0x77); -+ hdptx_write(hdptx, LANE_REG030E, 0x38); -+ hdptx_write(hdptx, LANE_REG0310, 0x03); -+ hdptx_write(hdptx, LANE_REG0311, 0x0f); -+ hdptx_write(hdptx, LANE_REG0312, 0x3c); -+ hdptx_write(hdptx, LANE_REG0316, 0x02); -+ hdptx_write(hdptx, LANE_REG031B, 0x01); -+ hdptx_write(hdptx, LANE_REG031F, 0x15); -+ hdptx_write(hdptx, LANE_REG0320, 0xa0); -+ hdptx_write(hdptx, LANE_REG0403, 0x0c); -+ hdptx_write(hdptx, LANE_REG0407, 0x20); -+ hdptx_write(hdptx, LANE_REG040A, 0x17); -+ hdptx_write(hdptx, LANE_REG040B, 0x77); -+ hdptx_write(hdptx, LANE_REG040C, 0x77); -+ hdptx_write(hdptx, LANE_REG040D, 0x77); -+ hdptx_write(hdptx, LANE_REG040E, 0x38); -+ hdptx_write(hdptx, LANE_REG0410, 0x03); -+ hdptx_write(hdptx, LANE_REG0411, 0x0f); -+ hdptx_write(hdptx, LANE_REG0412, 0x3c); -+ hdptx_write(hdptx, LANE_REG0416, 0x02); -+ hdptx_write(hdptx, LANE_REG041B, 0x01); -+ hdptx_write(hdptx, LANE_REG041F, 0x15); -+ hdptx_write(hdptx, LANE_REG0420, 0xa0); -+ hdptx_write(hdptx, LANE_REG0503, 0x0c); -+ hdptx_write(hdptx, LANE_REG0507, 0x20); -+ hdptx_write(hdptx, LANE_REG050A, 0x17); -+ hdptx_write(hdptx, LANE_REG050B, 0x77); -+ hdptx_write(hdptx, LANE_REG050C, 0x77); -+ hdptx_write(hdptx, LANE_REG050D, 0x77); -+ hdptx_write(hdptx, LANE_REG050E, 0x38); -+ hdptx_write(hdptx, LANE_REG0510, 0x03); -+ hdptx_write(hdptx, LANE_REG0511, 0x0f); -+ hdptx_write(hdptx, LANE_REG0512, 0x3c); -+ hdptx_write(hdptx, LANE_REG0516, 0x02); -+ hdptx_write(hdptx, LANE_REG051B, 0x01); -+ hdptx_write(hdptx, LANE_REG051F, 0x15); -+ hdptx_write(hdptx, LANE_REG0520, 0xa0); -+ hdptx_write(hdptx, LANE_REG0603, 0x0c); -+ hdptx_write(hdptx, LANE_REG0607, 0x20); -+ hdptx_write(hdptx, LANE_REG060A, 0x17); -+ hdptx_write(hdptx, LANE_REG060B, 0x77); -+ hdptx_write(hdptx, LANE_REG060C, 0x77); -+ hdptx_write(hdptx, LANE_REG060D, 0x77); -+ hdptx_write(hdptx, LANE_REG060E, 0x38); -+ hdptx_write(hdptx, LANE_REG0610, 0x03); -+ hdptx_write(hdptx, LANE_REG0611, 0x0f); -+ hdptx_write(hdptx, LANE_REG0612, 0x3c); -+ hdptx_write(hdptx, LANE_REG0616, 0x02); -+ hdptx_write(hdptx, LANE_REG061B, 0x01); -+ hdptx_write(hdptx, LANE_REG061F, 0x15); -+ hdptx_write(hdptx, LANE_REG0620, 0xa0); -+ -+ if (hdptx->earc_en) -+ hdptx_earc_config(hdptx); -+ -+ return hdptx_post_power_up(hdptx); -+} -+ -+static int hdptx_lcpll_frl_mode_config(struct rockchip_hdptx_phy *hdptx, u32 rate) -+{ -+ u32 bit_rate = rate & DATA_RATE_MASK; -+ u8 color_depth = (rate & COLOR_DEPTH_MASK) ? 1 : 0; -+ struct lcpll_config *cfg = lcpll_cfg; -+ -+ for (; cfg->bit_rate != ~0; cfg++) -+ if (bit_rate == cfg->bit_rate) -+ break; -+ -+ if (cfg->bit_rate == ~0) -+ return -EINVAL; -+ -+ hdptx_pre_power_up(hdptx); -+ -+ hdptx_update_bits(hdptx, CMN_REG0008, LCPLL_EN_MASK | -+ LCPLL_LCVCO_MODE_EN_MASK, LCPLL_EN(1) | -+ LCPLL_LCVCO_MODE_EN(cfg->lcvco_mode_en)); -+ hdptx_write(hdptx, CMN_REG0009, 0x0c); -+ hdptx_write(hdptx, CMN_REG000A, 0x83); -+ hdptx_write(hdptx, CMN_REG000B, 0x06); -+ hdptx_write(hdptx, CMN_REG000C, 0x20); -+ hdptx_write(hdptx, CMN_REG000D, 0xb8); -+ hdptx_write(hdptx, CMN_REG000E, 0x0f); -+ hdptx_write(hdptx, CMN_REG000F, 0x0f); -+ hdptx_write(hdptx, CMN_REG0010, 0x04); -+ hdptx_write(hdptx, CMN_REG0011, 0x00); -+ hdptx_write(hdptx, CMN_REG0012, 0x26); -+ hdptx_write(hdptx, CMN_REG0013, 0x22); -+ hdptx_write(hdptx, CMN_REG0014, 0x24); -+ hdptx_write(hdptx, CMN_REG0015, 0x77); -+ hdptx_write(hdptx, CMN_REG0016, 0x08); -+ hdptx_write(hdptx, CMN_REG0017, 0x00); -+ hdptx_write(hdptx, CMN_REG0018, 0x04); -+ hdptx_write(hdptx, CMN_REG0019, 0x48); -+ hdptx_write(hdptx, CMN_REG001A, 0x01); -+ hdptx_write(hdptx, CMN_REG001B, 0x00); -+ hdptx_write(hdptx, CMN_REG001C, 0x01); -+ hdptx_write(hdptx, CMN_REG001D, 0x64); -+ hdptx_update_bits(hdptx, CMN_REG001E, LCPLL_PI_EN_MASK | -+ LCPLL_100M_CLK_EN_MASK, -+ LCPLL_PI_EN(cfg->pi_en) | -+ LCPLL_100M_CLK_EN(cfg->clk_en_100m)); -+ hdptx_write(hdptx, CMN_REG001F, 0x00); -+ hdptx_write(hdptx, CMN_REG0020, cfg->pms_mdiv); -+ hdptx_write(hdptx, CMN_REG0021, cfg->pms_mdiv_afc); -+ hdptx_write(hdptx, CMN_REG0022, (cfg->pms_pdiv << 4) | cfg->pms_refdiv); -+ hdptx_write(hdptx, CMN_REG0023, (cfg->pms_sdiv << 4) | cfg->pms_sdiv); -+ hdptx_write(hdptx, CMN_REG0025, 0x10); -+ hdptx_write(hdptx, CMN_REG0026, 0x53); -+ hdptx_write(hdptx, CMN_REG0027, 0x01); -+ hdptx_write(hdptx, CMN_REG0028, 0x0d); -+ hdptx_write(hdptx, CMN_REG0029, 0x01); -+ hdptx_write(hdptx, CMN_REG002A, cfg->sdm_deno); -+ hdptx_write(hdptx, CMN_REG002B, cfg->sdm_num_sign); -+ hdptx_write(hdptx, CMN_REG002C, cfg->sdm_num); -+ hdptx_update_bits(hdptx, CMN_REG002D, LCPLL_SDC_N_MASK, -+ LCPLL_SDC_N(cfg->sdc_n)); -+ hdptx_write(hdptx, CMN_REG002E, 0x02); -+ hdptx_write(hdptx, CMN_REG002F, 0x0d); -+ hdptx_write(hdptx, CMN_REG0030, 0x00); -+ hdptx_write(hdptx, CMN_REG0031, 0x20); -+ hdptx_write(hdptx, CMN_REG0032, 0x30); -+ hdptx_write(hdptx, CMN_REG0033, 0x0b); -+ hdptx_write(hdptx, CMN_REG0034, 0x23); -+ hdptx_write(hdptx, CMN_REG0035, 0x00); -+ hdptx_write(hdptx, CMN_REG0038, 0x00); -+ hdptx_write(hdptx, CMN_REG0039, 0x00); -+ hdptx_write(hdptx, CMN_REG003A, 0x00); -+ hdptx_write(hdptx, CMN_REG003B, 0x00); -+ hdptx_write(hdptx, CMN_REG003C, 0x80); -+ hdptx_write(hdptx, CMN_REG003D, 0x00); -+ hdptx_write(hdptx, CMN_REG003E, 0x0c); -+ hdptx_write(hdptx, CMN_REG003F, 0x83); -+ hdptx_write(hdptx, CMN_REG0040, 0x06); -+ hdptx_write(hdptx, CMN_REG0041, 0x20); -+ hdptx_write(hdptx, CMN_REG0042, 0xb8); -+ hdptx_write(hdptx, CMN_REG0043, 0x00); -+ hdptx_write(hdptx, CMN_REG0044, 0x46); -+ hdptx_write(hdptx, CMN_REG0045, 0x24); -+ hdptx_write(hdptx, CMN_REG0046, 0xff); -+ hdptx_write(hdptx, CMN_REG0047, 0x00); -+ hdptx_write(hdptx, CMN_REG0048, 0x44); -+ hdptx_write(hdptx, CMN_REG0049, 0xfa); -+ hdptx_write(hdptx, CMN_REG004A, 0x08); -+ hdptx_write(hdptx, CMN_REG004B, 0x00); -+ hdptx_write(hdptx, CMN_REG004C, 0x01); -+ hdptx_write(hdptx, CMN_REG004D, 0x64); -+ hdptx_write(hdptx, CMN_REG004E, 0x14); -+ hdptx_write(hdptx, CMN_REG004F, 0x00); -+ hdptx_write(hdptx, CMN_REG0050, 0x00); -+ hdptx_write(hdptx, CMN_REG0051, 0x00); -+ hdptx_write(hdptx, CMN_REG0055, 0x00); -+ hdptx_write(hdptx, CMN_REG0059, 0x11); -+ hdptx_write(hdptx, CMN_REG005A, 0x03); -+ hdptx_write(hdptx, CMN_REG005C, 0x05); -+ hdptx_write(hdptx, CMN_REG005D, 0x0c); -+ hdptx_write(hdptx, CMN_REG005E, 0x07); -+ hdptx_write(hdptx, CMN_REG005F, 0x01); -+ hdptx_write(hdptx, CMN_REG0060, 0x01); -+ hdptx_write(hdptx, CMN_REG0064, 0x07); -+ hdptx_write(hdptx, CMN_REG0065, 0x00); -+ hdptx_write(hdptx, CMN_REG0069, 0x00); -+ hdptx_write(hdptx, CMN_REG006B, 0x04); -+ hdptx_write(hdptx, CMN_REG006C, 0x00); -+ hdptx_write(hdptx, CMN_REG0070, 0x01); -+ hdptx_write(hdptx, CMN_REG0073, 0x30); -+ hdptx_write(hdptx, CMN_REG0074, 0x00); -+ hdptx_write(hdptx, CMN_REG0075, 0x20); -+ hdptx_write(hdptx, CMN_REG0076, 0x30); -+ hdptx_write(hdptx, CMN_REG0077, 0x08); -+ hdptx_write(hdptx, CMN_REG0078, 0x0c); -+ hdptx_write(hdptx, CMN_REG0079, 0x00); -+ hdptx_write(hdptx, CMN_REG007B, 0x00); -+ hdptx_write(hdptx, CMN_REG007C, 0x00); -+ hdptx_write(hdptx, CMN_REG007D, 0x00); -+ hdptx_write(hdptx, CMN_REG007E, 0x00); -+ hdptx_write(hdptx, CMN_REG007F, 0x00); -+ hdptx_write(hdptx, CMN_REG0080, 0x00); -+ hdptx_write(hdptx, CMN_REG0081, 0x09); -+ hdptx_write(hdptx, CMN_REG0082, 0x04); -+ hdptx_write(hdptx, CMN_REG0083, 0x24); -+ hdptx_write(hdptx, CMN_REG0084, 0x20); -+ hdptx_write(hdptx, CMN_REG0085, 0x03); -+ hdptx_write(hdptx, CMN_REG0086, 0x01); -+ hdptx_update_bits(hdptx, CMN_REG0086, PLL_PCG_POSTDIV_SEL_MASK, -+ PLL_PCG_POSTDIV_SEL(cfg->pms_sdiv)); -+ hdptx_update_bits(hdptx, CMN_REG0086, PLL_PCG_CLK_SEL_MASK, -+ PLL_PCG_CLK_SEL(color_depth)); -+ hdptx_write(hdptx, CMN_REG0087, 0x0c); -+ hdptx_write(hdptx, CMN_REG0089, 0x02); -+ hdptx_write(hdptx, CMN_REG008A, 0x55); -+ hdptx_write(hdptx, CMN_REG008B, 0x25); -+ hdptx_write(hdptx, CMN_REG008C, 0x2c); -+ hdptx_write(hdptx, CMN_REG008D, 0x22); -+ hdptx_write(hdptx, CMN_REG008E, 0x14); -+ hdptx_write(hdptx, CMN_REG008F, 0x20); -+ hdptx_write(hdptx, CMN_REG0090, 0x00); -+ hdptx_write(hdptx, CMN_REG0091, 0x00); -+ hdptx_write(hdptx, CMN_REG0092, 0x00); -+ hdptx_write(hdptx, CMN_REG0093, 0x00); -+ hdptx_write(hdptx, CMN_REG0095, 0x00); -+ hdptx_write(hdptx, CMN_REG0097, 0x00); -+ hdptx_write(hdptx, CMN_REG0099, 0x00); -+ hdptx_write(hdptx, CMN_REG009A, 0x11); -+ hdptx_write(hdptx, CMN_REG009B, 0x10); -+ hdptx_write(hdptx, SB_REG0114, 0x00); -+ hdptx_write(hdptx, SB_REG0115, 0x00); -+ hdptx_write(hdptx, SB_REG0116, 0x00); -+ hdptx_write(hdptx, SB_REG0117, 0x00); -+ hdptx_write(hdptx, LNTOP_REG0200, 0x04); -+ hdptx_write(hdptx, LNTOP_REG0201, 0x00); -+ hdptx_write(hdptx, LNTOP_REG0202, 0x00); -+ hdptx_write(hdptx, LNTOP_REG0203, 0xf0); -+ hdptx_write(hdptx, LNTOP_REG0204, 0xff); -+ hdptx_write(hdptx, LNTOP_REG0205, 0xff); -+ hdptx_write(hdptx, LNTOP_REG0206, 0x05); -+ hdptx_write(hdptx, LNTOP_REG0207, 0x0f); -+ hdptx_write(hdptx, LANE_REG0303, 0x0c); -+ hdptx_write(hdptx, LANE_REG0307, 0x20); -+ hdptx_write(hdptx, LANE_REG030A, 0x17); -+ hdptx_write(hdptx, LANE_REG030B, 0x77); -+ hdptx_write(hdptx, LANE_REG030C, 0x77); -+ hdptx_write(hdptx, LANE_REG030D, 0x77); -+ hdptx_write(hdptx, LANE_REG030E, 0x38); -+ hdptx_write(hdptx, LANE_REG0310, 0x03); -+ hdptx_write(hdptx, LANE_REG0311, 0x0f); -+ hdptx_write(hdptx, LANE_REG0312, 0x3c); -+ hdptx_write(hdptx, LANE_REG0316, 0x02); -+ hdptx_write(hdptx, LANE_REG031B, 0x01); -+ hdptx_write(hdptx, LANE_REG031F, 0x15); -+ hdptx_write(hdptx, LANE_REG0320, 0xa0); -+ hdptx_write(hdptx, LANE_REG0403, 0x0c); -+ hdptx_write(hdptx, LANE_REG0407, 0x20); -+ hdptx_write(hdptx, LANE_REG040A, 0x17); -+ hdptx_write(hdptx, LANE_REG040B, 0x77); -+ hdptx_write(hdptx, LANE_REG040C, 0x77); -+ hdptx_write(hdptx, LANE_REG040D, 0x77); -+ hdptx_write(hdptx, LANE_REG040E, 0x38); -+ hdptx_write(hdptx, LANE_REG0410, 0x03); -+ hdptx_write(hdptx, LANE_REG0411, 0x0f); -+ hdptx_write(hdptx, LANE_REG0412, 0x3c); -+ hdptx_write(hdptx, LANE_REG0416, 0x02); -+ hdptx_write(hdptx, LANE_REG041B, 0x01); -+ hdptx_write(hdptx, LANE_REG041F, 0x15); -+ hdptx_write(hdptx, LANE_REG0420, 0xa0); -+ hdptx_write(hdptx, LANE_REG0503, 0x0c); -+ hdptx_write(hdptx, LANE_REG0507, 0x20); -+ hdptx_write(hdptx, LANE_REG050A, 0x17); -+ hdptx_write(hdptx, LANE_REG050B, 0x77); -+ hdptx_write(hdptx, LANE_REG050C, 0x77); -+ hdptx_write(hdptx, LANE_REG050D, 0x77); -+ hdptx_write(hdptx, LANE_REG050E, 0x38); -+ hdptx_write(hdptx, LANE_REG0510, 0x03); -+ hdptx_write(hdptx, LANE_REG0511, 0x0f); -+ hdptx_write(hdptx, LANE_REG0512, 0x3c); -+ hdptx_write(hdptx, LANE_REG0516, 0x02); -+ hdptx_write(hdptx, LANE_REG051B, 0x01); -+ hdptx_write(hdptx, LANE_REG051F, 0x15); -+ hdptx_write(hdptx, LANE_REG0520, 0xa0); -+ hdptx_write(hdptx, LANE_REG0603, 0x0c); -+ hdptx_write(hdptx, LANE_REG0607, 0x20); -+ hdptx_write(hdptx, LANE_REG060A, 0x17); -+ hdptx_write(hdptx, LANE_REG060B, 0x77); -+ hdptx_write(hdptx, LANE_REG060C, 0x77); -+ hdptx_write(hdptx, LANE_REG060D, 0x77); -+ hdptx_write(hdptx, LANE_REG060E, 0x38); -+ hdptx_write(hdptx, LANE_REG0610, 0x03); -+ hdptx_write(hdptx, LANE_REG0611, 0x0f); -+ hdptx_write(hdptx, LANE_REG0612, 0x3c); -+ hdptx_write(hdptx, LANE_REG0616, 0x02); -+ hdptx_write(hdptx, LANE_REG061B, 0x01); -+ hdptx_write(hdptx, LANE_REG061F, 0x15); -+ hdptx_write(hdptx, LANE_REG0620, 0xa0); -+ -+ hdptx_write(hdptx, LANE_REG0303, 0x2f); -+ hdptx_write(hdptx, LANE_REG0403, 0x2f); -+ hdptx_write(hdptx, LANE_REG0503, 0x2f); -+ hdptx_write(hdptx, LANE_REG0603, 0x2f); -+ hdptx_write(hdptx, LANE_REG0305, 0x03); -+ hdptx_write(hdptx, LANE_REG0405, 0x03); -+ hdptx_write(hdptx, LANE_REG0505, 0x03); -+ hdptx_write(hdptx, LANE_REG0605, 0x03); -+ hdptx_write(hdptx, LANE_REG0306, 0xfc); -+ hdptx_write(hdptx, LANE_REG0406, 0xfc); -+ hdptx_write(hdptx, LANE_REG0506, 0xfc); -+ hdptx_write(hdptx, LANE_REG0606, 0xfc); -+ -+ hdptx_write(hdptx, LANE_REG0305, 0x4f); -+ hdptx_write(hdptx, LANE_REG0405, 0x4f); -+ hdptx_write(hdptx, LANE_REG0505, 0x4f); -+ hdptx_write(hdptx, LANE_REG0605, 0x4f); -+ hdptx_write(hdptx, LANE_REG0304, 0x14); -+ hdptx_write(hdptx, LANE_REG0404, 0x14); -+ hdptx_write(hdptx, LANE_REG0504, 0x14); -+ hdptx_write(hdptx, LANE_REG0604, 0x14); -+ -+ if (hdptx->earc_en) -+ hdptx_earc_config(hdptx); -+ -+ return hdptx_post_power_up(hdptx); -+} -+ -+static int rockchip_hdptx_phy_power_on(struct phy *phy) -+{ -+ struct rockchip_hdptx_phy *hdptx = phy_get_drvdata(phy); -+ int bus_width = phy_get_bus_width(hdptx->phy); -+ int bit_rate = bus_width & DATA_RATE_MASK; -+ int ret; -+ -+ if (!hdptx->count) { -+ ret = clk_bulk_enable(hdptx->nr_clks, hdptx->clks); -+ if (ret) { -+ dev_err(hdptx->dev, "failed to enable clocks\n"); -+ return ret; -+ } -+ } -+ -+ dev_info(hdptx->dev, "bus_width:0x%x,bit_rate:%d\n", bus_width, bit_rate); -+ if (bus_width & HDMI_EARC_MASK) -+ hdptx->earc_en = true; -+ else -+ hdptx->earc_en = false; -+ -+ if (bus_width & HDMI_MODE_MASK) { -+ if (bit_rate > 24000000) -+ return hdptx_lcpll_frl_mode_config(hdptx, bus_width); -+ else -+ return hdptx_ropll_frl_mode_config(hdptx, bus_width); -+ } else { -+ return hdptx_ropll_tmds_mode_config(hdptx, bus_width); -+ } -+} -+ -+static int rockchip_hdptx_phy_power_off(struct phy *phy) -+{ -+ struct rockchip_hdptx_phy *hdptx = phy_get_drvdata(phy); -+ -+ if (hdptx->count) -+ return 0; -+ -+ if (!(hdptx_grf_read(hdptx, GRF_HDPTX_STATUS) & HDPTX_O_PLL_LOCK_DONE)) -+ return 0; -+ -+ hdptx_phy_disable(hdptx); -+ clk_bulk_disable(hdptx->nr_clks, hdptx->clks); -+ -+ return 0; -+} -+ -+static const struct phy_ops rockchip_hdptx_phy_ops = { -+ .owner = THIS_MODULE, -+ .power_on = rockchip_hdptx_phy_power_on, -+ .power_off = rockchip_hdptx_phy_power_off, -+}; -+ -+static const struct of_device_id rockchip_hdptx_phy_of_match[] = { -+ { .compatible = "rockchip,rk3588-hdptx-phy-hdmi", -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, rockchip_hdptx_phy_of_match); -+ -+static void rockchip_hdptx_phy_runtime_disable(void *data) -+{ -+ struct rockchip_hdptx_phy *hdptx = data; -+ -+ clk_bulk_unprepare(hdptx->nr_clks, hdptx->clks); -+ pm_runtime_disable(hdptx->dev); -+} -+ -+static unsigned long hdptx_phy_clk_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct rockchip_hdptx_phy *hdptx = to_rockchip_hdptx_phy(hw); -+ -+ return hdptx->rate; -+} -+ -+static long hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *parent_rate) -+{ -+ struct ropll_config *cfg = ropll_tmds_cfg; -+ u32 bit_rate = rate / 100; -+ -+ if (rate > HDMI20_MAX_RATE) -+ return rate; -+ -+ for (; cfg->bit_rate != ~0; cfg++) -+ if (bit_rate == cfg->bit_rate) -+ break; -+ -+ if (cfg->bit_rate == ~0 && !hdptx_phy_clk_pll_calc(bit_rate, NULL)) -+ return -EINVAL; -+ -+ return rate; -+} -+ -+static int hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ struct rockchip_hdptx_phy *hdptx = to_rockchip_hdptx_phy(hw); -+ -+ if (hdptx_grf_read(hdptx, GRF_HDPTX_STATUS) & HDPTX_O_PLL_LOCK_DONE) -+ hdptx_phy_disable(hdptx); -+ -+ rate = rate / 100; -+ -+ return hdptx_ropll_cmn_config(hdptx, rate); -+} -+ -+static int hdptx_phy_clk_enable(struct clk_hw *hw) -+{ -+ struct rockchip_hdptx_phy *hdptx = to_rockchip_hdptx_phy(hw); -+ int ret; -+ -+ if (hdptx->count) { -+ hdptx->count++; -+ return 0; -+ } -+ -+ ret = clk_bulk_enable(hdptx->nr_clks, hdptx->clks); -+ if (ret) { -+ dev_err(hdptx->dev, "failed to enable clocks\n"); -+ return ret; -+ } -+ -+ if (hdptx->rate) { -+ ret = hdptx_ropll_cmn_config(hdptx, hdptx->rate / 100); -+ if (ret < 0) { -+ dev_err(hdptx->dev, "hdmi phy pll init failed\n"); -+ return ret; -+ } -+ } -+ -+ hdptx->count++; -+ -+ return 0; -+} -+ -+static void hdptx_phy_clk_disable(struct clk_hw *hw) -+{ -+ struct rockchip_hdptx_phy *hdptx = to_rockchip_hdptx_phy(hw); -+ -+ if (hdptx->count > 1) { -+ hdptx->count--; -+ return; -+ } -+ -+ if (hdptx_grf_read(hdptx, GRF_HDPTX_STATUS) & HDPTX_O_PLL_LOCK_DONE) -+ hdptx_phy_disable(hdptx); -+ clk_bulk_disable(hdptx->nr_clks, hdptx->clks); -+ hdptx->count--; -+} -+ -+static const struct clk_ops hdptx_phy_clk_ops = { -+ .recalc_rate = hdptx_phy_clk_recalc_rate, -+ .round_rate = hdptx_phy_clk_round_rate, -+ .set_rate = hdptx_phy_clk_set_rate, -+ .enable = hdptx_phy_clk_enable, -+ .disable = hdptx_phy_clk_disable, -+}; -+ -+static int rockchip_hdptx_phy_clk_register(struct rockchip_hdptx_phy *hdptx) -+{ -+ struct device *dev = hdptx->dev; -+ struct device_node *np = dev->of_node; -+ struct device_node *clk_np; -+ struct platform_device *pdev; -+ struct clk_init_data init = {}; -+ struct clk *refclk; -+ const char *parent_name; -+ int ret; -+ -+ clk_np = of_get_child_by_name(np, "clk-port"); -+ if (!clk_np) -+ return 0; -+ -+ pdev = of_platform_device_create(clk_np, NULL, dev); -+ if (!pdev) -+ return 0; -+ -+ refclk = devm_clk_get(dev, "ref"); -+ if (IS_ERR(refclk)) { -+ dev_err(dev, "failed to get ref clock\n"); -+ return PTR_ERR(refclk); -+ } -+ -+ parent_name = __clk_get_name(refclk); -+ -+ init.parent_names = &parent_name; -+ init.num_parents = 1; -+ init.flags = CLK_GET_RATE_NOCACHE; -+ if (!hdptx->id) -+ init.name = "clk_hdmiphy_pixel0"; -+ else -+ init.name = "clk_hdmiphy_pixel1"; -+ init.ops = &hdptx_phy_clk_ops; -+ -+ /* optional override of the clock name */ -+ of_property_read_string(np, "clock-output-names", &init.name); -+ -+ hdptx->hw.init = &init; -+ -+ hdptx->dclk = devm_clk_register(&pdev->dev, &hdptx->hw); -+ if (IS_ERR(hdptx->dclk)) { -+ ret = PTR_ERR(hdptx->dclk); -+ dev_err(dev, "failed to register clock: %d\n", ret); -+ return ret; -+ } -+ -+ ret = of_clk_add_provider(clk_np, of_clk_src_simple_get, hdptx->dclk); -+ if (ret) { -+ dev_err(dev, "failed to register OF clock provider: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int rockchip_hdptx_phy_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct rockchip_hdptx_phy *hdptx; -+ struct phy_provider *phy_provider; -+ struct resource *res; -+ void __iomem *regs; -+ int ret; -+ -+ hdptx = devm_kzalloc(dev, sizeof(*hdptx), GFP_KERNEL); -+ if (!hdptx) -+ return -ENOMEM; -+ -+ hdptx->dev = dev; -+ -+ hdptx->id = of_alias_get_id(dev->of_node, "hdptxhdmi"); -+ if (hdptx->id < 0) -+ hdptx->id = 0; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(regs)) -+ return PTR_ERR(regs); -+ -+ ret = devm_clk_bulk_get_all(dev, &hdptx->clks); -+ if (ret < 1) -+ return dev_err_probe(dev, ret, "failed to get clocks\n"); -+ -+ hdptx->nr_clks = ret; -+ -+ ret = clk_bulk_prepare(hdptx->nr_clks, hdptx->clks); -+ if (ret) { -+ dev_err(hdptx->dev, "failed to prepare clocks\n"); -+ return ret; -+ } -+ -+ hdptx->regmap = devm_regmap_init_mmio(dev, regs, -+ &rockchip_hdptx_phy_regmap_config); -+ if (IS_ERR(hdptx->regmap)) { -+ ret = PTR_ERR(hdptx->regmap); -+ dev_err(dev, "failed to init regmap: %d\n", ret); -+ goto err_regsmap; -+ } -+ -+ hdptx->phy_reset = devm_reset_control_get(dev, "phy"); -+ if (IS_ERR(hdptx->phy_reset)) { -+ ret = PTR_ERR(hdptx->phy_reset); -+ dev_err(dev, "failed to get phy reset: %d\n", ret); -+ goto err_regsmap; -+ } -+ -+ hdptx->apb_reset = devm_reset_control_get(dev, "apb"); -+ if (IS_ERR(hdptx->apb_reset)) { -+ ret = PTR_ERR(hdptx->apb_reset); -+ dev_err(dev, "failed to get apb reset: %d\n", ret); -+ goto err_regsmap; -+ } -+ -+ hdptx->init_reset = devm_reset_control_get(dev, "init"); -+ if (IS_ERR(hdptx->init_reset)) { -+ ret = PTR_ERR(hdptx->init_reset); -+ dev_err(dev, "failed to get init reset: %d\n", ret); -+ goto err_regsmap; -+ } -+ -+ hdptx->cmn_reset = devm_reset_control_get(dev, "cmn"); -+ if (IS_ERR(hdptx->cmn_reset)) { -+ ret = PTR_ERR(hdptx->cmn_reset); -+ dev_err(dev, "failed to get apb reset: %d\n", ret); -+ goto err_regsmap; -+ } -+ -+ hdptx->lane_reset = devm_reset_control_get(dev, "lane"); -+ if (IS_ERR(hdptx->lane_reset)) { -+ ret = PTR_ERR(hdptx->lane_reset); -+ dev_err(dev, "failed to get lane reset: %d\n", ret); -+ goto err_regsmap; -+ } -+ -+ hdptx->ropll_reset = devm_reset_control_get(dev, "ropll"); -+ if (IS_ERR(hdptx->ropll_reset)) { -+ ret = PTR_ERR(hdptx->ropll_reset); -+ dev_err(dev, "failed to get ropll reset: %d\n", ret); -+ goto err_regsmap; -+ } -+ -+ hdptx->lcpll_reset = devm_reset_control_get(dev, "lcpll"); -+ if (IS_ERR(hdptx->lcpll_reset)) { -+ ret = PTR_ERR(hdptx->lcpll_reset); -+ dev_err(dev, "failed to get lcpll reset: %d\n", ret); -+ goto err_regsmap; -+ } -+ -+ hdptx->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); -+ if (IS_ERR(hdptx->grf)) { -+ ret = PTR_ERR(hdptx->grf); -+ dev_err(hdptx->dev, "Unable to get rockchip,grf\n"); -+ goto err_regsmap; -+ } -+ -+ hdptx->phy = devm_phy_create(dev, NULL, &rockchip_hdptx_phy_ops); -+ if (IS_ERR(hdptx->phy)) { -+ dev_err(dev, "failed to create HDMI PHY\n"); -+ ret = PTR_ERR(hdptx->phy); -+ goto err_regsmap; -+ } -+ -+ phy_set_drvdata(hdptx->phy, hdptx); -+ phy_set_bus_width(hdptx->phy, 8); -+ -+ pm_runtime_enable(dev); -+ ret = devm_add_action_or_reset(dev, rockchip_hdptx_phy_runtime_disable, -+ hdptx); -+ if (ret) -+ goto err_regsmap; -+ -+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); -+ if (IS_ERR(phy_provider)) { -+ dev_err(dev, "failed to register PHY provider\n"); -+ ret = PTR_ERR(phy_provider); -+ goto err_regsmap; -+ } -+ -+ reset_control_deassert(hdptx->apb_reset); -+ reset_control_deassert(hdptx->cmn_reset); -+ reset_control_deassert(hdptx->init_reset); -+ -+ ret = rockchip_hdptx_phy_clk_register(hdptx); -+ if (ret) -+ goto err_regsmap; -+ -+ platform_set_drvdata(pdev, hdptx); -+ dev_info(dev, "hdptx phy init success\n"); -+ return 0; -+ -+err_regsmap: -+ clk_bulk_unprepare(hdptx->nr_clks, hdptx->clks); -+ return ret; -+} -+ -+static struct platform_driver rockchip_hdptx_phy_driver = { -+ .probe = rockchip_hdptx_phy_probe, -+ .driver = { -+ .name = "rockchip-hdptx-phy-hdmi", -+ .of_match_table = of_match_ptr(rockchip_hdptx_phy_of_match), -+ }, -+}; -+ -+module_platform_driver(rockchip_hdptx_phy_driver); -+ -+MODULE_DESCRIPTION("Samsung HDMI-DP Transmitter Combphy Driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c -new file mode 100644 -index 000000000..bb0beafb8 ---- /dev/null -+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c -@@ -0,0 +1,1749 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Rockchip USBDP Combo PHY with Samsung IP block driver -+ * -+ * Copyright (C) 2021 Rockchip Electronics Co., Ltd -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* RK3588 USBDP PHY Register Definitions */ -+ -+#define UDPHY_PCS 0x4000 -+#define UDPHY_PMA 0x8000 -+ -+/* VO0 GRF Registers */ -+#define RK3588_GRF_VO0_CON0 0x0000 -+#define RK3588_GRF_VO0_CON2 0x0008 -+#define DP_SINK_HPD_CFG BIT(11) -+#define DP_SINK_HPD_SEL BIT(10) -+#define DP_AUX_DIN_SEL BIT(9) -+#define DP_AUX_DOUT_SEL BIT(8) -+#define DP_LANE_SEL_N(n) GENMASK(2 * (n) + 1, 2 * (n)) -+#define DP_LANE_SEL_ALL GENMASK(7, 0) -+#define PHY_AUX_DP_DATA_POL_NORMAL 0 -+#define PHY_AUX_DP_DATA_POL_INVERT 1 -+ -+/* PMA CMN Registers */ -+#define CMN_LANE_MUX_AND_EN_OFFSET 0x0288 /* cmn_reg00A2 */ -+#define CMN_DP_LANE_MUX_N(n) BIT((n) + 4) -+#define CMN_DP_LANE_EN_N(n) BIT(n) -+#define CMN_DP_LANE_MUX_ALL GENMASK(7, 4) -+#define CMN_DP_LANE_EN_ALL GENMASK(3, 0) -+#define PHY_LANE_MUX_USB 0 -+#define PHY_LANE_MUX_DP 1 -+ -+#define CMN_DP_LINK_OFFSET 0x28c /*cmn_reg00A3 */ -+#define CMN_DP_TX_LINK_BW GENMASK(6, 5) -+#define CMN_DP_TX_LANE_SWAP_EN BIT(2) -+ -+#define CMN_SSC_EN_OFFSET 0x2d0 /* cmn_reg00B4 */ -+#define CMN_ROPLL_SSC_EN BIT(1) -+#define CMN_LCPLL_SSC_EN BIT(0) -+ -+#define CMN_ANA_LCPLL_DONE_OFFSET 0x0350 /* cmn_reg00D4 */ -+#define CMN_ANA_LCPLL_LOCK_DONE BIT(7) -+#define CMN_ANA_LCPLL_AFC_DONE BIT(6) -+ -+#define CMN_ANA_ROPLL_DONE_OFFSET 0x0354 /* cmn_reg00D5 */ -+#define CMN_ANA_ROPLL_LOCK_DONE BIT(1) -+#define CMN_ANA_ROPLL_AFC_DONE BIT(0) -+ -+#define CMN_DP_RSTN_OFFSET 0x038c /* cmn_reg00E3 */ -+#define CMN_DP_INIT_RSTN BIT(3) -+#define CMN_DP_CMN_RSTN BIT(2) -+#define CMN_CDR_WTCHDG_EN BIT(1) -+#define CMN_CDR_WTCHDG_MSK_CDR_EN BIT(0) -+ -+#define TRSV_ANA_TX_CLK_OFFSET_N(n) (0x854 + (n) * 0x800) /* trsv_reg0215 */ -+#define LN_ANA_TX_SER_TXCLK_INV BIT(1) -+ -+#define TRSV_LN0_MON_RX_CDR_DONE_OFFSET 0x0b84 /* trsv_reg02E1 */ -+#define TRSV_LN0_MON_RX_CDR_LOCK_DONE BIT(0) -+ -+#define TRSV_LN2_MON_RX_CDR_DONE_OFFSET 0x1b84 /* trsv_reg06E1 */ -+#define TRSV_LN2_MON_RX_CDR_LOCK_DONE BIT(0) -+ -+ -+#define BIT_WRITEABLE_SHIFT 16 -+ -+enum { -+ DP_BW_RBR, -+ DP_BW_HBR, -+ DP_BW_HBR2, -+ DP_BW_HBR3, -+}; -+ -+enum { -+ UDPHY_MODE_NONE = 0, -+ UDPHY_MODE_USB = BIT(0), -+ UDPHY_MODE_DP = BIT(1), -+ UDPHY_MODE_DP_USB = BIT(1) | BIT(0), -+}; -+ -+struct udphy_grf_reg { -+ unsigned int offset; -+ unsigned int bitend; -+ unsigned int bitstart; -+ unsigned int disable; -+ unsigned int enable; -+}; -+ -+struct udphy_grf_cfg { -+ /* u2phy-grf */ -+ struct udphy_grf_reg bvalid_phy_con; -+ struct udphy_grf_reg bvalid_grf_con; -+ -+ /* usb-grf */ -+ struct udphy_grf_reg usb3otg0_cfg; -+ struct udphy_grf_reg usb3otg1_cfg; -+ -+ /* usbdpphy-grf */ -+ struct udphy_grf_reg low_pwrn; -+ struct udphy_grf_reg rx_lfps; -+}; -+ -+struct udphy_vogrf_cfg { -+ /* vo-grf */ -+ struct udphy_grf_reg hpd_trigger; -+}; -+ -+struct dp_tx_drv_ctrl { -+ u32 trsv_reg0204; -+ u32 trsv_reg0205; -+ u32 trsv_reg0206; -+ u32 trsv_reg0207; -+}; -+ -+struct rockchip_udphy; -+ -+struct rockchip_udphy_cfg { -+ /* resets to be requested */ -+ const char * const *rst_list; -+ int num_rsts; -+ -+ struct udphy_grf_cfg grfcfg; -+ struct udphy_vogrf_cfg vogrfcfg[2]; -+ const struct dp_tx_drv_ctrl (*dp_tx_ctrl_cfg[4])[4]; -+ const struct dp_tx_drv_ctrl (*dp_tx_ctrl_cfg_typec[4])[4]; -+ int (*combophy_init)(struct rockchip_udphy *udphy); -+ int (*dp_phy_set_rate)(struct rockchip_udphy *udphy, -+ struct phy_configure_opts_dp *dp); -+ int (*dp_phy_set_voltages)(struct rockchip_udphy *udphy, -+ struct phy_configure_opts_dp *dp); -+ int (*hpd_event_trigger)(struct rockchip_udphy *udphy, bool hpd); -+ int (*dplane_enable)(struct rockchip_udphy *udphy, int dp_lanes); -+ int (*dplane_select)(struct rockchip_udphy *udphy); -+}; -+ -+struct rockchip_udphy { -+ struct device *dev; -+ struct regmap *pma_regmap; -+ struct regmap *u2phygrf; -+ struct regmap *udphygrf; -+ struct regmap *usbgrf; -+ struct regmap *vogrf; -+ struct typec_switch_dev *sw; -+ struct typec_mux_dev *mux; -+ struct mutex mutex; /* mutex to protect access to individual PHYs */ -+ -+ /* clocks and rests */ -+ int num_clks; -+ struct clk_bulk_data *clks; -+ struct clk *refclk; -+ struct reset_control **rsts; -+ -+ /* PHY status management */ -+ bool flip; -+ bool mode_change; -+ u8 mode; -+ u8 status; -+ -+ /* utilized for USB */ -+ bool hs; /* flag for high-speed */ -+ -+ /* utilized for DP */ -+ struct gpio_desc *sbu1_dc_gpio; -+ struct gpio_desc *sbu2_dc_gpio; -+ u32 lane_mux_sel[4]; -+ u32 dp_lane_sel[4]; -+ u32 dp_aux_dout_sel; -+ u32 dp_aux_din_sel; -+ bool dp_sink_hpd_sel; -+ bool dp_sink_hpd_cfg; -+ u8 bw; -+ int id; -+ -+ /* PHY const config */ -+ const struct rockchip_udphy_cfg *cfgs; -+}; -+ -+static const struct dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_rbr_hbr[4][4] = { -+ /* voltage swing 0, pre-emphasis 0->3 */ -+ { -+ { 0x20, 0x10, 0x42, 0xe5 }, -+ { 0x26, 0x14, 0x42, 0xe5 }, -+ { 0x29, 0x18, 0x42, 0xe5 }, -+ { 0x2b, 0x1c, 0x43, 0xe7 }, -+ }, -+ -+ /* voltage swing 1, pre-emphasis 0->2 */ -+ { -+ { 0x23, 0x10, 0x42, 0xe7 }, -+ { 0x2a, 0x17, 0x43, 0xe7 }, -+ { 0x2b, 0x1a, 0x43, 0xe7 }, -+ }, -+ -+ /* voltage swing 2, pre-emphasis 0->1 */ -+ { -+ { 0x27, 0x10, 0x42, 0xe7 }, -+ { 0x2b, 0x17, 0x43, 0xe7 }, -+ }, -+ -+ /* voltage swing 3, pre-emphasis 0 */ -+ { -+ { 0x29, 0x10, 0x43, 0xe7 }, -+ }, -+}; -+ -+static const struct dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_rbr_hbr_typec[4][4] = { -+ /* voltage swing 0, pre-emphasis 0->3 */ -+ { -+ { 0x20, 0x10, 0x42, 0xe5 }, -+ { 0x26, 0x14, 0x42, 0xe5 }, -+ { 0x29, 0x18, 0x42, 0xe5 }, -+ { 0x2b, 0x1c, 0x43, 0xe7 }, -+ }, -+ -+ /* voltage swing 1, pre-emphasis 0->2 */ -+ { -+ { 0x23, 0x10, 0x42, 0xe7 }, -+ { 0x2a, 0x17, 0x43, 0xe7 }, -+ { 0x2b, 0x1a, 0x43, 0xe7 }, -+ }, -+ -+ /* voltage swing 2, pre-emphasis 0->1 */ -+ { -+ { 0x27, 0x10, 0x43, 0x67 }, -+ { 0x2b, 0x17, 0x43, 0xe7 }, -+ }, -+ -+ /* voltage swing 3, pre-emphasis 0 */ -+ { -+ { 0x29, 0x10, 0x43, 0xe7 }, -+ }, -+}; -+ -+static const struct dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_hbr2[4][4] = { -+ /* voltage swing 0, pre-emphasis 0->3 */ -+ { -+ { 0x21, 0x10, 0x42, 0xe5 }, -+ { 0x26, 0x14, 0x42, 0xe5 }, -+ { 0x26, 0x16, 0x43, 0xe5 }, -+ { 0x2a, 0x19, 0x43, 0xe7 }, -+ }, -+ -+ /* voltage swing 1, pre-emphasis 0->2 */ -+ { -+ { 0x24, 0x10, 0x42, 0xe7 }, -+ { 0x2a, 0x17, 0x43, 0xe7 }, -+ { 0x2b, 0x1a, 0x43, 0xe7 }, -+ }, -+ -+ /* voltage swing 2, pre-emphasis 0->1 */ -+ { -+ { 0x28, 0x10, 0x42, 0xe7 }, -+ { 0x2b, 0x17, 0x43, 0xe7 }, -+ }, -+ -+ /* voltage swing 3, pre-emphasis 0 */ -+ { -+ { 0x28, 0x10, 0x43, 0xe7 }, -+ }, -+}; -+ -+static const struct dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_hbr3[4][4] = { -+ /* voltage swing 0, pre-emphasis 0->3 */ -+ { -+ { 0x21, 0x10, 0x42, 0xe5 }, -+ { 0x26, 0x14, 0x42, 0xe5 }, -+ { 0x26, 0x16, 0x43, 0xe5 }, -+ { 0x29, 0x18, 0x43, 0xe7 }, -+ }, -+ -+ /* voltage swing 1, pre-emphasis 0->2 */ -+ { -+ { 0x24, 0x10, 0x42, 0xe7 }, -+ { 0x2a, 0x18, 0x43, 0xe7 }, -+ { 0x2b, 0x1b, 0x43, 0xe7 } -+ }, -+ -+ /* voltage swing 2, pre-emphasis 0->1 */ -+ { -+ { 0x27, 0x10, 0x42, 0xe7 }, -+ { 0x2b, 0x18, 0x43, 0xe7 } -+ }, -+ -+ /* voltage swing 3, pre-emphasis 0 */ -+ { -+ { 0x28, 0x10, 0x43, 0xe7 }, -+ }, -+}; -+ -+static const struct reg_sequence rk3588_udphy_24m_refclk_cfg[] = { -+ {0x0090, 0x68}, {0x0094, 0x68}, -+ {0x0128, 0x24}, {0x012c, 0x44}, -+ {0x0130, 0x3f}, {0x0134, 0x44}, -+ {0x015c, 0xa9}, {0x0160, 0x71}, -+ {0x0164, 0x71}, {0x0168, 0xa9}, -+ {0x0174, 0xa9}, {0x0178, 0x71}, -+ {0x017c, 0x71}, {0x0180, 0xa9}, -+ {0x018c, 0x41}, {0x0190, 0x00}, -+ {0x0194, 0x05}, {0x01ac, 0x2a}, -+ {0x01b0, 0x17}, {0x01b4, 0x17}, -+ {0x01b8, 0x2a}, {0x01c8, 0x04}, -+ {0x01cc, 0x08}, {0x01d0, 0x08}, -+ {0x01d4, 0x04}, {0x01d8, 0x20}, -+ {0x01dc, 0x01}, {0x01e0, 0x09}, -+ {0x01e4, 0x03}, {0x01f0, 0x29}, -+ {0x01f4, 0x02}, {0x01f8, 0x02}, -+ {0x01fc, 0x29}, {0x0208, 0x2a}, -+ {0x020c, 0x17}, {0x0210, 0x17}, -+ {0x0214, 0x2a}, {0x0224, 0x20}, -+ {0x03f0, 0x0a}, {0x03f4, 0x07}, -+ {0x03f8, 0x07}, {0x03fc, 0x0c}, -+ {0x0404, 0x12}, {0x0408, 0x1a}, -+ {0x040c, 0x1a}, {0x0410, 0x3f}, -+ {0x0ce0, 0x68}, {0x0ce8, 0xd0}, -+ {0x0cf0, 0x87}, {0x0cf8, 0x70}, -+ {0x0d00, 0x70}, {0x0d08, 0xa9}, -+ {0x1ce0, 0x68}, {0x1ce8, 0xd0}, -+ {0x1cf0, 0x87}, {0x1cf8, 0x70}, -+ {0x1d00, 0x70}, {0x1d08, 0xa9}, -+ {0x0a3c, 0xd0}, {0x0a44, 0xd0}, -+ {0x0a48, 0x01}, {0x0a4c, 0x0d}, -+ {0x0a54, 0xe0}, {0x0a5c, 0xe0}, -+ {0x0a64, 0xa8}, {0x1a3c, 0xd0}, -+ {0x1a44, 0xd0}, {0x1a48, 0x01}, -+ {0x1a4c, 0x0d}, {0x1a54, 0xe0}, -+ {0x1a5c, 0xe0}, {0x1a64, 0xa8} -+}; -+ -+static const struct reg_sequence rk3588_udphy_26m_refclk_cfg[] = { -+ {0x0830, 0x07}, {0x085c, 0x80}, -+ {0x1030, 0x07}, {0x105c, 0x80}, -+ {0x1830, 0x07}, {0x185c, 0x80}, -+ {0x2030, 0x07}, {0x205c, 0x80}, -+ {0x0228, 0x38}, {0x0104, 0x44}, -+ {0x0248, 0x44}, {0x038C, 0x02}, -+ {0x0878, 0x04}, {0x1878, 0x04}, -+ {0x0898, 0x77}, {0x1898, 0x77}, -+ {0x0054, 0x01}, {0x00e0, 0x38}, -+ {0x0060, 0x24}, {0x0064, 0x77}, -+ {0x0070, 0x76}, {0x0234, 0xE8}, -+ {0x0AF4, 0x15}, {0x1AF4, 0x15}, -+ {0x081C, 0xE5}, {0x181C, 0xE5}, -+ {0x099C, 0x48}, {0x199C, 0x48}, -+ {0x09A4, 0x07}, {0x09A8, 0x22}, -+ {0x19A4, 0x07}, {0x19A8, 0x22}, -+ {0x09B8, 0x3E}, {0x19B8, 0x3E}, -+ {0x09E4, 0x02}, {0x19E4, 0x02}, -+ {0x0A34, 0x1E}, {0x1A34, 0x1E}, -+ {0x0A98, 0x2F}, {0x1A98, 0x2F}, -+ {0x0c30, 0x0E}, {0x0C48, 0x06}, -+ {0x1C30, 0x0E}, {0x1C48, 0x06}, -+ {0x028C, 0x18}, {0x0AF0, 0x00}, -+ {0x1AF0, 0x00} -+}; -+ -+static const struct reg_sequence rk3588_udphy_init_sequence[] = { -+ {0x0104, 0x44}, {0x0234, 0xE8}, -+ {0x0248, 0x44}, {0x028C, 0x18}, -+ {0x081C, 0xE5}, {0x0878, 0x00}, -+ {0x0994, 0x1C}, {0x0AF0, 0x00}, -+ {0x181C, 0xE5}, {0x1878, 0x00}, -+ {0x1994, 0x1C}, {0x1AF0, 0x00}, -+ {0x0428, 0x60}, {0x0D58, 0x33}, -+ {0x1D58, 0x33}, {0x0990, 0x74}, -+ {0x0D64, 0x17}, {0x08C8, 0x13}, -+ {0x1990, 0x74}, {0x1D64, 0x17}, -+ {0x18C8, 0x13}, {0x0D90, 0x40}, -+ {0x0DA8, 0x40}, {0x0DC0, 0x40}, -+ {0x0DD8, 0x40}, {0x1D90, 0x40}, -+ {0x1DA8, 0x40}, {0x1DC0, 0x40}, -+ {0x1DD8, 0x40}, {0x03C0, 0x30}, -+ {0x03C4, 0x06}, {0x0E10, 0x00}, -+ {0x1E10, 0x00}, {0x043C, 0x0F}, -+ {0x0D2C, 0xFF}, {0x1D2C, 0xFF}, -+ {0x0D34, 0x0F}, {0x1D34, 0x0F}, -+ {0x08FC, 0x2A}, {0x0914, 0x28}, -+ {0x0A30, 0x03}, {0x0E38, 0x05}, -+ {0x0ECC, 0x27}, {0x0ED0, 0x22}, -+ {0x0ED4, 0x26}, {0x18FC, 0x2A}, -+ {0x1914, 0x28}, {0x1A30, 0x03}, -+ {0x1E38, 0x05}, {0x1ECC, 0x27}, -+ {0x1ED0, 0x22}, {0x1ED4, 0x26}, -+ {0x0048, 0x0F}, {0x0060, 0x3C}, -+ {0x0064, 0xF7}, {0x006C, 0x20}, -+ {0x0070, 0x7D}, {0x0074, 0x68}, -+ {0x0AF4, 0x1A}, {0x1AF4, 0x1A}, -+ {0x0440, 0x3F}, {0x10D4, 0x08}, -+ {0x20D4, 0x08}, {0x00D4, 0x30}, -+ {0x0024, 0x6e}, -+}; -+ -+static inline int grfreg_write(struct regmap *base, -+ const struct udphy_grf_reg *reg, bool en) -+{ -+ u32 val, mask, tmp; -+ -+ tmp = en ? reg->enable : reg->disable; -+ mask = GENMASK(reg->bitend, reg->bitstart); -+ val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT); -+ -+ return regmap_write(base, reg->offset, val); -+} -+ -+static int udphy_clk_init(struct rockchip_udphy *udphy, struct device *dev) -+{ -+ int i; -+ -+ udphy->num_clks = devm_clk_bulk_get_all(dev, &udphy->clks); -+ if (udphy->num_clks < 1) -+ return -ENODEV; -+ -+ /* used for configure phy reference clock frequency */ -+ for (i = 0; i < udphy->num_clks; i++) { -+ if (!strncmp(udphy->clks[i].id, "refclk", 6)) { -+ udphy->refclk = udphy->clks[i].clk; -+ break; -+ } -+ } -+ -+ if (!udphy->refclk) -+ dev_warn(udphy->dev, "no refclk found\n"); -+ -+ return 0; -+} -+ -+static int udphy_reset_init(struct rockchip_udphy *udphy, struct device *dev) -+{ -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ int idx; -+ -+ udphy->rsts = devm_kcalloc(dev, cfg->num_rsts, -+ sizeof(*udphy->rsts), GFP_KERNEL); -+ if (!udphy->rsts) -+ return -ENOMEM; -+ -+ for (idx = 0; idx < cfg->num_rsts; idx++) { -+ struct reset_control *rst; -+ const char *name = cfg->rst_list[idx]; -+ -+ rst = devm_reset_control_get(dev, name); -+ if (IS_ERR(rst)) { -+ dev_err(dev, "failed to get %s reset\n", name); -+ devm_kfree(dev, (void *)udphy->rsts); -+ return PTR_ERR(rst); -+ } -+ -+ udphy->rsts[idx] = rst; -+ } -+ -+ return 0; -+} -+ -+static int udphy_reset_assert_all(struct rockchip_udphy *udphy) -+{ -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ int idx, ret; -+ -+ for (idx = 0; idx < cfg->num_rsts; idx++) { -+ ret = reset_control_assert(udphy->rsts[idx]); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int udphy_reset_deassert_all(struct rockchip_udphy *udphy) -+{ -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ int idx, ret; -+ -+ for (idx = 0; idx < cfg->num_rsts; idx++) { -+ ret = reset_control_deassert(udphy->rsts[idx]); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int udphy_get_rst_idx(const char * const *list, int num, char *name) -+{ -+ int idx; -+ -+ for (idx = 0; idx < num; idx++) { -+ if (!strcmp(list[idx], name)) -+ return idx; -+ } -+ -+ return -EINVAL; -+} -+ -+static int udphy_reset_assert(struct rockchip_udphy *udphy, char *name) -+{ -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ int idx; -+ -+ idx = udphy_get_rst_idx(cfg->rst_list, cfg->num_rsts, name); -+ if (idx < 0) -+ return idx; -+ -+ return reset_control_assert(udphy->rsts[idx]); -+} -+ -+static int udphy_reset_deassert(struct rockchip_udphy *udphy, char *name) -+{ -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ int idx; -+ -+ idx = udphy_get_rst_idx(cfg->rst_list, cfg->num_rsts, name); -+ if (idx < 0) -+ return idx; -+ -+ return reset_control_deassert(udphy->rsts[idx]); -+} -+ -+static void udphy_u3_port_disable(struct rockchip_udphy *udphy, u8 disable) -+{ -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ const struct udphy_grf_reg *preg; -+ -+ preg = udphy->id ? &cfg->grfcfg.usb3otg1_cfg : &cfg->grfcfg.usb3otg0_cfg; -+ grfreg_write(udphy->usbgrf, preg, disable); -+} -+ -+static void udphy_usb_bvalid_enable(struct rockchip_udphy *udphy, u8 enable) -+{ -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ -+ grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_phy_con, enable); -+ grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_grf_con, enable); -+} -+ -+/* -+ * In usb/dp combo phy driver, here are 2 ways to mapping lanes. -+ * -+ * 1 Type-C Mapping table (DP_Alt_Mode V1.0b remove ABF pin mapping) -+ * --------------------------------------------------------------------------- -+ * Type-C Pin B11-B10 A2-A3 A11-A10 B2-B3 -+ * PHY Pad ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) -+ * C/E(Normal) dpln3 dpln2 dpln0 dpln1 -+ * C/E(Flip ) dpln0 dpln1 dpln3 dpln2 -+ * D/F(Normal) usbrx usbtx dpln0 dpln1 -+ * D/F(Flip ) dpln0 dpln1 usbrx usbtx -+ * A(Normal ) dpln3 dpln1 dpln2 dpln0 -+ * A(Flip ) dpln2 dpln0 dpln3 dpln1 -+ * B(Normal ) usbrx usbtx dpln1 dpln0 -+ * B(Flip ) dpln1 dpln0 usbrx usbtx -+ * --------------------------------------------------------------------------- -+ * -+ * 2 Mapping the lanes in dtsi -+ * if all 4 lane assignment for dp function, define rockchip,dp-lane-mux = ; -+ * sample as follow: -+ * --------------------------------------------------------------------------- -+ * B11-B10 A2-A3 A11-A10 B2-B3 -+ * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) -+ * <0 1 2 3> dpln0 dpln1 dpln2 dpln3 -+ * <2 3 0 1> dpln2 dpln3 dpln0 dpln1 -+ * --------------------------------------------------------------------------- -+ * if 2 lane for dp function, 2 lane for usb function, define rockchip,dp-lane-mux = ; -+ * sample as follow: -+ * --------------------------------------------------------------------------- -+ * B11-B10 A2-A3 A11-A10 B2-B3 -+ * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) -+ * <0 1> dpln0 dpln1 usbrx usbtx -+ * <2 3> usbrx usbtx dpln0 dpln1 -+ * --------------------------------------------------------------------------- -+ */ -+ -+static int udphy_dplane_select(struct rockchip_udphy *udphy) -+{ -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ -+ if (cfg->dplane_select) -+ return cfg->dplane_select(udphy); -+ -+ return 0; -+} -+ -+static int udphy_dplane_get(struct rockchip_udphy *udphy) -+{ -+ int dp_lanes; -+ -+ switch (udphy->mode) { -+ case UDPHY_MODE_DP: -+ dp_lanes = 4; -+ break; -+ case UDPHY_MODE_DP_USB: -+ dp_lanes = 2; -+ break; -+ case UDPHY_MODE_USB: -+ fallthrough; -+ default: -+ dp_lanes = 0; -+ break; -+ } -+ -+ return dp_lanes; -+} -+ -+static int udphy_dplane_enable(struct rockchip_udphy *udphy, int dp_lanes) -+{ -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ int ret = 0; -+ -+ if (cfg->dplane_enable) -+ ret = cfg->dplane_enable(udphy, dp_lanes); -+ -+ return ret; -+} -+ -+static int upphy_set_typec_default_mapping(struct rockchip_udphy *udphy) -+{ -+ if (udphy->flip) { -+ udphy->dp_lane_sel[0] = 0; -+ udphy->dp_lane_sel[1] = 1; -+ udphy->dp_lane_sel[2] = 3; -+ udphy->dp_lane_sel[3] = 2; -+ udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; -+ udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; -+ udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB; -+ udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB; -+ udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_INVERT; -+ udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_INVERT; -+ gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 1); -+ gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 0); -+ } else { -+ udphy->dp_lane_sel[0] = 2; -+ udphy->dp_lane_sel[1] = 3; -+ udphy->dp_lane_sel[2] = 1; -+ udphy->dp_lane_sel[3] = 0; -+ udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB; -+ udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB; -+ udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; -+ udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; -+ udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_NORMAL; -+ udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_NORMAL; -+ gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 0); -+ gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 1); -+ } -+ -+ udphy->mode = UDPHY_MODE_DP_USB; -+ -+ return 0; -+} -+ -+static int udphy_orien_sw_set(struct typec_switch_dev *sw, -+ enum typec_orientation orien) -+{ -+ struct rockchip_udphy *udphy = typec_switch_get_drvdata(sw); -+ -+ mutex_lock(&udphy->mutex); -+ -+ if (orien == TYPEC_ORIENTATION_NONE) { -+ gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 0); -+ gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 0); -+ /* unattached */ -+ udphy_usb_bvalid_enable(udphy, false); -+ goto unlock_ret; -+ } -+ -+ udphy->flip = (orien == TYPEC_ORIENTATION_REVERSE) ? true : false; -+ upphy_set_typec_default_mapping(udphy); -+ udphy_usb_bvalid_enable(udphy, true); -+ -+unlock_ret: -+ mutex_unlock(&udphy->mutex); -+ return 0; -+} -+ -+static int udphy_setup_orien_switch(struct rockchip_udphy *udphy) -+{ -+ struct typec_switch_desc sw_desc = { }; -+ -+ sw_desc.drvdata = udphy; -+ sw_desc.fwnode = dev_fwnode(udphy->dev); -+ sw_desc.set = udphy_orien_sw_set; -+ -+ udphy->sw = typec_switch_register(udphy->dev, &sw_desc); -+ if (IS_ERR(udphy->sw)) { -+ dev_err(udphy->dev, "Error register typec orientation switch: %ld\n", -+ PTR_ERR(udphy->sw)); -+ return PTR_ERR(udphy->sw); -+ } -+ -+ return 0; -+} -+ -+static void udphy_orien_switch_unregister(void *data) -+{ -+ struct rockchip_udphy *udphy = data; -+ -+ typec_switch_unregister(udphy->sw); -+} -+ -+static int udphy_setup(struct rockchip_udphy *udphy) -+{ -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ int ret = 0; -+ -+ ret = clk_bulk_prepare_enable(udphy->num_clks, udphy->clks); -+ if (ret) { -+ dev_err(udphy->dev, "failed to enable clk\n"); -+ return ret; -+ } -+ -+ if (cfg->combophy_init) { -+ ret = cfg->combophy_init(udphy); -+ if (ret) { -+ dev_err(udphy->dev, "failed to init combophy\n"); -+ clk_bulk_disable_unprepare(udphy->num_clks, udphy->clks); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int udphy_disable(struct rockchip_udphy *udphy) -+{ -+ clk_bulk_disable_unprepare(udphy->num_clks, udphy->clks); -+ udphy_reset_assert_all(udphy); -+ -+ return 0; -+} -+ -+static int udphy_parse_lane_mux_data(struct rockchip_udphy *udphy, struct device_node *np) -+{ -+ struct property *prop; -+ int ret, i, len, num_lanes; -+ -+ prop = of_find_property(np, "rockchip,dp-lane-mux", &len); -+ if (!prop) { -+ dev_dbg(udphy->dev, "failed to find dp lane mux, following dp alt mode\n"); -+ udphy->mode = UDPHY_MODE_USB; -+ return 0; -+ } -+ -+ num_lanes = len / sizeof(u32); -+ -+ if (num_lanes != 2 && num_lanes != 4) { -+ dev_err(udphy->dev, "invalid number of lane mux\n"); -+ return -EINVAL; -+ } -+ -+ ret = of_property_read_u32_array(np, "rockchip,dp-lane-mux", udphy->dp_lane_sel, num_lanes); -+ if (ret) { -+ dev_err(udphy->dev, "get dp lane mux failed\n"); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < num_lanes; i++) { -+ int j; -+ -+ if (udphy->dp_lane_sel[i] > 3) { -+ dev_err(udphy->dev, "lane mux between 0 and 3, exceeding the range\n"); -+ return -EINVAL; -+ } -+ -+ udphy->lane_mux_sel[udphy->dp_lane_sel[i]] = PHY_LANE_MUX_DP; -+ -+ for (j = i + 1; j < num_lanes; j++) { -+ if (udphy->dp_lane_sel[i] == udphy->dp_lane_sel[j]) { -+ dev_err(udphy->dev, "set repeat lane mux value\n"); -+ return -EINVAL; -+ } -+ } -+ } -+ -+ udphy->mode = UDPHY_MODE_DP; -+ if (num_lanes == 2) { -+ udphy->mode |= UDPHY_MODE_USB; -+ udphy->flip = (udphy->lane_mux_sel[0] == PHY_LANE_MUX_DP); -+ } -+ -+ return 0; -+} -+ -+static int udphy_get_initial_status(struct rockchip_udphy *udphy) -+{ -+ int ret; -+ u32 value; -+ -+ ret = clk_bulk_prepare_enable(udphy->num_clks, udphy->clks); -+ if (ret) { -+ dev_err(udphy->dev, "failed to enable clk\n"); -+ return ret; -+ } -+ -+ udphy_reset_deassert_all(udphy); -+ -+ regmap_read(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, &value); -+ if (FIELD_GET(CMN_DP_LANE_MUX_ALL, value) && FIELD_GET(CMN_DP_LANE_EN_ALL, value)) -+ udphy->status = UDPHY_MODE_DP; -+ else -+ udphy_disable(udphy); -+ -+ return 0; -+} -+ -+static int udphy_parse_dt(struct rockchip_udphy *udphy, struct device *dev) -+{ -+ struct device_node *np = dev->of_node; -+ enum usb_device_speed maximum_speed; -+ int ret; -+ -+ udphy->u2phygrf = syscon_regmap_lookup_by_phandle(np, "rockchip,u2phy-grf"); -+ if (IS_ERR(udphy->u2phygrf)) { -+ if (PTR_ERR(udphy->u2phygrf) == -ENODEV) { -+ dev_warn(dev, "missing u2phy-grf dt node\n"); -+ udphy->u2phygrf = NULL; -+ } else { -+ return PTR_ERR(udphy->u2phygrf); -+ } -+ } -+ -+ udphy->udphygrf = syscon_regmap_lookup_by_phandle(np, "rockchip,usbdpphy-grf"); -+ if (IS_ERR(udphy->udphygrf)) { -+ if (PTR_ERR(udphy->udphygrf) == -ENODEV) { -+ dev_warn(dev, "missing usbdpphy-grf dt node\n"); -+ udphy->udphygrf = NULL; -+ } else { -+ return PTR_ERR(udphy->udphygrf); -+ } -+ } -+ -+ udphy->usbgrf = syscon_regmap_lookup_by_phandle(np, "rockchip,usb-grf"); -+ if (IS_ERR(udphy->usbgrf)) { -+ if (PTR_ERR(udphy->usbgrf) == -ENODEV) { -+ dev_warn(dev, "missing usb-grf dt node\n"); -+ udphy->usbgrf = NULL; -+ } else { -+ return PTR_ERR(udphy->usbgrf); -+ } -+ } -+ -+ udphy->vogrf = syscon_regmap_lookup_by_phandle(np, "rockchip,vo-grf"); -+ if (IS_ERR(udphy->vogrf)) { -+ if (PTR_ERR(udphy->vogrf) == -ENODEV) { -+ dev_warn(dev, "missing vo-grf dt node\n"); -+ udphy->vogrf = NULL; -+ } else { -+ return PTR_ERR(udphy->vogrf); -+ } -+ } -+ -+ ret = udphy_parse_lane_mux_data(udphy, np); -+ if (ret) -+ return ret; -+ -+ udphy->sbu1_dc_gpio = devm_gpiod_get_optional(dev, "sbu1-dc", GPIOD_OUT_LOW); -+ if (IS_ERR(udphy->sbu1_dc_gpio)) -+ return PTR_ERR(udphy->sbu1_dc_gpio); -+ -+ udphy->sbu2_dc_gpio = devm_gpiod_get_optional(dev, "sbu2-dc", GPIOD_OUT_LOW); -+ if (IS_ERR(udphy->sbu2_dc_gpio)) -+ return PTR_ERR(udphy->sbu2_dc_gpio); -+ -+ if (device_property_present(dev, "maximum-speed")) { -+ maximum_speed = usb_get_maximum_speed(dev); -+ udphy->hs = maximum_speed <= USB_SPEED_HIGH ? true : false; -+ } -+ -+ ret = udphy_clk_init(udphy, dev); -+ if (ret) -+ return ret; -+ -+ ret = udphy_reset_init(udphy, dev); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int udphy_power_on(struct rockchip_udphy *udphy, u8 mode) -+{ -+ int ret; -+ -+ if (!(udphy->mode & mode)) { -+ dev_info(udphy->dev, "mode 0x%02x is not support\n", mode); -+ return 0; -+ } -+ -+ if (udphy->status == UDPHY_MODE_NONE) { -+ udphy->mode_change = false; -+ ret = udphy_setup(udphy); -+ if (ret) -+ return ret; -+ -+ if (udphy->mode & UDPHY_MODE_USB) -+ udphy_u3_port_disable(udphy, false); -+ } else if (udphy->mode_change) { -+ udphy->mode_change = false; -+ udphy->status = UDPHY_MODE_NONE; -+ if (udphy->mode == UDPHY_MODE_DP) -+ udphy_u3_port_disable(udphy, true); -+ -+ ret = udphy_disable(udphy); -+ if (ret) -+ return ret; -+ ret = udphy_setup(udphy); -+ if (ret) -+ return ret; -+ } -+ -+ udphy->status |= mode; -+ -+ return 0; -+} -+ -+static int udphy_power_off(struct rockchip_udphy *udphy, u8 mode) -+{ -+ int ret; -+ -+ if (!(udphy->mode & mode)) { -+ dev_info(udphy->dev, "mode 0x%02x is not support\n", mode); -+ return 0; -+ } -+ -+ if (!udphy->status) -+ return 0; -+ -+ udphy->status &= ~mode; -+ -+ if (udphy->status == UDPHY_MODE_NONE) { -+ ret = udphy_disable(udphy); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int rockchip_dp_phy_power_on(struct phy *phy) -+{ -+ struct rockchip_udphy *udphy = phy_get_drvdata(phy); -+ int ret, dp_lanes; -+ -+ mutex_lock(&udphy->mutex); -+ -+ dp_lanes = udphy_dplane_get(udphy); -+ phy_set_bus_width(phy, dp_lanes); -+ -+ ret = udphy_power_on(udphy, UDPHY_MODE_DP); -+ if (ret) -+ goto unlock; -+ -+ ret = udphy_dplane_enable(udphy, dp_lanes); -+ if (ret) -+ goto unlock; -+ -+ ret = udphy_dplane_select(udphy); -+ -+unlock: -+ mutex_unlock(&udphy->mutex); -+ /* -+ * If data send by aux channel too fast after phy power on, -+ * the aux may be not ready which will cause aux error. Adding -+ * delay to avoid this issue. -+ */ -+ usleep_range(10000, 11000); -+ return ret; -+} -+ -+static int rockchip_dp_phy_power_off(struct phy *phy) -+{ -+ struct rockchip_udphy *udphy = phy_get_drvdata(phy); -+ int ret; -+ -+ mutex_lock(&udphy->mutex); -+ ret = udphy_dplane_enable(udphy, 0); -+ if (ret) -+ goto unlock; -+ -+ ret = udphy_power_off(udphy, UDPHY_MODE_DP); -+ -+unlock: -+ mutex_unlock(&udphy->mutex); -+ return ret; -+} -+ -+static int rockchip_dp_phy_verify_link_rate(unsigned int link_rate) -+{ -+ switch (link_rate) { -+ case 1620: -+ case 2700: -+ case 5400: -+ case 8100: -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int rockchip_dp_phy_verify_config(struct rockchip_udphy *udphy, -+ struct phy_configure_opts_dp *dp) -+{ -+ int i, ret; -+ -+ /* If changing link rate was required, verify it's supported. */ -+ ret = rockchip_dp_phy_verify_link_rate(dp->link_rate); -+ if (ret) -+ return ret; -+ -+ /* Verify lane count. */ -+ switch (dp->lanes) { -+ case 1: -+ case 2: -+ case 4: -+ /* valid lane count. */ -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ /* -+ * If changing voltages is required, check swing and pre-emphasis -+ * levels, per-lane. -+ */ -+ if (dp->set_voltages) { -+ /* Lane count verified previously. */ -+ for (i = 0; i < dp->lanes; i++) { -+ if (dp->voltage[i] > 3 || dp->pre[i] > 3) -+ return -EINVAL; -+ -+ /* -+ * Sum of voltage swing and pre-emphasis levels cannot -+ * exceed 3. -+ */ -+ if (dp->voltage[i] + dp->pre[i] > 3) -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+static int rockchip_dp_phy_configure(struct phy *phy, -+ union phy_configure_opts *opts) -+{ -+ struct rockchip_udphy *udphy = phy_get_drvdata(phy); -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ int ret; -+ -+ ret = rockchip_dp_phy_verify_config(udphy, &opts->dp); -+ if (ret) -+ return ret; -+ -+ if (opts->dp.set_rate && cfg->dp_phy_set_rate) { -+ ret = cfg->dp_phy_set_rate(udphy, &opts->dp); -+ if (ret) { -+ dev_err(udphy->dev, -+ "rockchip_hdptx_phy_set_rate failed\n"); -+ return ret; -+ } -+ } -+ -+ if (opts->dp.set_voltages && cfg->dp_phy_set_voltages) { -+ ret = cfg->dp_phy_set_voltages(udphy, &opts->dp); -+ if (ret) { -+ dev_err(udphy->dev, -+ "rockchip_dp_phy_set_voltages failed\n"); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static const struct phy_ops rockchip_dp_phy_ops = { -+ .power_on = rockchip_dp_phy_power_on, -+ .power_off = rockchip_dp_phy_power_off, -+ .configure = rockchip_dp_phy_configure, -+ .owner = THIS_MODULE, -+}; -+ -+static int rockchip_u3phy_init(struct phy *phy) -+{ -+ struct rockchip_udphy *udphy = phy_get_drvdata(phy); -+ int ret = 0; -+ -+ mutex_lock(&udphy->mutex); -+ /* DP only or high-speed, disable U3 port */ -+ if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) { -+ udphy_u3_port_disable(udphy, true); -+ goto unlock; -+ } -+ -+ ret = udphy_power_on(udphy, UDPHY_MODE_USB); -+ -+unlock: -+ mutex_unlock(&udphy->mutex); -+ return ret; -+} -+ -+static int rockchip_u3phy_exit(struct phy *phy) -+{ -+ struct rockchip_udphy *udphy = phy_get_drvdata(phy); -+ int ret = 0; -+ -+ mutex_lock(&udphy->mutex); -+ /* DP only or high-speed */ -+ if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) -+ goto unlock; -+ -+ ret = udphy_power_off(udphy, UDPHY_MODE_USB); -+ -+unlock: -+ mutex_unlock(&udphy->mutex); -+ return ret; -+} -+ -+static const struct phy_ops rockchip_u3phy_ops = { -+ .init = rockchip_u3phy_init, -+ .exit = rockchip_u3phy_exit, -+ .owner = THIS_MODULE, -+}; -+ -+static int usbdp_typec_mux_set(struct typec_mux_dev *mux, -+ struct typec_mux_state *state) -+{ -+ struct rockchip_udphy *udphy = typec_mux_get_drvdata(mux); -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ u8 mode; -+ -+ mutex_lock(&udphy->mutex); -+ -+ switch (state->mode) { -+ case TYPEC_DP_STATE_C: -+ fallthrough; -+ case TYPEC_DP_STATE_E: -+ udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; -+ udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; -+ udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; -+ udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; -+ mode = UDPHY_MODE_DP; -+ break; -+ case TYPEC_DP_STATE_D: -+ fallthrough; -+ default: -+ if (udphy->flip) { -+ udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; -+ udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; -+ udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB; -+ udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB; -+ } else { -+ udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB; -+ udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB; -+ udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; -+ udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; -+ } -+ mode = UDPHY_MODE_DP_USB; -+ break; -+ } -+ -+ if (state->alt && state->alt->svid == USB_TYPEC_DP_SID) { -+ struct typec_displayport_data *data = state->data; -+ -+ if (!data) { -+ if (cfg->hpd_event_trigger) -+ cfg->hpd_event_trigger(udphy, false); -+ } else if (data->status & DP_STATUS_IRQ_HPD) { -+ if (cfg->hpd_event_trigger) { -+ cfg->hpd_event_trigger(udphy, false); -+ usleep_range(750, 800); -+ cfg->hpd_event_trigger(udphy, true); -+ } -+ } else if (data->status & DP_STATUS_HPD_STATE) { -+ if (udphy->mode != mode) { -+ udphy->mode = mode; -+ udphy->mode_change = true; -+ } -+ if (cfg->hpd_event_trigger) -+ cfg->hpd_event_trigger(udphy, true); -+ } else { -+ if (cfg->hpd_event_trigger) -+ cfg->hpd_event_trigger(udphy, false); -+ } -+ } -+ -+ mutex_unlock(&udphy->mutex); -+ return 0; -+} -+ -+static int udphy_setup_typec_mux(struct rockchip_udphy *udphy) -+{ -+ struct typec_mux_desc mux_desc = {}; -+ -+ mux_desc.drvdata = udphy; -+ mux_desc.fwnode = dev_fwnode(udphy->dev); -+ mux_desc.set = usbdp_typec_mux_set; -+ -+ udphy->mux = typec_mux_register(udphy->dev, &mux_desc); -+ if (IS_ERR(udphy->mux)) { -+ dev_err(udphy->dev, "Error register typec mux: %ld\n", -+ PTR_ERR(udphy->mux)); -+ return PTR_ERR(udphy->mux); -+ } -+ -+ return 0; -+} -+ -+static void udphy_typec_mux_unregister(void *data) -+{ -+ struct rockchip_udphy *udphy = data; -+ -+ typec_mux_unregister(udphy->mux); -+} -+ -+static u32 udphy_dp_get_max_link_rate(struct rockchip_udphy *udphy, struct device_node *np) -+{ -+ u32 max_link_rate; -+ int ret; -+ -+ ret = of_property_read_u32(np, "max-link-rate", &max_link_rate); -+ if (ret) -+ return 8100; -+ -+ ret = rockchip_dp_phy_verify_link_rate(max_link_rate); -+ if (ret) { -+ dev_warn(udphy->dev, "invalid max-link-rate value:%d\n", max_link_rate); -+ max_link_rate = 8100; -+ } -+ -+ return max_link_rate; -+} -+ -+static const struct regmap_config rockchip_udphy_pma_regmap_cfg = { -+ .reg_bits = 32, -+ .reg_stride = 4, -+ .val_bits = 32, -+ .fast_io = true, -+ .max_register = 0x20dc, -+}; -+ -+static int rockchip_udphy_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct device_node *child_np; -+ struct phy_provider *phy_provider; -+ struct resource *res; -+ struct rockchip_udphy *udphy; -+ const struct rockchip_udphy_cfg *phy_cfgs; -+ void __iomem *base; -+ int id, ret; -+ -+ udphy = devm_kzalloc(dev, sizeof(*udphy), GFP_KERNEL); -+ if (!udphy) -+ return -ENOMEM; -+ -+ id = of_alias_get_id(dev->of_node, "usbdp"); -+ if (id < 0) -+ id = 0; -+ udphy->id = id; -+ -+ phy_cfgs = device_get_match_data(dev); -+ if (!phy_cfgs) { -+ dev_err(dev, "missing match data\n"); -+ return -EINVAL; -+ } -+ -+ udphy->cfgs = phy_cfgs; -+ -+ base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ udphy->pma_regmap = devm_regmap_init_mmio(dev, base + UDPHY_PMA, -+ &rockchip_udphy_pma_regmap_cfg); -+ if (IS_ERR(udphy->pma_regmap)) -+ return PTR_ERR(udphy->pma_regmap); -+ -+ ret = udphy_parse_dt(udphy, dev); -+ if (ret) -+ return ret; -+ -+ ret = udphy_get_initial_status(udphy); -+ if (ret) -+ return ret; -+ -+ mutex_init(&udphy->mutex); -+ udphy->dev = dev; -+ platform_set_drvdata(pdev, udphy); -+ -+ if (device_property_present(dev, "orientation-switch")) { -+ ret = udphy_setup_orien_switch(udphy); -+ if (ret) -+ return ret; -+ -+ ret = devm_add_action_or_reset(dev, udphy_orien_switch_unregister, udphy); -+ if (ret) -+ return ret; -+ } -+ -+ if (device_property_present(dev, "mode-switch")) { -+ ret = udphy_setup_typec_mux(udphy); -+ if (ret) -+ return ret; -+ -+ ret = devm_add_action_or_reset(dev, udphy_typec_mux_unregister, udphy); -+ if (ret) -+ return ret; -+ } -+ -+ for_each_available_child_of_node(np, child_np) { -+ struct phy *phy; -+ -+ if (of_node_name_eq(child_np, "dp-port")) { -+ phy = devm_phy_create(dev, child_np, &rockchip_dp_phy_ops); -+ if (IS_ERR(phy)) { -+ dev_err(dev, "failed to create dp phy: %pOFn\n", child_np); -+ goto put_child; -+ } -+ -+ phy_set_bus_width(phy, udphy_dplane_get(udphy)); -+ phy->attrs.max_link_rate = udphy_dp_get_max_link_rate(udphy, child_np); -+ } else if (of_node_name_eq(child_np, "usb3-port")) { -+ phy = devm_phy_create(dev, child_np, &rockchip_u3phy_ops); -+ if (IS_ERR(phy)) { -+ dev_err(dev, "failed to create usb phy: %pOFn\n", child_np); -+ goto put_child; -+ } -+ } else -+ continue; -+ -+ phy_set_drvdata(phy, udphy); -+ } -+ -+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); -+ if (IS_ERR(phy_provider)) { -+ dev_err(dev, "failed to register phy provider\n"); -+ goto put_child; -+ } -+ -+ return 0; -+ -+put_child: -+ of_node_put(child_np); -+ return ret; -+} -+ -+static int rk3588_udphy_refclk_set(struct rockchip_udphy *udphy) -+{ -+ unsigned long rate; -+ int ret; -+ -+ /* configure phy reference clock */ -+ rate = clk_get_rate(udphy->refclk); -+ dev_dbg(udphy->dev, "refclk freq %ld\n", rate); -+ -+ switch (rate) { -+ case 24000000: -+ ret = regmap_multi_reg_write(udphy->pma_regmap, rk3588_udphy_24m_refclk_cfg, -+ ARRAY_SIZE(rk3588_udphy_24m_refclk_cfg)); -+ if (ret) -+ return ret; -+ break; -+ case 26000000: -+ /* register default is 26MHz */ -+ ret = regmap_multi_reg_write(udphy->pma_regmap, rk3588_udphy_26m_refclk_cfg, -+ ARRAY_SIZE(rk3588_udphy_26m_refclk_cfg)); -+ if (ret) -+ return ret; -+ break; -+ default: -+ dev_err(udphy->dev, "unsupported refclk freq %ld\n", rate); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int rk3588_udphy_status_check(struct rockchip_udphy *udphy) -+{ -+ unsigned int val; -+ int ret; -+ -+ /* LCPLL check */ -+ if (udphy->mode & UDPHY_MODE_USB) { -+ ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_LCPLL_DONE_OFFSET, -+ val, (val & CMN_ANA_LCPLL_AFC_DONE) && -+ (val & CMN_ANA_LCPLL_LOCK_DONE), 200, 100000); -+ if (ret) { -+ dev_err(udphy->dev, "cmn ana lcpll lock timeout\n"); -+ return ret; -+ } -+ -+ if (!udphy->flip) { -+ ret = regmap_read_poll_timeout(udphy->pma_regmap, -+ TRSV_LN0_MON_RX_CDR_DONE_OFFSET, val, -+ val & TRSV_LN0_MON_RX_CDR_LOCK_DONE, -+ 200, 100000); -+ if (ret) -+ dev_err(udphy->dev, "trsv ln0 mon rx cdr lock timeout\n"); -+ } else { -+ ret = regmap_read_poll_timeout(udphy->pma_regmap, -+ TRSV_LN2_MON_RX_CDR_DONE_OFFSET, val, -+ val & TRSV_LN2_MON_RX_CDR_LOCK_DONE, -+ 200, 100000); -+ if (ret) -+ dev_err(udphy->dev, "trsv ln2 mon rx cdr lock timeout\n"); -+ } -+ } -+ -+ return 0; -+} -+ -+static int rk3588_udphy_init(struct rockchip_udphy *udphy) -+{ -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ int ret; -+ -+ /* enable rx lfps for usb */ -+ if (udphy->mode & UDPHY_MODE_USB) -+ grfreg_write(udphy->udphygrf, &cfg->grfcfg.rx_lfps, true); -+ -+ /* Step 1: power on pma and deassert apb rstn */ -+ grfreg_write(udphy->udphygrf, &cfg->grfcfg.low_pwrn, true); -+ -+ udphy_reset_deassert(udphy, "pma_apb"); -+ udphy_reset_deassert(udphy, "pcs_apb"); -+ -+ /* Step 2: set init sequence and phy refclk */ -+ ret = regmap_multi_reg_write(udphy->pma_regmap, rk3588_udphy_init_sequence, -+ ARRAY_SIZE(rk3588_udphy_init_sequence)); -+ if (ret) { -+ dev_err(udphy->dev, "init sequence set error %d\n", ret); -+ goto assert_apb; -+ } -+ -+ ret = rk3588_udphy_refclk_set(udphy); -+ if (ret) { -+ dev_err(udphy->dev, "refclk set error %d\n", ret); -+ goto assert_apb; -+ } -+ -+ /* Step 3: configure lane mux */ -+ regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, -+ CMN_DP_LANE_MUX_ALL | CMN_DP_LANE_EN_ALL, -+ FIELD_PREP(CMN_DP_LANE_MUX_N(3), udphy->lane_mux_sel[3]) | -+ FIELD_PREP(CMN_DP_LANE_MUX_N(2), udphy->lane_mux_sel[2]) | -+ FIELD_PREP(CMN_DP_LANE_MUX_N(1), udphy->lane_mux_sel[1]) | -+ FIELD_PREP(CMN_DP_LANE_MUX_N(0), udphy->lane_mux_sel[0]) | -+ FIELD_PREP(CMN_DP_LANE_EN_ALL, 0)); -+ -+ /* Step 4: deassert init rstn and wait for 200ns from datasheet */ -+ if (udphy->mode & UDPHY_MODE_USB) -+ udphy_reset_deassert(udphy, "init"); -+ -+ if (udphy->mode & UDPHY_MODE_DP) { -+ regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, -+ CMN_DP_INIT_RSTN, -+ FIELD_PREP(CMN_DP_INIT_RSTN, 0x1)); -+ } -+ -+ udelay(1); -+ -+ /* Step 5: deassert cmn/lane rstn */ -+ if (udphy->mode & UDPHY_MODE_USB) { -+ udphy_reset_deassert(udphy, "cmn"); -+ udphy_reset_deassert(udphy, "lane"); -+ } -+ -+ /* Step 6: wait for lock done of pll */ -+ ret = rk3588_udphy_status_check(udphy); -+ if (ret) -+ goto assert_phy; -+ -+ return 0; -+ -+assert_phy: -+ udphy_reset_assert(udphy, "init"); -+ udphy_reset_assert(udphy, "cmn"); -+ udphy_reset_assert(udphy, "lane"); -+ -+assert_apb: -+ udphy_reset_assert(udphy, "pma_apb"); -+ udphy_reset_assert(udphy, "pcs_apb"); -+ return ret; -+} -+ -+static int rk3588_udphy_hpd_event_trigger(struct rockchip_udphy *udphy, bool hpd) -+{ -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ -+ udphy->dp_sink_hpd_sel = true; -+ udphy->dp_sink_hpd_cfg = hpd; -+ -+ grfreg_write(udphy->vogrf, &cfg->vogrfcfg[udphy->id].hpd_trigger, hpd); -+ -+ return 0; -+} -+ -+static int rk3588_udphy_dplane_enable(struct rockchip_udphy *udphy, int dp_lanes) -+{ -+ int i; -+ u32 val = 0; -+ -+ for (i = 0; i < dp_lanes; i++) -+ val |= BIT(udphy->dp_lane_sel[i]); -+ -+ regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, CMN_DP_LANE_EN_ALL, -+ FIELD_PREP(CMN_DP_LANE_EN_ALL, val)); -+ -+ if (!dp_lanes) -+ regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, -+ CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0)); -+ -+ return 0; -+} -+ -+static int rk3588_udphy_dplane_select(struct rockchip_udphy *udphy) -+{ -+ u32 value = 0; -+ -+ switch (udphy->mode) { -+ case UDPHY_MODE_DP: -+ value |= 2 << udphy->dp_lane_sel[2] * 2; -+ value |= 3 << udphy->dp_lane_sel[3] * 2; -+ fallthrough; -+ case UDPHY_MODE_DP_USB: -+ value |= 0 << udphy->dp_lane_sel[0] * 2; -+ value |= 1 << udphy->dp_lane_sel[1] * 2; -+ break; -+ case UDPHY_MODE_USB: -+ break; -+ default: -+ break; -+ } -+ -+ regmap_write(udphy->vogrf, udphy->id ? RK3588_GRF_VO0_CON2 : RK3588_GRF_VO0_CON0, -+ ((DP_AUX_DIN_SEL | DP_AUX_DOUT_SEL | DP_LANE_SEL_ALL) << 16) | -+ FIELD_PREP(DP_AUX_DIN_SEL, udphy->dp_aux_din_sel) | -+ FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value); -+ -+ return 0; -+} -+ -+static int rk3588_dp_phy_set_rate(struct rockchip_udphy *udphy, -+ struct phy_configure_opts_dp *dp) -+{ -+ u32 val; -+ int ret; -+ -+ regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, -+ CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0)); -+ -+ switch (dp->link_rate) { -+ case 1620: -+ udphy->bw = DP_BW_RBR; -+ break; -+ case 2700: -+ udphy->bw = DP_BW_HBR; -+ break; -+ case 5400: -+ udphy->bw = DP_BW_HBR2; -+ break; -+ case 8100: -+ udphy->bw = DP_BW_HBR3; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ regmap_update_bits(udphy->pma_regmap, CMN_DP_LINK_OFFSET, CMN_DP_TX_LINK_BW, -+ FIELD_PREP(CMN_DP_TX_LINK_BW, udphy->bw)); -+ regmap_update_bits(udphy->pma_regmap, CMN_SSC_EN_OFFSET, CMN_ROPLL_SSC_EN, -+ FIELD_PREP(CMN_ROPLL_SSC_EN, dp->ssc)); -+ regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, CMN_DP_CMN_RSTN, -+ FIELD_PREP(CMN_DP_CMN_RSTN, 0x1)); -+ -+ ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_ROPLL_DONE_OFFSET, val, -+ FIELD_GET(CMN_ANA_ROPLL_LOCK_DONE, val) && -+ FIELD_GET(CMN_ANA_ROPLL_AFC_DONE, val), -+ 0, 1000); -+ if (ret) { -+ dev_err(udphy->dev, "ROPLL is not lock\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void rk3588_dp_phy_set_voltage(struct rockchip_udphy *udphy, u8 bw, -+ u32 voltage, u32 pre, u32 lane) -+{ -+ u32 offset = 0x800 * lane; -+ u32 val; -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ const struct dp_tx_drv_ctrl (*dp_ctrl)[4]; -+ -+ dp_ctrl = udphy->mux ? cfg->dp_tx_ctrl_cfg_typec[bw] : cfg->dp_tx_ctrl_cfg[bw]; -+ val = dp_ctrl[voltage][pre].trsv_reg0204; -+ regmap_write(udphy->pma_regmap, 0x0810 + offset, val); -+ -+ val = dp_ctrl[voltage][pre].trsv_reg0205; -+ regmap_write(udphy->pma_regmap, 0x0814 + offset, val); -+ -+ val = dp_ctrl[voltage][pre].trsv_reg0206; -+ regmap_write(udphy->pma_regmap, 0x0818 + offset, val); -+ -+ val = dp_ctrl[voltage][pre].trsv_reg0207; -+ regmap_write(udphy->pma_regmap, 0x081c + offset, val); -+} -+ -+static int rk3588_dp_phy_set_voltages(struct rockchip_udphy *udphy, -+ struct phy_configure_opts_dp *dp) -+{ -+ u32 i, lane; -+ -+ for (i = 0; i < dp->lanes; i++) { -+ lane = udphy->dp_lane_sel[i]; -+ switch (dp->link_rate) { -+ case 1620: -+ case 2700: -+ regmap_update_bits(udphy->pma_regmap, TRSV_ANA_TX_CLK_OFFSET_N(lane), -+ LN_ANA_TX_SER_TXCLK_INV, -+ FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, -+ udphy->lane_mux_sel[lane])); -+ break; -+ case 5400: -+ case 8100: -+ regmap_update_bits(udphy->pma_regmap, TRSV_ANA_TX_CLK_OFFSET_N(lane), -+ LN_ANA_TX_SER_TXCLK_INV, -+ FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, 0x0)); -+ break; -+ } -+ -+ rk3588_dp_phy_set_voltage(udphy, udphy->bw, dp->voltage[i], dp->pre[i], lane); -+ } -+ -+ return 0; -+} -+ -+static int __maybe_unused udphy_resume(struct device *dev) -+{ -+ struct rockchip_udphy *udphy = dev_get_drvdata(dev); -+ const struct rockchip_udphy_cfg *cfg = udphy->cfgs; -+ -+ if (udphy->dp_sink_hpd_sel) -+ cfg->hpd_event_trigger(udphy, udphy->dp_sink_hpd_cfg); -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops udphy_pm_ops = { -+ SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, udphy_resume) -+}; -+ -+static const char * const rk3588_udphy_rst_l[] = { -+ "init", "cmn", "lane", "pcs_apb", "pma_apb" -+}; -+ -+static const struct rockchip_udphy_cfg rk3588_udphy_cfgs = { -+ .num_rsts = ARRAY_SIZE(rk3588_udphy_rst_l), -+ .rst_list = rk3588_udphy_rst_l, -+ .grfcfg = { -+ /* u2phy-grf */ -+ .bvalid_phy_con = { 0x0008, 1, 0, 0x2, 0x3 }, -+ .bvalid_grf_con = { 0x0010, 3, 2, 0x2, 0x3 }, -+ -+ /* usb-grf */ -+ .usb3otg0_cfg = { 0x001c, 15, 0, 0x1100, 0x0188 }, -+ .usb3otg1_cfg = { 0x0034, 15, 0, 0x1100, 0x0188 }, -+ -+ /* usbdpphy-grf */ -+ .low_pwrn = { 0x0004, 13, 13, 0, 1 }, -+ .rx_lfps = { 0x0004, 14, 14, 0, 1 }, -+ }, -+ .vogrfcfg = { -+ { -+ .hpd_trigger = { 0x0000, 11, 10, 1, 3 }, -+ }, -+ { -+ .hpd_trigger = { 0x0008, 11, 10, 1, 3 }, -+ }, -+ }, -+ .dp_tx_ctrl_cfg = { -+ rk3588_dp_tx_drv_ctrl_rbr_hbr, -+ rk3588_dp_tx_drv_ctrl_rbr_hbr, -+ rk3588_dp_tx_drv_ctrl_hbr2, -+ rk3588_dp_tx_drv_ctrl_hbr3, -+ }, -+ .dp_tx_ctrl_cfg_typec = { -+ rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, -+ rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, -+ rk3588_dp_tx_drv_ctrl_hbr2, -+ rk3588_dp_tx_drv_ctrl_hbr3, -+ }, -+ .combophy_init = rk3588_udphy_init, -+ .dp_phy_set_rate = rk3588_dp_phy_set_rate, -+ .dp_phy_set_voltages = rk3588_dp_phy_set_voltages, -+ .hpd_event_trigger = rk3588_udphy_hpd_event_trigger, -+ .dplane_enable = rk3588_udphy_dplane_enable, -+ .dplane_select = rk3588_udphy_dplane_select, -+}; -+ -+static const struct of_device_id rockchip_udphy_dt_match[] = { -+ { -+ .compatible = "rockchip,rk3588-usbdp-phy", -+ .data = &rk3588_udphy_cfgs -+ }, -+ { /* sentinel */ } -+}; -+ -+MODULE_DEVICE_TABLE(of, rockchip_udphy_dt_match); -+ -+static struct platform_driver rockchip_udphy_driver = { -+ .probe = rockchip_udphy_probe, -+ .driver = { -+ .name = "rockchip-usbdp-phy", -+ .of_match_table = rockchip_udphy_dt_match, -+ .pm = &udphy_pm_ops, -+ }, -+}; -+ -+module_platform_driver(rockchip_udphy_driver); -+ -+MODULE_AUTHOR("Frank Wang "); -+MODULE_AUTHOR("Zhang Yubing "); -+MODULE_DESCRIPTION("Rockchip USBDP Combo PHY driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c -index 058d5b853..a3ef7d703 100644 ---- a/drivers/usb/typec/tcpm/tcpm.c -+++ b/drivers/usb/typec/tcpm/tcpm.c -@@ -6588,9 +6588,9 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) - port->partner_desc.identity = &port->partner_ident; - port->port_type = port->typec_caps.type; - -- port->role_sw = usb_role_switch_get(port->dev); -+ port->role_sw = fwnode_usb_role_switch_get(tcpc->fwnode); - if (!port->role_sw) -- port->role_sw = fwnode_usb_role_switch_get(tcpc->fwnode); -+ port->role_sw = usb_role_switch_get(port->dev); - if (IS_ERR(port->role_sw)) { - err = PTR_ERR(port->role_sw); - goto out_destroy_wq; -diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h -index 6a46baa07..9042039f2 100644 ---- a/include/drm/bridge/dw_hdmi.h -+++ b/include/drm/bridge/dw_hdmi.h -@@ -6,12 +6,14 @@ - #ifndef __DW_HDMI__ - #define __DW_HDMI__ - -+#include - #include - - struct drm_display_info; - struct drm_display_mode; - struct drm_encoder; - struct dw_hdmi; -+struct dw_hdmi_qp; - struct platform_device; - - /** -@@ -92,6 +94,13 @@ enum dw_hdmi_phy_type { - DW_HDMI_PHY_VENDOR_PHY = 0xfe, - }; - -+struct dw_hdmi_audio_tmds_n { -+ unsigned long tmds; -+ unsigned int n_32k; -+ unsigned int n_44k1; -+ unsigned int n_48k; -+}; -+ - struct dw_hdmi_mpll_config { - unsigned long mpixelclock; - struct { -@@ -112,6 +121,15 @@ struct dw_hdmi_phy_config { - u16 vlev_ctr; /* voltage level control */ - }; - -+struct dw_hdmi_link_config { -+ bool dsc_mode; -+ bool frl_mode; -+ int frl_lanes; -+ int rate_per_lane; -+ int hcactive; -+ u8 pps_payload[128]; -+}; -+ - struct dw_hdmi_phy_ops { - int (*init)(struct dw_hdmi *hdmi, void *data, - const struct drm_display_info *display, -@@ -123,14 +141,52 @@ struct dw_hdmi_phy_ops { - void (*setup_hpd)(struct dw_hdmi *hdmi, void *data); - }; - -+struct dw_hdmi_qp_phy_ops { -+ int (*init)(struct dw_hdmi_qp *hdmi, void *data, -+ struct drm_display_mode *mode); -+ void (*disable)(struct dw_hdmi_qp *hdmi, void *data); -+ enum drm_connector_status (*read_hpd)(struct dw_hdmi_qp *hdmi, -+ void *data); -+ void (*update_hpd)(struct dw_hdmi_qp *hdmi, void *data, -+ bool force, bool disabled, bool rxsense); -+ void (*setup_hpd)(struct dw_hdmi_qp *hdmi, void *data); -+ void (*set_mode)(struct dw_hdmi_qp *dw_hdmi, void *data, -+ u32 mode_mask, bool enable); -+}; -+ -+struct dw_hdmi_property_ops { -+ void (*attach_properties)(struct drm_connector *connector, -+ unsigned int color, int version, -+ void *data); -+ void (*destroy_properties)(struct drm_connector *connector, -+ void *data); -+ int (*set_property)(struct drm_connector *connector, -+ struct drm_connector_state *state, -+ struct drm_property *property, -+ u64 val, -+ void *data); -+ int (*get_property)(struct drm_connector *connector, -+ const struct drm_connector_state *state, -+ struct drm_property *property, -+ u64 *val, -+ void *data); -+}; -+ - struct dw_hdmi_plat_data { - struct regmap *regm; - -+ //[CC:] not in dowstream - unsigned int output_port; - -+ unsigned long input_bus_format; - unsigned long input_bus_encoding; -+ unsigned int max_tmdsclk; -+ int id; - bool use_drm_infoframe; - bool ycbcr_420_allowed; -+ bool unsupported_yuv_input; -+ bool unsupported_deep_color; -+ bool is_hdmi_qp; - - /* - * Private data passed to all the .mode_valid() and .configure_phy() -@@ -139,6 +195,7 @@ struct dw_hdmi_plat_data { - void *priv_data; - - /* Platform-specific mode validation (optional). */ -+ //[CC:] downstream changed "struct dw_hdmi *hdmi" to "struct drm_connector *connector" - enum drm_mode_status (*mode_valid)(struct dw_hdmi *hdmi, void *data, - const struct drm_display_info *info, - const struct drm_display_mode *mode); -@@ -150,18 +207,51 @@ struct dw_hdmi_plat_data { - - /* Vendor PHY support */ - const struct dw_hdmi_phy_ops *phy_ops; -+ const struct dw_hdmi_qp_phy_ops *qp_phy_ops; - const char *phy_name; - void *phy_data; - unsigned int phy_force_vendor; - -+ /* split mode */ -+ bool split_mode; -+ bool first_screen; -+ struct dw_hdmi_qp *left; -+ struct dw_hdmi_qp *right; -+ - /* Synopsys PHY support */ - const struct dw_hdmi_mpll_config *mpll_cfg; -+ const struct dw_hdmi_mpll_config *mpll_cfg_420; - const struct dw_hdmi_curr_ctrl *cur_ctr; - const struct dw_hdmi_phy_config *phy_config; - int (*configure_phy)(struct dw_hdmi *hdmi, void *data, - unsigned long mpixelclock); - - unsigned int disable_cec : 1; -+ -+ //[CC:] 7b29b5f29585 ("drm/rockchip: dw_hdmi: Support HDMI 2.0 YCbCr 4:2:0") -+ unsigned long (*get_input_bus_format)(void *data); -+ unsigned long (*get_output_bus_format)(void *data); -+ unsigned long (*get_enc_in_encoding)(void *data); -+ unsigned long (*get_enc_out_encoding)(void *data); -+ -+ unsigned long (*get_quant_range)(void *data); -+ struct drm_property *(*get_hdr_property)(void *data); -+ struct drm_property_blob *(*get_hdr_blob)(void *data); -+ bool (*get_color_changed)(void *data); -+ int (*get_yuv422_format)(struct drm_connector *connector, -+ struct edid *edid); -+ int (*get_edid_dsc_info)(void *data, struct edid *edid); -+ int (*get_next_hdr_data)(void *data, struct edid *edid, -+ struct drm_connector *connector); -+ struct dw_hdmi_link_config *(*get_link_cfg)(void *data); -+ void (*set_grf_cfg)(void *data); -+ void (*convert_to_split_mode)(struct drm_display_mode *mode); -+ void (*convert_to_origin_mode)(struct drm_display_mode *mode); -+ int (*dclk_set)(void *data, bool enable); -+ -+ /* Vendor Property support */ -+ const struct dw_hdmi_property_ops *property_ops; -+ struct drm_connector *connector; - }; - - struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, -@@ -172,6 +262,7 @@ struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev, - struct drm_encoder *encoder, - const struct dw_hdmi_plat_data *plat_data); - -+void dw_hdmi_suspend(struct dw_hdmi *hdmi); - void dw_hdmi_resume(struct dw_hdmi *hdmi); - - void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense); -@@ -205,6 +296,32 @@ enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi, - 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_set_quant_range(struct dw_hdmi *hdmi); -+void dw_hdmi_set_output_type(struct dw_hdmi *hdmi, u64 val); -+bool dw_hdmi_get_output_whether_hdmi(struct dw_hdmi *hdmi); -+int dw_hdmi_get_output_type_cap(struct dw_hdmi *hdmi); -+//void dw_hdmi_set_cec_adap(struct dw_hdmi *hdmi, struct cec_adapter *adap); -+ -+void dw_hdmi_qp_unbind(struct dw_hdmi_qp *hdmi); -+struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, -+ struct drm_encoder *encoder, -+ struct dw_hdmi_plat_data *plat_data); -+void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi); -+void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi); -+//void dw_hdmi_qp_cec_set_hpd(struct dw_hdmi_qp *hdmi, bool plug_in, bool change); -+//void dw_hdmi_qp_set_cec_adap(struct dw_hdmi_qp *hdmi, struct cec_adapter *adap); -+int dw_hdmi_qp_set_earc(struct dw_hdmi_qp *hdmi); -+void dw_hdmi_qp_set_sample_rate(struct dw_hdmi_qp *hdmi, unsigned int rate); -+void dw_hdmi_qp_set_channel_count(struct dw_hdmi_qp *hdmi, unsigned int cnt); -+void dw_hdmi_qp_set_channel_status(struct dw_hdmi_qp *hdmi, u8 *channel_status, -+ bool ref2stream); -+void dw_hdmi_qp_set_channel_allocation(struct dw_hdmi_qp *hdmi, unsigned int ca); -+//void dw_hdmi_qp_set_audio_infoframe(struct dw_hdmi_qp *hdmi, -+// struct hdmi_codec_params *hparms); -+//void dw_hdmi_qp_audio_enable(struct dw_hdmi_qp *hdmi); -+//void dw_hdmi_qp_audio_disable(struct dw_hdmi_qp *hdmi); -+int dw_hdmi_qp_set_plugged_cb(struct dw_hdmi_qp *hdmi, hdmi_codec_plugged_cb fn, -+ struct device *codec_dev); - - bool dw_hdmi_bus_fmt_is_420(struct dw_hdmi *hdmi); - -diff --git a/include/dt-bindings/clock/rockchip,rk3588-cru.h b/include/dt-bindings/clock/rockchip,rk3588-cru.h -index 5790b1391..50ba72980 100644 ---- a/include/dt-bindings/clock/rockchip,rk3588-cru.h -+++ b/include/dt-bindings/clock/rockchip,rk3588-cru.h -@@ -733,8 +733,9 @@ - #define ACLK_AV1_PRE 718 - #define PCLK_AV1_PRE 719 - #define HCLK_SDIO_PRE 720 -+#define PCLK_VO1GRF 721 - --#define CLK_NR_CLKS (HCLK_SDIO_PRE + 1) -+#define CLK_NR_CLKS (PCLK_VO1GRF + 1) - - /* scmi-clocks indices */ - -diff --git a/include/dt-bindings/soc/rockchip,vop2.h b/include/dt-bindings/soc/rockchip,vop2.h -index 6e66a802b..668f199df 100644 ---- a/include/dt-bindings/soc/rockchip,vop2.h -+++ b/include/dt-bindings/soc/rockchip,vop2.h -@@ -10,5 +10,9 @@ - #define ROCKCHIP_VOP2_EP_LVDS0 5 - #define ROCKCHIP_VOP2_EP_MIPI1 6 - #define ROCKCHIP_VOP2_EP_LVDS1 7 -+#define ROCKCHIP_VOP2_EP_HDMI1 8 -+#define ROCKCHIP_VOP2_EP_EDP1 9 -+#define ROCKCHIP_VOP2_EP_DP0 10 -+#define ROCKCHIP_VOP2_EP_DP1 11 - - #endif /* __DT_BINDINGS_ROCKCHIP_VOP2_H */ -diff --git a/include/linux/math.h b/include/linux/math.h -index dd4152711..f80bfb375 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; }) - -diff --git a/include/uapi/drm/rockchip_drm.h b/include/uapi/drm/rockchip_drm.h -new file mode 100644 -index 000000000..246192fa2 ---- /dev/null -+++ b/include/uapi/drm/rockchip_drm.h -@@ -0,0 +1,134 @@ -+/* -+ * -+ * Copyright (c) Fuzhou Rockchip Electronics Co.Ltd -+ * Authors: -+ * Mark Yao -+ * -+ * base on exynos_drm.h -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+ -+#ifndef _UAPI_ROCKCHIP_DRM_H -+#define _UAPI_ROCKCHIP_DRM_H -+ -+#include -+#include -+ -+/* -+ * Send vcnt event instead of blocking, -+ * like _DRM_VBLANK_EVENT -+ */ -+#define _DRM_ROCKCHIP_VCNT_EVENT 0x80000000 -+#define DRM_EVENT_ROCKCHIP_CRTC_VCNT 0xf -+ -+/* memory type definitions. */ -+enum drm_rockchip_gem_mem_type { -+ /* Physically Continuous memory. */ -+ ROCKCHIP_BO_CONTIG = 1 << 0, -+ /* cachable mapping. */ -+ ROCKCHIP_BO_CACHABLE = 1 << 1, -+ /* write-combine mapping. */ -+ ROCKCHIP_BO_WC = 1 << 2, -+ ROCKCHIP_BO_SECURE = 1 << 3, -+ /* keep kmap for cma buffer or alloc kmap for other type memory */ -+ ROCKCHIP_BO_ALLOC_KMAP = 1 << 4, -+ ROCKCHIP_BO_MASK = ROCKCHIP_BO_CONTIG | ROCKCHIP_BO_CACHABLE | -+ ROCKCHIP_BO_WC | ROCKCHIP_BO_SECURE | ROCKCHIP_BO_ALLOC_KMAP, -+}; -+ -+/** -+ * User-desired buffer creation information structure. -+ * -+ * @size: user-desired memory allocation size. -+ * @flags: user request for setting memory type or cache attributes. -+ * @handle: returned a handle to created gem object. -+ * - this handle will be set by gem module of kernel side. -+ */ -+struct drm_rockchip_gem_create { -+ uint64_t size; -+ uint32_t flags; -+ uint32_t handle; -+}; -+ -+struct drm_rockchip_gem_phys { -+ uint32_t handle; -+ uint32_t phy_addr; -+}; -+ -+/** -+ * A structure for getting buffer offset. -+ * -+ * @handle: a pointer to gem object created. -+ * @pad: just padding to be 64-bit aligned. -+ * @offset: relatived offset value of the memory region allocated. -+ * - this value should be set by user. -+ */ -+struct drm_rockchip_gem_map_off { -+ uint32_t handle; -+ uint32_t pad; -+ uint64_t offset; -+}; -+ -+/* acquire type definitions. */ -+enum drm_rockchip_gem_cpu_acquire_type { -+ DRM_ROCKCHIP_GEM_CPU_ACQUIRE_SHARED = 0x0, -+ DRM_ROCKCHIP_GEM_CPU_ACQUIRE_EXCLUSIVE = 0x1, -+}; -+ -+enum rockchip_crtc_feture { -+ ROCKCHIP_DRM_CRTC_FEATURE_ALPHA_SCALE, -+ ROCKCHIP_DRM_CRTC_FEATURE_HDR10, -+ ROCKCHIP_DRM_CRTC_FEATURE_NEXT_HDR, -+}; -+ -+enum rockchip_plane_feture { -+ ROCKCHIP_DRM_PLANE_FEATURE_SCALE, -+ ROCKCHIP_DRM_PLANE_FEATURE_ALPHA, -+ ROCKCHIP_DRM_PLANE_FEATURE_HDR2SDR, -+ ROCKCHIP_DRM_PLANE_FEATURE_SDR2HDR, -+ ROCKCHIP_DRM_PLANE_FEATURE_AFBDC, -+ ROCKCHIP_DRM_PLANE_FEATURE_PDAF_POS, -+ ROCKCHIP_DRM_PLANE_FEATURE_MAX, -+}; -+ -+enum rockchip_cabc_mode { -+ ROCKCHIP_DRM_CABC_MODE_DISABLE, -+ ROCKCHIP_DRM_CABC_MODE_NORMAL, -+ ROCKCHIP_DRM_CABC_MODE_LOWPOWER, -+ ROCKCHIP_DRM_CABC_MODE_USERSPACE, -+}; -+ -+struct drm_rockchip_vcnt_event { -+ struct drm_pending_event base; -+}; -+ -+#define DRM_ROCKCHIP_GEM_CREATE 0x00 -+#define DRM_ROCKCHIP_GEM_MAP_OFFSET 0x01 -+#define DRM_ROCKCHIP_GEM_CPU_ACQUIRE 0x02 -+#define DRM_ROCKCHIP_GEM_CPU_RELEASE 0x03 -+#define DRM_ROCKCHIP_GEM_GET_PHYS 0x04 -+#define DRM_ROCKCHIP_GET_VCNT_EVENT 0x05 -+ -+#define DRM_IOCTL_ROCKCHIP_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ -+ DRM_ROCKCHIP_GEM_CREATE, struct drm_rockchip_gem_create) -+ -+#define DRM_IOCTL_ROCKCHIP_GEM_MAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + \ -+ DRM_ROCKCHIP_GEM_MAP_OFFSET, struct drm_rockchip_gem_map_off) -+ -+#define DRM_IOCTL_ROCKCHIP_GEM_CPU_ACQUIRE DRM_IOWR(DRM_COMMAND_BASE + \ -+ DRM_ROCKCHIP_GEM_CPU_ACQUIRE, struct drm_rockchip_gem_cpu_acquire) -+ -+#define DRM_IOCTL_ROCKCHIP_GEM_CPU_RELEASE DRM_IOWR(DRM_COMMAND_BASE + \ -+ DRM_ROCKCHIP_GEM_CPU_RELEASE, struct drm_rockchip_gem_cpu_release) -+ -+#define DRM_IOCTL_ROCKCHIP_GEM_GET_PHYS DRM_IOWR(DRM_COMMAND_BASE + \ -+ DRM_ROCKCHIP_GEM_GET_PHYS, struct drm_rockchip_gem_phys) -+ -+#define DRM_IOCTL_ROCKCHIP_GET_VCNT_EVENT DRM_IOWR(DRM_COMMAND_BASE + \ -+ DRM_ROCKCHIP_GET_VCNT_EVENT, union drm_wait_vblank) -+ -+#endif /* _UAPI_ROCKCHIP_DRM_H */ diff --git a/system/hosts/router/metrics.nix b/system/hosts/router/metrics.nix index f1a316e..bb2fc66 100644 --- a/system/hosts/router/metrics.nix +++ b/system/hosts/router/metrics.nix @@ -31,7 +31,7 @@ in { ]; listenAddress = netAddresses.lan4; }; - ping = { + ping2 = { enable = true; listenAddress = netAddresses.lan4; port = 9380; diff --git a/system/hosts/server/files.nix b/system/hosts/server/files.nix index 37f64e7..535de6e 100644 --- a/system/hosts/server/files.nix +++ b/system/hosts/server/files.nix @@ -72,7 +72,7 @@ in { }; services.nextcloud = { enable = true; - package = pkgs.nextcloud27; + package = pkgs.nextcloud28; autoUpdateApps.enable = true; # TODO: use socket auth and remove the next line database.createLocally = false; @@ -81,8 +81,8 @@ in { dbpassFile = "/var/lib/nextcloud/db_password"; dbtype = "pgsql"; dbhost = "/run/postgresql"; - overwriteProtocol = "https"; }; + extraOptions.overwriteprotocol = "https"; hostName = "cloud.${cfg.domainName}"; https = true; }; diff --git a/system/hosts/server/home.nix b/system/hosts/server/home.nix index eea1204..e758148 100644 --- a/system/hosts/server/home.nix +++ b/system/hosts/server/home.nix @@ -108,12 +108,13 @@ in { # so normal nix evals don't have access to builtins nix.settings.extra-builtins-file = "/secrets/nixos/extra-builtins.nix"; nix.settings.allowed-uris = [ - # required for home-manager + # required for home-manager (no idea if it's required at this point) "https://git.sr.ht/~rycee/nmd/" - # required for server (I suppose since nvfetcher uses fetchTarball here...) - "https://github.com/searxng/searxng/" - # required for home config (nvfetcher again) + # ...for the rest of the home config "https://api.github.com/repos/FAForever/" + "https://github.com/nix-community/nix-index-database/releases/download/" + # required for server (I suppose since nvfetcher uses fetchTarball here...) + "https://github.com/searxng/searxng/releases/download/" # for nginx CF-Connecting-IP config generation "https://www.cloudflare.com/ips-v4" "https://www.cloudflare.com/ips-v6" @@ -146,6 +147,11 @@ in { notificationSender = "noreply@${cfg.domainName}"; # smtpHost = "mail.${cfg.domainName}"; useSubstitutes = true; + # I really don't want to do this... but nix-plugins refuses to work otherwise + # TODO: fix, hopefully + extraConfig = '' + evaluator_pure_eval = 0 + ''; }; # boot.binfmt.emulatedSystems = builtins.filter (x: x != pkgs.system) [ "aarch64-linux" "x86_64-linux" ]; nix.buildMachines = [ diff --git a/system/hosts/server/maubot.nix b/system/hosts/server/maubot.nix index 76ddb9c..e34a2aa 100644 --- a/system/hosts/server/maubot.nix +++ b/system/hosts/server/maubot.nix @@ -1,14 +1,11 @@ { config , lib , pkgs -, inputs , ... }: let cfg = config.server; in { - imports = [ inputs.maubot.nixosModules.default ]; - services.nginx.virtualHosts."matrix.${cfg.domainName}".locations = let inherit (config.services.maubot) settings; in { diff --git a/system/modules/ping-exporter.nix b/system/modules/ping-exporter.nix index bb14d31..d01fe62 100644 --- a/system/modules/ping-exporter.nix +++ b/system/modules/ping-exporter.nix @@ -5,7 +5,7 @@ }: let - cfg = config.services.prometheus.exporters.ping; + cfg = config.services.prometheus.exporters.ping2; inherit (lib) concatStrings literalExpression mkMerge mkDefault mkEnableOption mkIf mkOption types; # copied from nixpkgs/nixos/modules/services/monitoring/prometheus/exporters mkExporterOpts = { name, port }: { @@ -118,7 +118,7 @@ let }; format = pkgs.formats.toml { }; in { - options.services.prometheus.exporters.ping = mkExporterOpts { name = "ping"; port = 9390; } // { + options.services.prometheus.exporters.ping2 = mkExporterOpts { name = "ping2"; port = 9390; } // { config = mkOption { type = format.type; default = { }; @@ -126,7 +126,7 @@ in { }; }; config = mkExporterConf { - name = "ping"; + name = "ping2"; conf = cfg; serviceOpts = { serviceConfig = rec {